jarvis-ai-assistant 0.7.8__py3-none-any.whl → 1.0.2__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 (279) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +567 -222
  3. jarvis/jarvis_agent/agent_manager.py +19 -12
  4. jarvis/jarvis_agent/builtin_input_handler.py +79 -11
  5. jarvis/jarvis_agent/config_editor.py +7 -2
  6. jarvis/jarvis_agent/event_bus.py +24 -13
  7. jarvis/jarvis_agent/events.py +19 -1
  8. jarvis/jarvis_agent/file_context_handler.py +67 -64
  9. jarvis/jarvis_agent/file_methodology_manager.py +38 -24
  10. jarvis/jarvis_agent/jarvis.py +186 -114
  11. jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
  12. jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
  13. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
  14. jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
  15. jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
  16. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
  17. jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
  18. jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
  19. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
  20. jarvis/jarvis_agent/language_support_info.py +250 -219
  21. jarvis/jarvis_agent/main.py +19 -23
  22. jarvis/jarvis_agent/memory_manager.py +9 -6
  23. jarvis/jarvis_agent/methodology_share_manager.py +21 -15
  24. jarvis/jarvis_agent/output_handler.py +4 -2
  25. jarvis/jarvis_agent/prompt_builder.py +7 -6
  26. jarvis/jarvis_agent/prompt_manager.py +113 -8
  27. jarvis/jarvis_agent/prompts.py +317 -85
  28. jarvis/jarvis_agent/protocols.py +5 -2
  29. jarvis/jarvis_agent/run_loop.py +192 -32
  30. jarvis/jarvis_agent/session_manager.py +7 -3
  31. jarvis/jarvis_agent/share_manager.py +23 -13
  32. jarvis/jarvis_agent/shell_input_handler.py +12 -8
  33. jarvis/jarvis_agent/stdio_redirect.py +25 -26
  34. jarvis/jarvis_agent/task_analyzer.py +29 -23
  35. jarvis/jarvis_agent/task_list.py +869 -0
  36. jarvis/jarvis_agent/task_manager.py +26 -23
  37. jarvis/jarvis_agent/tool_executor.py +6 -5
  38. jarvis/jarvis_agent/tool_share_manager.py +24 -14
  39. jarvis/jarvis_agent/user_interaction.py +3 -3
  40. jarvis/jarvis_agent/utils.py +9 -1
  41. jarvis/jarvis_agent/web_bridge.py +37 -17
  42. jarvis/jarvis_agent/web_output_sink.py +5 -2
  43. jarvis/jarvis_agent/web_server.py +165 -36
  44. jarvis/jarvis_c2rust/__init__.py +1 -1
  45. jarvis/jarvis_c2rust/cli.py +260 -141
  46. jarvis/jarvis_c2rust/collector.py +37 -18
  47. jarvis/jarvis_c2rust/constants.py +60 -0
  48. jarvis/jarvis_c2rust/library_replacer.py +242 -1010
  49. jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
  50. jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
  51. jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
  52. jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
  53. jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
  54. jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
  55. jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
  56. jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
  57. jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
  58. jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
  59. jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
  60. jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
  61. jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
  62. jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
  63. jarvis/jarvis_c2rust/loaders.py +28 -10
  64. jarvis/jarvis_c2rust/models.py +5 -2
  65. jarvis/jarvis_c2rust/optimizer.py +192 -1974
  66. jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
  67. jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
  68. jarvis/jarvis_c2rust/optimizer_config.py +49 -0
  69. jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
  70. jarvis/jarvis_c2rust/optimizer_options.py +48 -0
  71. jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
  72. jarvis/jarvis_c2rust/optimizer_report.py +52 -0
  73. jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
  74. jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
  75. jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
  76. jarvis/jarvis_c2rust/scanner.py +229 -166
  77. jarvis/jarvis_c2rust/transpiler.py +531 -2732
  78. jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
  79. jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
  80. jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
  81. jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
  82. jarvis/jarvis_c2rust/transpiler_config.py +178 -0
  83. jarvis/jarvis_c2rust/transpiler_context.py +122 -0
  84. jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
  85. jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
  86. jarvis/jarvis_c2rust/transpiler_git.py +163 -0
  87. jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
  88. jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
  89. jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
  90. jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
  91. jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
  92. jarvis/jarvis_c2rust/utils.py +269 -79
  93. jarvis/jarvis_code_agent/after_change.py +233 -0
  94. jarvis/jarvis_code_agent/build_validation_config.py +37 -30
  95. jarvis/jarvis_code_agent/builtin_rules.py +68 -0
  96. jarvis/jarvis_code_agent/code_agent.py +976 -1517
  97. jarvis/jarvis_code_agent/code_agent_build.py +227 -0
  98. jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
  99. jarvis/jarvis_code_agent/code_agent_git.py +525 -0
  100. jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
  101. jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
  102. jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
  103. jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
  104. jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
  105. jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
  106. jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
  107. jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
  108. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
  109. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
  110. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
  111. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
  112. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
  113. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
  114. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
  115. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
  116. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
  117. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
  118. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
  119. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
  120. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
  121. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
  122. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
  123. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
  124. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
  125. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
  126. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
  127. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
  128. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
  129. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
  130. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
  131. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
  132. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
  133. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
  134. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
  135. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
  136. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
  137. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
  138. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
  139. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
  140. jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
  141. jarvis/jarvis_code_agent/lint.py +223 -524
  142. jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
  143. jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
  144. jarvis/jarvis_code_agent/rules/code_review.md +115 -0
  145. jarvis/jarvis_code_agent/rules/documentation.md +165 -0
  146. jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
  147. jarvis/jarvis_code_agent/rules/performance.md +158 -0
  148. jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
  149. jarvis/jarvis_code_agent/rules/security.md +160 -0
  150. jarvis/jarvis_code_agent/rules/tdd.md +78 -0
  151. jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
  152. jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
  153. jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
  154. jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
  155. jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
  156. jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
  157. jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
  158. jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
  159. jarvis/jarvis_code_agent/utils.py +36 -26
  160. jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
  161. jarvis/jarvis_code_analysis/code_review.py +64 -33
  162. jarvis/jarvis_data/config_schema.json +285 -192
  163. jarvis/jarvis_git_squash/main.py +8 -6
  164. jarvis/jarvis_git_utils/git_commiter.py +53 -76
  165. jarvis/jarvis_mcp/__init__.py +5 -2
  166. jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
  167. jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
  168. jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
  169. jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
  170. jarvis/jarvis_methodology/main.py +48 -39
  171. jarvis/jarvis_multi_agent/__init__.py +56 -23
  172. jarvis/jarvis_multi_agent/main.py +15 -18
  173. jarvis/jarvis_platform/base.py +179 -111
  174. jarvis/jarvis_platform/human.py +27 -16
  175. jarvis/jarvis_platform/kimi.py +52 -45
  176. jarvis/jarvis_platform/openai.py +101 -40
  177. jarvis/jarvis_platform/registry.py +51 -33
  178. jarvis/jarvis_platform/tongyi.py +68 -38
  179. jarvis/jarvis_platform/yuanbao.py +59 -43
  180. jarvis/jarvis_platform_manager/main.py +68 -76
  181. jarvis/jarvis_platform_manager/service.py +24 -14
  182. jarvis/jarvis_rag/README_CONFIG.md +314 -0
  183. jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
  184. jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
  185. jarvis/jarvis_rag/__init__.py +57 -4
  186. jarvis/jarvis_rag/cache.py +3 -1
  187. jarvis/jarvis_rag/cli.py +48 -68
  188. jarvis/jarvis_rag/embedding_interface.py +39 -0
  189. jarvis/jarvis_rag/embedding_manager.py +7 -230
  190. jarvis/jarvis_rag/embeddings/__init__.py +41 -0
  191. jarvis/jarvis_rag/embeddings/base.py +114 -0
  192. jarvis/jarvis_rag/embeddings/cohere.py +66 -0
  193. jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
  194. jarvis/jarvis_rag/embeddings/local.py +260 -0
  195. jarvis/jarvis_rag/embeddings/openai.py +62 -0
  196. jarvis/jarvis_rag/embeddings/registry.py +293 -0
  197. jarvis/jarvis_rag/llm_interface.py +8 -6
  198. jarvis/jarvis_rag/query_rewriter.py +8 -9
  199. jarvis/jarvis_rag/rag_pipeline.py +61 -52
  200. jarvis/jarvis_rag/reranker.py +7 -75
  201. jarvis/jarvis_rag/reranker_interface.py +32 -0
  202. jarvis/jarvis_rag/rerankers/__init__.py +41 -0
  203. jarvis/jarvis_rag/rerankers/base.py +109 -0
  204. jarvis/jarvis_rag/rerankers/cohere.py +67 -0
  205. jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
  206. jarvis/jarvis_rag/rerankers/jina.py +79 -0
  207. jarvis/jarvis_rag/rerankers/local.py +89 -0
  208. jarvis/jarvis_rag/rerankers/registry.py +293 -0
  209. jarvis/jarvis_rag/retriever.py +58 -43
  210. jarvis/jarvis_sec/__init__.py +66 -141
  211. jarvis/jarvis_sec/agents.py +21 -17
  212. jarvis/jarvis_sec/analysis.py +80 -33
  213. jarvis/jarvis_sec/checkers/__init__.py +7 -13
  214. jarvis/jarvis_sec/checkers/c_checker.py +356 -164
  215. jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
  216. jarvis/jarvis_sec/cli.py +43 -21
  217. jarvis/jarvis_sec/clustering.py +430 -272
  218. jarvis/jarvis_sec/file_manager.py +99 -55
  219. jarvis/jarvis_sec/parsers.py +9 -6
  220. jarvis/jarvis_sec/prompts.py +4 -3
  221. jarvis/jarvis_sec/report.py +44 -22
  222. jarvis/jarvis_sec/review.py +180 -107
  223. jarvis/jarvis_sec/status.py +50 -41
  224. jarvis/jarvis_sec/types.py +3 -0
  225. jarvis/jarvis_sec/utils.py +160 -83
  226. jarvis/jarvis_sec/verification.py +411 -181
  227. jarvis/jarvis_sec/workflow.py +132 -21
  228. jarvis/jarvis_smart_shell/main.py +28 -41
  229. jarvis/jarvis_stats/cli.py +14 -12
  230. jarvis/jarvis_stats/stats.py +28 -19
  231. jarvis/jarvis_stats/storage.py +14 -8
  232. jarvis/jarvis_stats/visualizer.py +12 -7
  233. jarvis/jarvis_tools/base.py +5 -2
  234. jarvis/jarvis_tools/clear_memory.py +13 -9
  235. jarvis/jarvis_tools/cli/main.py +23 -18
  236. jarvis/jarvis_tools/edit_file.py +572 -873
  237. jarvis/jarvis_tools/execute_script.py +10 -7
  238. jarvis/jarvis_tools/file_analyzer.py +7 -8
  239. jarvis/jarvis_tools/meta_agent.py +287 -0
  240. jarvis/jarvis_tools/methodology.py +5 -3
  241. jarvis/jarvis_tools/read_code.py +305 -1438
  242. jarvis/jarvis_tools/read_symbols.py +50 -17
  243. jarvis/jarvis_tools/read_webpage.py +19 -18
  244. jarvis/jarvis_tools/registry.py +435 -156
  245. jarvis/jarvis_tools/retrieve_memory.py +16 -11
  246. jarvis/jarvis_tools/save_memory.py +8 -6
  247. jarvis/jarvis_tools/search_web.py +31 -31
  248. jarvis/jarvis_tools/sub_agent.py +32 -28
  249. jarvis/jarvis_tools/sub_code_agent.py +44 -60
  250. jarvis/jarvis_tools/task_list_manager.py +1811 -0
  251. jarvis/jarvis_tools/virtual_tty.py +29 -19
  252. jarvis/jarvis_utils/__init__.py +4 -0
  253. jarvis/jarvis_utils/builtin_replace_map.py +2 -1
  254. jarvis/jarvis_utils/clipboard.py +9 -8
  255. jarvis/jarvis_utils/collections.py +331 -0
  256. jarvis/jarvis_utils/config.py +699 -194
  257. jarvis/jarvis_utils/dialogue_recorder.py +294 -0
  258. jarvis/jarvis_utils/embedding.py +6 -3
  259. jarvis/jarvis_utils/file_processors.py +7 -1
  260. jarvis/jarvis_utils/fzf.py +9 -3
  261. jarvis/jarvis_utils/git_utils.py +71 -42
  262. jarvis/jarvis_utils/globals.py +116 -32
  263. jarvis/jarvis_utils/http.py +6 -2
  264. jarvis/jarvis_utils/input.py +318 -83
  265. jarvis/jarvis_utils/jsonnet_compat.py +119 -104
  266. jarvis/jarvis_utils/methodology.py +37 -28
  267. jarvis/jarvis_utils/output.py +201 -44
  268. jarvis/jarvis_utils/utils.py +986 -628
  269. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
  270. jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
  271. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
  272. jarvis/jarvis_tools/generate_new_tool.py +0 -205
  273. jarvis/jarvis_tools/lsp_client.py +0 -1552
  274. jarvis/jarvis_tools/rewrite_file.py +0 -105
  275. jarvis_ai_assistant-0.7.8.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -1,38 +1,41 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Jarvis AI 助手主入口模块"""
3
- from typing import Optional, List
3
+
4
+ import os
4
5
  import shutil
6
+ import signal
7
+ import subprocess
8
+ import sys
5
9
  from datetime import datetime
10
+ from pathlib import Path
11
+ from typing import Any
12
+ from typing import Dict
13
+ from typing import List
14
+ from typing import Optional
6
15
 
7
16
  import typer
17
+ import yaml
18
+ from rich.console import Console
19
+ from rich.table import Table
8
20
 
21
+ import jarvis.jarvis_utils.utils as jutils
9
22
  from jarvis.jarvis_agent.agent_manager import AgentManager
10
23
  from jarvis.jarvis_agent.config_editor import ConfigEditor
11
24
  from jarvis.jarvis_agent.methodology_share_manager import MethodologyShareManager
12
25
  from jarvis.jarvis_agent.tool_share_manager import ToolShareManager
13
- from jarvis.jarvis_utils.utils import init_env
14
- from jarvis.jarvis_utils.config import (
15
- is_enable_git_repo_jca_switch,
16
- is_enable_builtin_config_selector,
17
- get_agent_definition_dirs,
18
- get_multi_agent_dirs,
19
- get_roles_dirs,
20
- get_data_dir,
21
- set_config,
22
- is_non_interactive,
23
- )
24
- import jarvis.jarvis_utils.utils as jutils
25
- from jarvis.jarvis_utils.input import user_confirm, get_single_line_input
26
+ from jarvis.jarvis_utils.config import get_agent_definition_dirs
27
+ from jarvis.jarvis_utils.config import get_data_dir
28
+ from jarvis.jarvis_utils.config import get_multi_agent_dirs
29
+ from jarvis.jarvis_utils.config import get_roles_dirs
30
+ from jarvis.jarvis_utils.config import is_enable_builtin_config_selector
31
+ from jarvis.jarvis_utils.config import is_enable_git_repo_jca_switch
32
+ from jarvis.jarvis_utils.config import is_non_interactive
33
+ from jarvis.jarvis_utils.config import set_config
26
34
  from jarvis.jarvis_utils.fzf import fzf_select
27
- import os
28
- import subprocess
29
- from pathlib import Path
30
- import signal
31
- import yaml # type: ignore
32
- from rich.table import Table
33
- from rich.console import Console
34
-
35
- import sys
35
+ from jarvis.jarvis_utils.input import get_single_line_input
36
+ from jarvis.jarvis_utils.input import user_confirm
37
+ from jarvis.jarvis_utils.output import PrettyOutput
38
+ from jarvis.jarvis_utils.utils import init_env
36
39
 
37
40
 
38
41
  def _normalize_backup_data_argv(argv: List[str]) -> None:
@@ -47,7 +50,9 @@ def _normalize_backup_data_argv(argv: List[str]) -> None:
47
50
  if tok == "--backup-data":
48
51
  # 情况1:位于末尾,无参数
49
52
  # 情况2:后续是下一个选项(以 '-' 开头),表示未提供参数
50
- if i == len(argv) - 1 or (i + 1 < len(argv) and argv[i + 1].startswith("-")):
53
+ if i == len(argv) - 1 or (
54
+ i + 1 < len(argv) and argv[i + 1].startswith("-")
55
+ ):
51
56
  argv.insert(i + 1, "~/jarvis_backups")
52
57
  i += 1 # 跳过我们插入的默认值,避免重复插入
53
58
  i += 1
@@ -169,7 +174,7 @@ def handle_interactive_config_option(
169
174
  config_data, ask_all=True
170
175
  )
171
176
  if not changed:
172
- print("ℹ️ 没有需要更新的配置项,保持现有配置。")
177
+ PrettyOutput.auto_print("ℹ️ 没有需要更新的配置项,保持现有配置。")
173
178
  return True
174
179
 
175
180
  # 剔除与 schema 默认值一致的键,保持配置精简
@@ -208,10 +213,10 @@ def handle_interactive_config_option(
208
213
  wf.write(header)
209
214
  wf.write(yaml_str)
210
215
 
211
- print(f"✅ 配置已更新: {config_path}")
216
+ PrettyOutput.auto_print(f"✅ 配置已更新: {config_path}")
212
217
  return True
213
218
  except Exception as e:
214
- print(f"❌ 交互式配置失败: {e}")
219
+ PrettyOutput.auto_print(f"❌ 交互式配置失败: {e}")
215
220
  return True
216
221
 
217
222
 
@@ -223,7 +228,7 @@ def handle_backup_option(backup_dir_path: Optional[str]) -> bool:
223
228
  init_env("", config_file=None)
224
229
  data_dir = Path(get_data_dir())
225
230
  if not data_dir.is_dir():
226
- print(f"❌ 数据目录不存在: {data_dir}")
231
+ PrettyOutput.auto_print(f"❌ 数据目录不存在: {data_dir}")
227
232
  return True
228
233
 
229
234
  backup_dir_str = backup_dir_path if backup_dir_path.strip() else "~/jarvis_backups"
@@ -237,14 +242,16 @@ def handle_backup_option(backup_dir_path: Optional[str]) -> bool:
237
242
  archive_path = shutil.make_archive(
238
243
  str(backup_file_base), "zip", root_dir=str(data_dir)
239
244
  )
240
- print(f"✅ 数据已成功备份到: {archive_path}")
245
+ PrettyOutput.auto_print(f"✅ 数据已成功备份到: {archive_path}")
241
246
  except Exception as e:
242
- print(f"❌ 数据备份失败: {e}")
247
+ PrettyOutput.auto_print(f"❌ 数据备份失败: {e}")
243
248
 
244
249
  return True
245
250
 
246
251
 
247
- def handle_restore_option(restore_path: Optional[str], config_file: Optional[str]) -> bool:
252
+ def handle_restore_option(
253
+ restore_path: Optional[str], config_file: Optional[str]
254
+ ) -> bool:
248
255
  """处理数据恢复选项,返回是否已处理并需提前结束。"""
249
256
  if not restore_path:
250
257
  return False
@@ -252,11 +259,11 @@ def handle_restore_option(restore_path: Optional[str], config_file: Optional[str
252
259
  restore_file = Path(os.path.expanduser(os.path.expandvars(restore_path)))
253
260
  # 兼容 ~ 与环境变量,避免用户输入未展开路径导致找不到文件
254
261
  if not restore_file.is_file():
255
- print(f"❌ 指定的恢复文件不存在: {restore_file}")
262
+ PrettyOutput.auto_print(f"❌ 指定的恢复文件不存在: {restore_file}")
256
263
  return True
257
264
 
258
265
  # 在恢复数据时不要触发完整环境初始化,避免引导流程或网络请求
259
- # 优先从配置文件解析 JARVIS_DATA_PATH,否则回退到默认数据目录
266
+ # 优先从配置文件解析 data_path,否则回退到默认数据目录
260
267
  data_dir_str: Optional[str] = None
261
268
  try:
262
269
  if config_file:
@@ -265,7 +272,7 @@ def handle_restore_option(restore_path: Optional[str], config_file: Optional[str
265
272
  with open(cfg_path, "r", encoding="utf-8", errors="ignore") as cf:
266
273
  cfg_data = yaml.safe_load(cf) or {}
267
274
  if isinstance(cfg_data, dict):
268
- val = cfg_data.get("JARVIS_DATA_PATH")
275
+ val = cfg_data.get("data_path")
269
276
  if isinstance(val, str) and val.strip():
270
277
  data_dir_str = val.strip()
271
278
  except Exception:
@@ -280,21 +287,21 @@ def handle_restore_option(restore_path: Optional[str], config_file: Optional[str
280
287
  if not user_confirm(
281
288
  f"数据目录 '{data_dir}' 已存在,恢复操作将覆盖它。是否继续?", default=False
282
289
  ):
283
- print("ℹ️ 恢复操作已取消。")
290
+ PrettyOutput.auto_print("ℹ️ 恢复操作已取消。")
284
291
  return True
285
292
  try:
286
293
  shutil.rmtree(data_dir)
287
294
  except Exception as e:
288
- print(f"❌ 无法移除现有数据目录: {e}")
295
+ PrettyOutput.auto_print(f"❌ 无法移除现有数据目录: {e}")
289
296
  return True
290
297
 
291
298
  try:
292
299
  data_dir.mkdir(parents=True)
293
300
  shutil.unpack_archive(str(restore_file), str(data_dir), "zip")
294
- print(f"✅ 数据已从 '{restore_path}' 成功恢复到 '{data_dir}'")
301
+ PrettyOutput.auto_print(f"✅ 数据已从 '{restore_path}' 成功恢复到 '{data_dir}'")
295
302
 
296
303
  except Exception as e:
297
- print(f"❌ 数据恢复失败: {e}")
304
+ PrettyOutput.auto_print(f"❌ 数据恢复失败: {e}")
298
305
 
299
306
  return True
300
307
 
@@ -330,7 +337,7 @@ def try_switch_to_jca_if_git_repo(
330
337
  if res.returncode == 0:
331
338
  git_root = res.stdout.strip()
332
339
  if git_root and os.path.isdir(git_root):
333
- print(f"ℹ️ 检测到当前位于 Git 仓库: {git_root}")
340
+ PrettyOutput.auto_print(f"ℹ️ 检测到当前位于 Git 仓库: {git_root}")
334
341
  if user_confirm(
335
342
  "检测到Git仓库,是否切换到代码开发模式(jca)?", default=False
336
343
  ):
@@ -346,7 +353,9 @@ def try_switch_to_jca_if_git_repo(
346
353
  args += ["--restore-session"]
347
354
  if task:
348
355
  args += ["-r", task]
349
- print("ℹ️ 正在切换到 'jca'(jarvis-code-agent)以进入代码开发模式...")
356
+ PrettyOutput.auto_print(
357
+ "ℹ️ 正在切换到 'jca'(jarvis-code-agent)以进入代码开发模式..."
358
+ )
350
359
  os.execvp(args[0], args)
351
360
  except Exception:
352
361
  # 静默忽略检测异常,不影响主流程
@@ -385,7 +394,7 @@ def handle_builtin_config_selector(
385
394
  _unique.append(d)
386
395
  builtin_dirs = _unique
387
396
  # 向后兼容:保留第一个候选作为 builtin_root
388
- builtin_root = builtin_dirs[0] if builtin_dirs else None # type: ignore[assignment]
397
+ builtin_root = builtin_dirs[0] if builtin_dirs else None
389
398
 
390
399
  categories = [
391
400
  ("agent", "jarvis-agent", "*.yaml"),
@@ -428,9 +437,13 @@ def handle_builtin_config_selector(
428
437
 
429
438
  # 追加内置目录(支持多个候选)
430
439
  try:
431
- candidates = builtin_dirs if isinstance(builtin_dirs, list) and builtin_dirs else ([builtin_root] if builtin_root else [])
440
+ candidates = (
441
+ builtin_dirs
442
+ if isinstance(builtin_dirs, list) and builtin_dirs
443
+ else ([builtin_root] if builtin_root else [])
444
+ )
432
445
  except Exception:
433
- candidates = ([builtin_root] if builtin_root else [])
446
+ candidates = [builtin_root] if builtin_root else []
434
447
  for _bd in candidates:
435
448
  if _bd:
436
449
  search_dirs.append(Path(_bd) / cat)
@@ -449,8 +462,11 @@ def handle_builtin_config_selector(
449
462
 
450
463
  # 可选调试输出:查看每类的搜索目录
451
464
  try:
452
- if os.environ.get("JARVIS_DEBUG_BUILTIN_SELECTOR") == "1":
453
- print(f"ℹ️ DEBUG: category={cat} search_dirs=" + ", ".join(str(p) for p in unique_dirs))
465
+ if os.environ.get("debug_builtin_selector") == "1":
466
+ PrettyOutput.auto_print(
467
+ f"ℹ️ DEBUG: category={cat} search_dirs="
468
+ + ", ".join(str(p) for p in unique_dirs)
469
+ )
454
470
  except Exception:
455
471
  pass
456
472
 
@@ -527,7 +543,7 @@ def handle_builtin_config_selector(
527
543
  },
528
544
  )
529
545
 
530
- print("✅ 可用的内置配置")
546
+ PrettyOutput.auto_print("✅ 可用的内置配置")
531
547
  # 使用 rich Table 呈现
532
548
  table = Table(show_header=True, header_style="bold magenta")
533
549
  table.add_column("No.", style="cyan", no_wrap=True)
@@ -582,7 +598,8 @@ def handle_builtin_config_selector(
582
598
  else:
583
599
  # Fallback to manual input if fzf is not used or available
584
600
  choice = get_single_line_input(
585
- "选择要启动的配置编号,直接回车使用默认通用代理(jvs): ", default=""
601
+ "选择要启动的配置编号,直接回车使用默认通用代理(jvs): ",
602
+ default="",
586
603
  )
587
604
  if choice.strip():
588
605
  try:
@@ -632,7 +649,7 @@ def handle_builtin_config_selector(
632
649
  args += ["-g", str(model_group)]
633
650
 
634
651
  if args:
635
- print(f"ℹ️ 正在启动: {' '.join(args)}")
652
+ PrettyOutput.auto_print(f"ℹ️ 正在启动: {' '.join(args)}")
636
653
  os.execvp(args[0], args)
637
654
  except Exception:
638
655
  # 任何异常都不影响默认流程
@@ -695,9 +712,14 @@ def run_cli(
695
712
  None, "--restore-data", help="从指定的压缩包恢复 Jarvis 数据"
696
713
  ),
697
714
  non_interactive: bool = typer.Option(
698
- False, "-n", "--non-interactive", help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟"
715
+ False,
716
+ "-n",
717
+ "--non-interactive",
718
+ help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟",
719
+ ),
720
+ web: bool = typer.Option(
721
+ False, "--web", help="以 Web 模式启动,通过浏览器 WebSocket 交互"
699
722
  ),
700
- web: bool = typer.Option(False, "--web", help="以 Web 模式启动,通过浏览器 WebSocket 交互"),
701
723
  web_host: str = typer.Option("127.0.0.1", "--web-host", help="Web 服务主机"),
702
724
  web_port: int = typer.Option(8765, "--web-port", help="Web 服务端口"),
703
725
  web_launch_cmd: Optional[str] = typer.Option(
@@ -705,7 +727,9 @@ def run_cli(
705
727
  "--web-launch-cmd",
706
728
  help="交互式终端启动命令(字符串格式,用空格分隔,如: --web-launch-cmd 'jca --task \"xxx\"')",
707
729
  ),
708
- stop: bool = typer.Option(False, "--stop", help="停止后台 Web 服务(需与 --web 一起使用)"),
730
+ stop: bool = typer.Option(
731
+ False, "--stop", help="停止后台 Web 服务(需与 --web 一起使用)"
732
+ ),
709
733
  ) -> None:
710
734
  """Jarvis AI assistant command-line interface."""
711
735
  if ctx.invoked_subcommand is not None:
@@ -714,32 +738,28 @@ def run_cli(
714
738
  # 使用 rich 输出命令与快捷方式总览
715
739
  print_commands_overview()
716
740
 
717
- # CLI 标志:非交互模式(不依赖配置文件)
718
- if non_interactive:
719
- try:
720
- os.environ["JARVIS_NON_INTERACTIVE"] = "true"
721
- except Exception:
722
- pass
723
- # 注意:全局配置同步在 init_env 之后执行,避免被覆盖
741
+ # CLI 标志:非交互模式(不依赖配置文件,仅作为 Agent 实例属性)
724
742
 
725
743
  # 同步其他 CLI 选项到全局配置,确保后续模块读取一致
726
744
  try:
727
745
  if model_group:
728
- set_config("JARVIS_LLM_GROUP", str(model_group))
746
+ set_config("llm_group", str(model_group))
729
747
  if tool_group:
730
- set_config("JARVIS_TOOL_GROUP", str(tool_group))
748
+ set_config("tool_group", str(tool_group))
731
749
  if disable_methodology_analysis:
732
- set_config("JARVIS_USE_METHODOLOGY", False)
733
- set_config("JARVIS_USE_ANALYSIS", False)
750
+ set_config("use_methodology", False)
751
+ set_config("use_analysis", False)
734
752
  if restore_session:
735
- set_config("JARVIS_RESTORE_SESSION", True)
753
+ set_config("restore_session", True)
736
754
  except Exception:
737
755
  # 静默忽略同步异常,不影响主流程
738
756
  pass
739
757
 
740
758
  # 非交互模式要求从命令行传入任务
741
759
  if non_interactive and not (task and str(task).strip()):
742
- print("❌ 非交互模式已启用:必须使用 --task 传入任务内容,因多行输入不可用。")
760
+ PrettyOutput.auto_print(
761
+ "❌ 非交互模式已启用:必须使用 --task 传入任务内容,因多行输入不可用。"
762
+ )
743
763
  raise typer.Exit(code=2)
744
764
 
745
765
  # 处理数据备份
@@ -779,10 +799,13 @@ def run_cli(
779
799
  if not pf.exists():
780
800
  # 兼容旧版本:回退检查数据目录中的旧 PID 文件位置
781
801
  try:
782
- pf_alt = Path(os.path.expanduser(os.path.expandvars(get_data_dir()))) / f"jarvis_web_{web_port}.pid"
802
+ pf_alt = (
803
+ Path(os.path.expanduser(os.path.expandvars(get_data_dir())))
804
+ / f"jarvis_web_{web_port}.pid"
805
+ )
783
806
  except Exception:
784
- pf_alt = None # type: ignore[assignment]
785
- if pf_alt and pf_alt.exists(): # type: ignore[truthy-bool]
807
+ pf_alt = None
808
+ if pf_alt and pf_alt.exists():
786
809
  pf = pf_alt
787
810
  if not pf.exists():
788
811
  # 进一步回退:尝试按端口查找并停止(无 PID 文件)
@@ -799,17 +822,23 @@ def run_cli(
799
822
  candidate_pid = int(ln.strip())
800
823
  try:
801
824
  os.kill(candidate_pid, signal.SIGTERM)
802
- print(f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。")
825
+ PrettyOutput.auto_print(
826
+ f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。"
827
+ )
803
828
  killed_any = True
804
829
  except Exception as e:
805
- print(f"⚠️ 按端口停止失败: {e}")
830
+ PrettyOutput.auto_print(
831
+ f"⚠️ 按端口停止失败: {e}"
832
+ )
806
833
  except Exception:
807
834
  continue
808
835
  except Exception:
809
836
  pass
810
837
  if not killed_any:
811
838
  try:
812
- res2 = subprocess.run(["ss", "-ltpn"], capture_output=True, text=True)
839
+ res2 = subprocess.run(
840
+ ["ss", "-ltpn"], capture_output=True, text=True
841
+ )
813
842
  if res2.returncode == 0 and res2.stdout:
814
843
  for ln in res2.stdout.splitlines():
815
844
  if f":{web_port} " in ln or f":{web_port}\n" in ln:
@@ -817,14 +846,22 @@ def run_cli(
817
846
  idx = ln.find("pid=")
818
847
  if idx != -1:
819
848
  end = ln.find(",", idx)
820
- pid_str2 = ln[idx+4:end if end != -1 else None]
849
+ pid_str2 = ln[
850
+ idx + 4 : end if end != -1 else None
851
+ ]
821
852
  candidate_pid = int(pid_str2)
822
853
  try:
823
- os.kill(candidate_pid, signal.SIGTERM)
824
- print(f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。")
854
+ os.kill(
855
+ candidate_pid, signal.SIGTERM
856
+ )
857
+ PrettyOutput.auto_print(
858
+ f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。"
859
+ )
825
860
  killed_any = True
826
861
  except Exception as e:
827
- print(f"⚠️ 按端口停止失败: {e}")
862
+ PrettyOutput.auto_print(
863
+ f"⚠️ 按端口停止失败: {e}"
864
+ )
828
865
  break
829
866
  except Exception:
830
867
  continue
@@ -841,10 +878,14 @@ def run_cli(
841
878
  p = int(ptxt)
842
879
  try:
843
880
  os.kill(p, signal.SIGTERM)
844
- print(f"✅ 已停止后台 Web 服务 (PID {p})。")
881
+ PrettyOutput.auto_print(
882
+ f"✅ 已停止后台 Web 服务 (PID {p})。"
883
+ )
845
884
  killed_any = True
846
885
  except Exception as e:
847
- print(f"⚠️ 停止 PID {p} 失败: {e}")
886
+ PrettyOutput.auto_print(
887
+ f"⚠️ 停止 PID {p} 失败: {e}"
888
+ )
848
889
  except Exception:
849
890
  pass
850
891
  try:
@@ -854,7 +895,9 @@ def run_cli(
854
895
  except Exception:
855
896
  pass
856
897
  if not killed_any:
857
- print("⚠️ 未找到后台 Web 服务的 PID 文件,可能未启动或已停止。")
898
+ PrettyOutput.auto_print(
899
+ "⚠️ 未找到后台 Web 服务的 PID 文件,可能未启动或已停止。"
900
+ )
858
901
  return
859
902
  # 优先使用 PID 文件中的 PID
860
903
  try:
@@ -866,10 +909,12 @@ def run_cli(
866
909
  if pid > 0:
867
910
  try:
868
911
  os.kill(pid, signal.SIGTERM)
869
- print(f"✅ 已向后台 Web 服务发送停止信号 (PID {pid})。")
912
+ PrettyOutput.auto_print(
913
+ f"✅ 已向后台 Web 服务发送停止信号 (PID {pid})。"
914
+ )
870
915
  killed = True
871
916
  except Exception as e:
872
- print(f"⚠️ 发送停止信号失败或进程不存在: {e}")
917
+ PrettyOutput.auto_print(f"⚠️ 发送停止信号失败或进程不存在: {e}")
873
918
  if not killed:
874
919
  # 无 PID 文件或停止失败时,尝试按端口查找进程
875
920
  candidate_pid = 0
@@ -890,7 +935,9 @@ def run_cli(
890
935
  pass
891
936
  if not candidate_pid:
892
937
  try:
893
- res2 = subprocess.run(["ss", "-ltpn"], capture_output=True, text=True)
938
+ res2 = subprocess.run(
939
+ ["ss", "-ltpn"], capture_output=True, text=True
940
+ )
894
941
  if res2.returncode == 0 and res2.stdout:
895
942
  for ln in res2.stdout.splitlines():
896
943
  if f":{web_port} " in ln or f":{web_port}\n" in ln:
@@ -899,7 +946,9 @@ def run_cli(
899
946
  idx = ln.find("pid=")
900
947
  if idx != -1:
901
948
  end = ln.find(",", idx)
902
- pid_str2 = ln[idx+4:end if end != -1 else None]
949
+ pid_str2 = ln[
950
+ idx + 4 : end if end != -1 else None
951
+ ]
903
952
  candidate_pid = int(pid_str2)
904
953
  break
905
954
  except Exception:
@@ -909,28 +958,33 @@ def run_cli(
909
958
  if candidate_pid:
910
959
  try:
911
960
  os.kill(candidate_pid, signal.SIGTERM)
912
- print(f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。")
961
+ PrettyOutput.auto_print(
962
+ f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。"
963
+ )
913
964
  killed = True
914
965
  except Exception as e:
915
- print(f"⚠️ 按端口停止失败: {e}")
966
+ PrettyOutput.auto_print(f"⚠️ 按端口停止失败: {e}")
916
967
  # 清理可能存在的 PID 文件(两个位置)
917
968
  try:
918
969
  pidfile.unlink(missing_ok=True) # 家目录位置
919
970
  except Exception:
920
971
  pass
921
972
  try:
922
- alt_pf = Path(os.path.expanduser(os.path.expandvars(get_data_dir()))) / f"jarvis_web_{web_port}.pid"
973
+ alt_pf = (
974
+ Path(os.path.expanduser(os.path.expandvars(get_data_dir())))
975
+ / f"jarvis_web_{web_port}.pid"
976
+ )
923
977
  alt_pf.unlink(missing_ok=True)
924
978
  except Exception:
925
979
  pass
926
980
  except Exception as e:
927
- print(f"❌ 停止后台 Web 服务失败: {e}")
981
+ PrettyOutput.auto_print(f"❌ 停止后台 Web 服务失败: {e}")
928
982
  finally:
929
983
  return
930
984
  # 后台启动:父进程拉起子进程并记录 PID
931
985
  is_daemon = False
932
986
  try:
933
- is_daemon = os.environ.get("JARVIS_WEB_DAEMON") == "1"
987
+ is_daemon = os.environ.get("web_daemon") == "1"
934
988
  except Exception:
935
989
  is_daemon = False
936
990
  if not is_daemon:
@@ -961,7 +1015,7 @@ def run_cli(
961
1015
  if web_launch_cmd:
962
1016
  args += ["--web-launch-cmd", str(web_launch_cmd)]
963
1017
  env = os.environ.copy()
964
- env["JARVIS_WEB_DAEMON"] = "1"
1018
+ env["web_daemon"] = "1"
965
1019
  # 启动子进程(后台运行)
966
1020
  proc = subprocess.Popen(
967
1021
  args,
@@ -980,9 +1034,11 @@ def run_cli(
980
1034
  pidfile.write_text(str(proc.pid), encoding="utf-8")
981
1035
  except Exception:
982
1036
  pass
983
- print(f"✅ Web 服务已在后台启动 (PID {proc.pid}),地址: http://{web_host}:{web_port}")
1037
+ PrettyOutput.auto_print(
1038
+ f"✅ Web 服务已在后台启动 (PID {proc.pid}),地址: http://{web_host}:{web_port}"
1039
+ )
984
1040
  except Exception as e:
985
- print(f"❌ 后台启动 Web 服务失败: {e}")
1041
+ PrettyOutput.auto_print(f"❌ 后台启动 Web 服务失败: {e}")
986
1042
  raise typer.Exit(code=1)
987
1043
  return
988
1044
 
@@ -1007,17 +1063,14 @@ def run_cli(
1007
1063
  # 在初始化环境后同步 CLI 选项到全局配置,避免被 init_env 覆盖
1008
1064
  try:
1009
1065
  if model_group:
1010
- set_config("JARVIS_LLM_GROUP", str(model_group))
1066
+ set_config("llm_group", str(model_group))
1011
1067
  if tool_group:
1012
- set_config("JARVIS_TOOL_GROUP", str(tool_group))
1068
+ set_config("tool_group", str(tool_group))
1013
1069
  if disable_methodology_analysis:
1014
- set_config("JARVIS_USE_METHODOLOGY", False)
1015
- set_config("JARVIS_USE_ANALYSIS", False)
1070
+ set_config("use_methodology", False)
1071
+ set_config("use_analysis", False)
1016
1072
  if restore_session:
1017
- set_config("JARVIS_RESTORE_SESSION", True)
1018
- if non_interactive:
1019
- # 保持运行期非交互标志
1020
- set_config("JARVIS_NON_INTERACTIVE", True)
1073
+ set_config("restore_session", True)
1021
1074
  except Exception:
1022
1075
  # 静默忽略同步异常,不影响主流程
1023
1076
  pass
@@ -1025,10 +1078,10 @@ def run_cli(
1025
1078
  # 运行主流程
1026
1079
  try:
1027
1080
  # 在 Web 模式下注入基于 WebSocket 的输入/确认回调
1028
- extra_kwargs = {}
1081
+ extra_kwargs: Dict[str, Any] = {}
1029
1082
  if web:
1030
1083
  # 纯 xterm 交互模式:不注入 WebBridge 的输入/确认回调,避免阻塞等待浏览器响应
1031
- #(交互由 /terminal PTY 会话中的 jvs 进程处理)
1084
+ # (交互由 /terminal PTY 会话中的 jvs 进程处理)
1032
1085
  pass
1033
1086
 
1034
1087
  agent_manager = AgentManager(
@@ -1044,16 +1097,19 @@ def run_cli(
1044
1097
 
1045
1098
  if web:
1046
1099
  try:
1047
-
1100
+ from jarvis.jarvis_agent.stdio_redirect import enable_web_stdin_redirect
1101
+ from jarvis.jarvis_agent.stdio_redirect import enable_web_stdio_redirect
1048
1102
  from jarvis.jarvis_agent.web_server import start_web_server
1049
- from jarvis.jarvis_agent.stdio_redirect import enable_web_stdio_redirect, enable_web_stdin_redirect
1103
+
1050
1104
  # 在 Web 模式下固定TTY宽度为200,改善前端显示效果
1051
1105
  try:
1052
1106
  import os as _os
1107
+
1053
1108
  _os.environ["COLUMNS"] = "200"
1054
1109
  # 尝试固定全局 Console 的宽度
1055
1110
  try:
1056
1111
  from jarvis.jarvis_utils.globals import console as _console
1112
+
1057
1113
  try:
1058
1114
  _console._width = 200 # rich Console的固定宽度参数
1059
1115
  except Exception:
@@ -1077,20 +1133,26 @@ def run_cli(
1077
1133
  # 解析字符串命令(支持引号)
1078
1134
  try:
1079
1135
  import shlex
1136
+
1080
1137
  launch_cmd = shlex.split(web_launch_cmd.strip())
1081
1138
  # 调试输出(可选,可以通过环境变量控制)
1082
- if os.environ.get("JARVIS_DEBUG_WEB_LAUNCH_CMD") == "1":
1083
- print(f"🔍 解析后的启动命令: {launch_cmd}")
1139
+ if os.environ.get("debug_web_launch_cmd") == "1":
1140
+ PrettyOutput.auto_print(
1141
+ f"🔍 解析后的启动命令: {launch_cmd}"
1142
+ )
1084
1143
  except Exception:
1085
1144
  # 如果解析失败,使用简单的空格分割
1086
1145
  launch_cmd = web_launch_cmd.strip().split()
1087
- if os.environ.get("JARVIS_DEBUG_WEB_LAUNCH_CMD") == "1":
1088
- print(f"🔍 使用简单分割的启动命令: {launch_cmd}")
1146
+ if os.environ.get("debug_web_launch_cmd") == "1":
1147
+ PrettyOutput.auto_print(
1148
+ f"🔍 使用简单分割的启动命令: {launch_cmd}"
1149
+ )
1089
1150
  else:
1090
1151
  # 如果没有指定,则自动构建(移除 web 相关参数)
1091
1152
  try:
1092
- import sys as _sys
1093
1153
  import os as _os
1154
+ import sys as _sys
1155
+
1094
1156
  _argv = list(_sys.argv)
1095
1157
  # 去掉程序名(argv[0]),并过滤 --web 相关参数
1096
1158
  filtered = []
@@ -1125,22 +1187,32 @@ def run_cli(
1125
1187
  launch_cmd = ["jvs"] + filtered
1126
1188
  except Exception:
1127
1189
  pass
1128
-
1190
+
1129
1191
  # 同时写入环境变量作为备选(向后兼容)
1130
1192
  if launch_cmd:
1131
1193
  try:
1132
- import os as _os
1133
1194
  import json as _json
1134
- _os.environ["JARVIS_WEB_LAUNCH_JSON"] = _json.dumps(launch_cmd, ensure_ascii=False)
1195
+ import os as _os
1196
+
1197
+ _os.environ["web_launch_json"] = _json.dumps(
1198
+ launch_cmd, ensure_ascii=False
1199
+ )
1135
1200
  except Exception:
1136
1201
  pass
1137
-
1138
- print("ℹ️ 以 Web 模式启动,请在浏览器中打开提供的地址进行交互。")
1202
+
1203
+ PrettyOutput.auto_print(
1204
+ "ℹ️ 以 Web 模式启动,请在浏览器中打开提供的地址进行交互。"
1205
+ )
1139
1206
  # 启动 Web 服务(阻塞调用),传入启动命令
1140
- start_web_server(agent_manager, host=web_host, port=web_port, launch_command=launch_cmd)
1207
+ start_web_server(
1208
+ agent_manager,
1209
+ host=web_host,
1210
+ port=web_port,
1211
+ launch_command=launch_cmd,
1212
+ )
1141
1213
  return
1142
1214
  except Exception as e:
1143
- print(f"❌ Web 模式启动失败: {e}")
1215
+ PrettyOutput.auto_print(f"❌ Web 模式启动失败: {e}")
1144
1216
  raise typer.Exit(code=1)
1145
1217
 
1146
1218
  # 默认 CLI 模式:运行任务(可能来自 --task 或交互输入)
@@ -1148,7 +1220,7 @@ def run_cli(
1148
1220
  except typer.Exit:
1149
1221
  raise
1150
1222
  except Exception as err: # pylint: disable=broad-except
1151
- print(f"❌ 初始化错误: {str(err)}")
1223
+ PrettyOutput.auto_print(f"❌ 初始化错误: {str(err)}")
1152
1224
  raise typer.Exit(code=1)
1153
1225
 
1154
1226