jarvis-ai-assistant 0.7.16__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.16.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.16.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  """
3
2
  输入处理模块
4
3
  该模块提供了处理Jarvis系统中用户输入的实用工具。
@@ -8,34 +7,44 @@
8
7
  - 带有模糊匹配的文件路径补全
9
8
  - 用于输入控制的自定义键绑定
10
9
  """
10
+
11
+ import base64
11
12
  import os
13
+
14
+ from jarvis.jarvis_utils.output import PrettyOutput
15
+
16
+ # -*- coding: utf-8 -*-
12
17
  import sys
13
- import base64
14
- from typing import Iterable, List, Optional
18
+ from typing import Iterable
19
+ from typing import List
20
+ from typing import Optional
21
+ from typing import Tuple
22
+
15
23
  import wcwidth
16
24
  from colorama import Fore
17
25
  from colorama import Style as ColoramaStyle
18
26
  from fuzzywuzzy import process
19
27
  from prompt_toolkit import PromptSession
20
- from prompt_toolkit.application import Application, run_in_terminal
28
+ from prompt_toolkit.application import Application
29
+ from prompt_toolkit.application import run_in_terminal
21
30
  from prompt_toolkit.completion import CompleteEvent
22
- from prompt_toolkit.completion import (
23
- Completer,
24
- Completion,
25
- PathCompleter,
26
- )
31
+ from prompt_toolkit.completion import Completer
32
+ from prompt_toolkit.completion import Completion
33
+ from prompt_toolkit.completion import PathCompleter
27
34
  from prompt_toolkit.document import Document
35
+ from prompt_toolkit.enums import DEFAULT_BUFFER
36
+ from prompt_toolkit.filters import has_focus
28
37
  from prompt_toolkit.formatted_text import FormattedText
29
38
  from prompt_toolkit.history import FileHistory
30
39
  from prompt_toolkit.key_binding import KeyBindings
31
- from prompt_toolkit.enums import DEFAULT_BUFFER
32
- from prompt_toolkit.filters import has_focus
33
40
  from prompt_toolkit.layout.containers import Window
34
41
  from prompt_toolkit.layout.controls import FormattedTextControl
35
42
  from prompt_toolkit.layout.layout import Layout
36
43
  from prompt_toolkit.styles import Style as PromptStyle
44
+
37
45
  from jarvis.jarvis_utils.clipboard import copy_to_clipboard
38
- from jarvis.jarvis_utils.config import get_data_dir, get_replace_map
46
+ from jarvis.jarvis_utils.config import get_data_dir
47
+ from jarvis.jarvis_utils.config import get_replace_map
39
48
  from jarvis.jarvis_utils.globals import get_message_history
40
49
  from jarvis.jarvis_utils.tag import ot
41
50
 
@@ -51,6 +60,7 @@ FZF_REQUEST_ALL_SENTINEL_PREFIX = "__FZF_REQUEST_ALL__::"
51
60
  # Persistent hint marker for multiline input (shown only once across runs)
52
61
  _MULTILINE_HINT_MARK_FILE = os.path.join(get_data_dir(), "multiline_enter_hint_shown")
53
62
 
63
+
54
64
  def _display_width(s: str) -> int:
55
65
  """计算字符串在终端中的可打印宽度(处理宽字符)。"""
56
66
  try:
@@ -65,6 +75,7 @@ def _display_width(s: str) -> int:
65
75
  except Exception:
66
76
  return len(s)
67
77
 
78
+
68
79
  def _calc_prompt_rows(prev_text: str) -> int:
69
80
  """
70
81
  估算上一个提示占用了多少终端行数。
@@ -78,7 +89,7 @@ def _calc_prompt_rows(prev_text: str) -> int:
78
89
  prefix_w = _display_width(prefix)
79
90
 
80
91
  if prev_text is None:
81
- return 1
92
+ return 1 # type: ignore
82
93
 
83
94
  lines = prev_text.splitlines()
84
95
  if not lines:
@@ -97,6 +108,7 @@ def _calc_prompt_rows(prev_text: str) -> int:
97
108
  total_rows += rows
98
109
  return max(1, total_rows)
99
110
 
111
+
100
112
  def _multiline_hint_already_shown() -> bool:
101
113
  """检查是否已显示过多行输入提示(持久化存储)。"""
102
114
  try:
@@ -104,6 +116,7 @@ def _multiline_hint_already_shown() -> bool:
104
116
  except Exception:
105
117
  return False
106
118
 
119
+
107
120
  def _mark_multiline_hint_shown() -> None:
108
121
  """持久化存储多行输入提示已显示的状态。"""
109
122
  try:
@@ -114,6 +127,7 @@ def _mark_multiline_hint_shown() -> None:
114
127
  # Non-critical persistence failure; ignore to avoid breaking input flow
115
128
  pass
116
129
 
130
+
117
131
  def get_single_line_input(tip: str, default: str = "") -> str:
118
132
  """
119
133
  获取支持历史记录的单行输入。
@@ -123,7 +137,8 @@ def get_single_line_input(tip: str, default: str = "") -> str:
123
137
  {"prompt": "ansicyan", "bottom-toolbar": "fg:#888888"}
124
138
  )
125
139
  prompt = FormattedText([("class:prompt", f"👤 > {tip}")])
126
- return session.prompt(prompt, default=default, style=style)
140
+ return str(session.prompt(prompt, default=default, style=style))
141
+
127
142
 
128
143
  def get_choice(tip: str, choices: List[str]) -> str:
129
144
  """
@@ -220,6 +235,7 @@ def get_choice(tip: str, choices: List[str]) -> str:
220
235
  except (KeyboardInterrupt, EOFError):
221
236
  return ""
222
237
 
238
+
223
239
  class FileCompleter(Completer):
224
240
  """
225
241
  带有模糊匹配的文件路径自定义补全器。
@@ -227,13 +243,113 @@ class FileCompleter(Completer):
227
243
 
228
244
  def __init__(self):
229
245
  self.path_completer = PathCompleter()
230
- self.max_suggestions = 10
246
+ self.max_suggestions = 30
231
247
  self.min_score = 10
232
248
  self.replace_map = get_replace_map()
233
249
  # Caches for file lists to avoid repeated expensive scans
234
250
  self._git_files_cache = None
235
251
  self._all_files_cache = None
236
252
  self._max_walk_files = 10000
253
+ # Cache for rules to avoid repeated loading
254
+ self._rules_cache = None
255
+
256
+ def _get_all_rule_completions(self) -> List[str]:
257
+ """获取所有规则补全项的统一接口
258
+
259
+ 返回:
260
+ List[str]: 格式为"<rule:{rule_name}>"的规则列表
261
+ """
262
+ all_rules = []
263
+ try:
264
+ import os
265
+
266
+ from jarvis.jarvis_code_agent.code_agent_rules import RulesManager
267
+
268
+ rules_manager = RulesManager(os.getcwd())
269
+ available_rules = rules_manager.get_all_available_rule_names()
270
+
271
+ # 添加内置规则
272
+ if available_rules.get("builtin"):
273
+ for rule_name in available_rules["builtin"]:
274
+ all_rules.append(f"<rule:{rule_name}>")
275
+
276
+ # 添加文件规则
277
+ if available_rules.get("files"):
278
+ for rule_name in available_rules["files"]:
279
+ all_rules.append(f"<rule:{rule_name}>")
280
+
281
+ # 添加YAML规则
282
+ if available_rules.get("yaml"):
283
+ for rule_name in available_rules["yaml"]:
284
+ all_rules.append(f"<rule:{rule_name}>")
285
+ except ImportError:
286
+ # 如果无法导入,只使用内置规则
287
+ try:
288
+ from jarvis.jarvis_code_agent.builtin_rules import list_builtin_rules
289
+
290
+ for rule_name in list_builtin_rules():
291
+ all_rules.append(f"<rule:{rule_name}>")
292
+ except ImportError:
293
+ pass
294
+ except Exception:
295
+ # 任何错误都静默处理
296
+ pass
297
+
298
+ return all_rules
299
+
300
+ def _get_all_rules(self) -> List[Tuple[str, str]]:
301
+ """获取所有可用的规则,包括内置规则、文件规则和YAML规则
302
+
303
+ 返回:
304
+ List[Tuple[str, str]]: (规则名称, 规则描述) 列表
305
+ """
306
+ if self._rules_cache is not None:
307
+ return self._rules_cache # type: ignore
308
+
309
+ all_rules = []
310
+
311
+ try:
312
+ # 导入必要的模块
313
+ import os
314
+
315
+ from jarvis.jarvis_code_agent.code_agent_rules import RulesManager
316
+
317
+ # 创建RulesManager实例
318
+ rules_manager = RulesManager(os.getcwd())
319
+
320
+ # 获取所有可用规则
321
+ available_rules = rules_manager.get_all_available_rule_names()
322
+
323
+ # 添加内置规则
324
+ if available_rules.get("builtin"):
325
+ for rule_name in available_rules["builtin"]:
326
+ all_rules.append((rule_name, f"📚 内置规则: {rule_name}"))
327
+
328
+ # 添加文件规则
329
+ if available_rules.get("files"):
330
+ for rule_name in available_rules["files"]:
331
+ all_rules.append((rule_name, f"📄 文件规则: {rule_name}"))
332
+
333
+ # 添加YAML规则
334
+ if available_rules.get("yaml"):
335
+ for rule_name in available_rules["yaml"]:
336
+ all_rules.append((rule_name, f"📝 YAML规则: {rule_name}"))
337
+
338
+ except ImportError:
339
+ # 如果无法导入,只使用内置规则
340
+ try:
341
+ from jarvis.jarvis_code_agent.builtin_rules import list_builtin_rules
342
+
343
+ for rule_name in list_builtin_rules():
344
+ all_rules.append((rule_name, f"📚 内置规则: {rule_name}"))
345
+ except ImportError:
346
+ pass
347
+ except Exception:
348
+ # 任何错误都静默处理
349
+ pass
350
+
351
+ self._rules_cache = all_rules
352
+ return all_rules
237
353
 
238
354
  def get_completions(
239
355
  self, document: Document, _: CompleteEvent
@@ -268,12 +384,18 @@ class FileCompleter(Completer):
268
384
  all_completions.extend(
269
385
  [
270
386
  (ot("Summary"), "总结"),
387
+ (ot("Pin"), "固定/置顶内容"),
271
388
  (ot("Clear"), "清除历史"),
272
389
  (ot("ToolUsage"), "工具使用说明"),
273
390
  (ot("ReloadConfig"), "重新加载配置"),
274
391
  (ot("SaveSession"), "保存当前会话"),
392
+ (ot("Quiet"), "静默模式"),
275
393
  ]
276
394
  )
395
+ # 添加所有规则(包括内置规则、文件规则、YAML规则)到补全列表
396
+ rules = self._get_all_rules()
397
+ for rule_name, rule_desc in rules:
398
+ all_completions.append((f"<rule:{rule_name}>", rule_desc))
277
399
 
278
400
  # File path candidates
279
401
  try:
@@ -353,43 +475,152 @@ class FileCompleter(Completer):
353
475
  return tag
354
476
 
355
477
 
356
- # ---------------------
478
+ def get_all_rules_formatted() -> List[str]:
479
+ """
480
+ 获取所有可用规则的格式化列表,包括内置、文件和YAML规则。
481
+
482
+ 返回:
483
+ List[str]: 格式化的规则列表,每个规则以"<rule:规则名>"格式返回
484
+
485
+ 异常处理:
486
+ - 处理RulesManager导入失败的情况
487
+ - 处理内置规则导入失败的情况
488
+ - 在任何错误情况下返回空列表而不是抛出异常
489
+ """
490
+ all_rules = []
491
+ try:
492
+ try:
493
+ import os
494
+
495
+ from jarvis.jarvis_code_agent.code_agent_rules import RulesManager
496
+
497
+ rules_manager = RulesManager(os.getcwd())
498
+ available_rules = rules_manager.get_all_available_rule_names()
499
+
500
+ # 添加内置规则
501
+ if available_rules.get("builtin"):
502
+ for rule_name in available_rules["builtin"]:
503
+ all_rules.append(f"<rule:{rule_name}>")
504
+
505
+ # 添加文件规则
506
+ if available_rules.get("files"):
507
+ for rule_name in available_rules["files"]:
508
+ all_rules.append(f"<rule:{rule_name}>")
509
+
510
+ # 添加YAML规则
511
+ if available_rules.get("yaml"):
512
+ for rule_name in available_rules["yaml"]:
513
+ all_rules.append(f"<rule:{rule_name}>")
514
+ except ImportError:
515
+ # 如果无法导入RulesManager,只使用内置规则
516
+ try:
517
+ from jarvis.jarvis_code_agent.builtin_rules import list_builtin_rules
518
+
519
+ for rule_name in list_builtin_rules():
520
+ all_rules.append(f"<rule:{rule_name}>")
521
+ except ImportError:
522
+ pass
523
+ except Exception:
524
+ # 任何异常都返回空列表
525
+ all_rules = []
526
+
527
+ return all_rules
528
+
529
+
530
+ def _get_fzf_completion_items(specials: List[str], files: List[str]) -> List[str]:
531
+ """
532
+ 获取fzf补全所需的完整项目列表。
533
+
534
+ 该函数统一处理fzf补全所需的各类项目,包括特殊符号、内置标签、规则、文件等,
535
+ 消除了两处fzf补全代码中的重复逻辑。
536
+
537
+ 参数:
538
+ specials: 特殊符号列表
539
+ files: 文件列表
540
+
541
+ 返回:
542
+ List[str]: 合并后的完整项目列表,按特定顺序排列
543
+ """
544
+ items = []
545
+
546
+ # 添加特殊符号(过滤空字符串)
547
+ items.extend([s for s in specials if isinstance(s, str) and s.strip()])
548
+
549
+ # 添加内置标签
550
+ try:
551
+ from jarvis.jarvis_utils.config import get_replace_map
552
+ from jarvis.jarvis_utils.tag import ot
553
+
554
+ replace_map = get_replace_map()
555
+ builtin_tags = [
556
+ ot(tag)
557
+ for tag in replace_map.keys()
558
+ if isinstance(tag, str) and tag.strip()
559
+ ]
560
+ items.extend(builtin_tags)
561
+ except Exception:
562
+ # 标签获取失败时跳过
563
+ pass
564
+
565
+ # 添加规则
566
+ try:
567
+ builtin_rules = get_all_rules_formatted()
568
+ items.extend(builtin_rules)
569
+ except Exception:
570
+ # 规则获取失败时跳过
571
+ pass
572
+
573
+ # 添加文件
574
+ items.extend(files)
575
+
576
+ return items
577
+
578
+
579
+ # -+
357
580
  # 公共判定辅助函数(按当前Agent优先)
358
581
  # ---------------------
359
582
  def _get_current_agent_for_input():
360
583
  try:
361
584
  import jarvis.jarvis_utils.globals as g
362
- current_name = getattr(g, "current_agent_name", "")
585
+
586
+ current_name = g.get_current_agent_name()
363
587
  if current_name:
364
588
  return g.get_agent(current_name)
365
589
  except Exception:
366
590
  pass
367
591
  return None
592
+
593
+
368
594
  def _is_non_interactive_for_current_agent() -> bool:
369
595
  try:
370
596
  from jarvis.jarvis_utils.config import is_non_interactive
597
+
371
598
  ag = _get_current_agent_for_input()
372
599
  try:
373
- return bool(getattr(ag, "non_interactive", False)) if ag else bool(is_non_interactive())
600
+ return (
601
+ bool(getattr(ag, "non_interactive", False))
602
+ if ag
603
+ else bool(is_non_interactive())
604
+ )
374
605
  except Exception:
375
606
  return bool(is_non_interactive())
376
607
  except Exception:
377
608
  return False
609
+
610
+
378
611
  def _is_auto_complete_for_current_agent() -> bool:
379
612
  try:
380
- from jarvis.jarvis_utils.config import GLOBAL_CONFIG_DATA
381
613
  ag = _get_current_agent_for_input()
382
614
  if ag is not None and hasattr(ag, "auto_complete"):
383
615
  try:
384
616
  return bool(getattr(ag, "auto_complete", False))
385
617
  except Exception:
386
618
  pass
387
- env_v = os.getenv("JARVIS_AUTO_COMPLETE")
388
- if env_v is not None:
389
- return str(env_v).strip().lower() in ("1", "true", "yes", "on")
390
- return bool(GLOBAL_CONFIG_DATA.get("JARVIS_AUTO_COMPLETE", False))
619
+ return False
391
620
  except Exception:
392
621
  return False
622
+
623
+
393
624
  def user_confirm(tip: str, default: bool = True) -> bool:
394
625
  """提示用户确认是/否问题(按当前Agent优先判断非交互)"""
395
626
  try:
@@ -401,6 +632,7 @@ def user_confirm(tip: str, default: bool = True) -> bool:
401
632
  except KeyboardInterrupt:
402
633
  return False
403
634
 
635
+
404
636
  def _show_history_and_copy():
405
637
  """
406
638
  显示消息历史记录并处理复制到剪贴板。
@@ -409,7 +641,7 @@ def _show_history_and_copy():
409
641
 
410
642
  history = get_message_history()
411
643
  if not history:
412
- print("ℹ️ 没有可复制的消息")
644
+ PrettyOutput.auto_print("ℹ️ 没有可复制的消息")
413
645
  return
414
646
 
415
647
  # 为避免 PrettyOutput 在循环中为每行加框,先拼接后统一打印
@@ -422,7 +654,7 @@ def _show_history_and_copy():
422
654
  )
423
655
  lines.append(f" {i + 1}: {display_msg.strip()}")
424
656
  lines.append("=" * 58 + "\n")
425
- print("ℹ️ " + "\n".join(lines))
657
+ PrettyOutput.auto_print("ℹ️ " + "\n".join(lines))
426
658
 
427
659
  while True:
428
660
  try:
@@ -431,11 +663,11 @@ def _show_history_and_copy():
431
663
 
432
664
  if not choice_str: # User pressed Enter
433
665
  if not history:
434
- print("ℹ️ 没有历史记录可供选择。")
666
+ PrettyOutput.auto_print("ℹ️ 没有历史记录可供选择。")
435
667
  break
436
668
  choice = len(history) - 1
437
669
  elif choice_str.lower() == "c":
438
- print("ℹ️ 已取消")
670
+ PrettyOutput.auto_print("ℹ️ 已取消")
439
671
  break
440
672
  else:
441
673
  choice = int(choice_str) - 1
@@ -443,16 +675,17 @@ def _show_history_and_copy():
443
675
  if 0 <= choice < len(history):
444
676
  selected_msg = history[choice]
445
677
  copy_to_clipboard(selected_msg)
446
- print(f"✅ 已复制消息: {selected_msg[:70]}...")
678
+ PrettyOutput.auto_print(f"✅ 已复制消息: {selected_msg[:70]}...")
447
679
  break
448
680
  else:
449
- print("⚠️ 无效的序号,请重试。")
681
+ PrettyOutput.auto_print("⚠️ 无效的序号,请重试。")
450
682
  except ValueError:
451
- print("⚠️ 无效的输入,请输入数字。")
683
+ PrettyOutput.auto_print("⚠️ 无效的输入,请输入数字。")
452
684
  except (KeyboardInterrupt, EOFError):
453
- print("\nℹ️ 操作取消")
685
+ PrettyOutput.auto_print("\nℹ️ 操作取消")
454
686
  break
455
687
 
688
+
456
689
  def _get_multiline_input_internal(
457
690
  tip: str, preset: Optional[str] = None, preset_cursor: Optional[int] = None
458
691
  ) -> str:
@@ -472,7 +705,9 @@ def _get_multiline_input_internal(
472
705
  first_enter_hint_shown = True
473
706
 
474
707
  def _show_notice():
475
- print("ℹ️ 提示:当前支持多行输入。输入完成请使用 Ctrl+J 确认;Enter 仅用于换行。")
708
+ PrettyOutput.auto_print(
709
+ "ℹ️ 提示:当前支持多行输入。输入完成请使用 Ctrl+J 确认;Enter 仅用于换行。"
710
+ )
476
711
  try:
477
712
  input("按回车继续...")
478
713
  except Exception:
@@ -508,7 +743,7 @@ def _get_multiline_input_internal(
508
743
  def _(event):
509
744
  """Return a shell command like '!bash' for upper input_handler to execute."""
510
745
 
511
- def _gen_shell_cmd() -> str: # type: ignore
746
+ def _gen_shell_cmd() -> str:
512
747
  try:
513
748
  import os
514
749
  import shutil
@@ -519,22 +754,24 @@ def _get_multiline_input_internal(
519
754
  if name == "cmd" or shutil.which(name):
520
755
  if name == "cmd":
521
756
  # Keep session open with /K and set env for the spawned shell
522
- return "!cmd /K set JARVIS_TERMINAL=1"
757
+ return "!cmd /K set terminal=1"
523
758
  else:
524
759
  # PowerShell or pwsh: set env then remain in session
525
- return f"!{name} -NoExit -Command \"$env:JARVIS_TERMINAL='1'\""
760
+ return f"!{name} -NoExit -Command \"$env:terminal='1'\""
526
761
  else:
527
762
  shell_path = os.environ.get("SHELL", "")
528
763
  if shell_path:
529
764
  base = os.path.basename(shell_path)
530
765
  if base:
531
- return f"!env JARVIS_TERMINAL=1 {base}"
766
+ return f"!env terminal=1 {base}"
532
767
  for name in ("fish", "zsh", "bash", "sh"):
533
768
  if shutil.which(name):
534
- return f"!env JARVIS_TERMINAL=1 {name}"
535
- return "!env JARVIS_TERMINAL=1 bash"
769
+ return f"!env terminal=1 {name}"
770
+ return "!env terminal=1 bash"
536
771
  except Exception:
537
- return "!env JARVIS_TERMINAL=1 bash"
772
+ return "!env terminal=1 bash"
773
+ # Fallback for all cases
774
+ return "!env terminal=1 bash"
538
775
 
539
776
  # Append a special marker to indicate no-confirm execution in shell_input_handler
540
777
  event.app.exit(result=_gen_shell_cmd() + " # JARVIS-NOCONFIRM")
@@ -545,7 +782,7 @@ def _get_multiline_input_internal(
545
782
  使用 @ 触发 fzf(当 fzf 存在);否则仅插入 @ 以启用内置补全
546
783
  逻辑:
547
784
  - 若检测到系统存在 fzf,则先插入 '@',随后请求外层运行 fzf 并在返回后进行替换/插入
548
- - 若不存在 fzf 或发生异常,则直接插入 '@'
785
+ - 若不存在 fzf 或发生异常,则直接插入 '@' 并触发补全
549
786
  """
550
787
  try:
551
788
  import shutil
@@ -553,6 +790,8 @@ def _get_multiline_input_internal(
553
790
  buf = event.current_buffer
554
791
  if shutil.which("fzf") is None:
555
792
  buf.insert_text("@")
793
+ # 手动触发补全,以便显示 rule 和其他补全选项
794
+ buf.start_completion(select_first=False)
556
795
  return
557
796
  # 先插入 '@',以便外层根据最后一个 '@' 进行片段替换
558
797
  buf.insert_text("@")
@@ -566,7 +805,10 @@ def _get_multiline_input_internal(
566
805
  return
567
806
  except Exception:
568
807
  try:
569
- event.current_buffer.insert_text("@")
808
+ buf = event.current_buffer
809
+ buf.insert_text("@")
810
+ # 即使发生异常,也尝试触发补全
811
+ buf.start_completion(select_first=False)
570
812
  except Exception:
571
813
  pass
572
814
 
@@ -581,6 +823,8 @@ def _get_multiline_input_internal(
581
823
  buf = event.current_buffer
582
824
  if shutil.which("fzf") is None:
583
825
  buf.insert_text("#")
826
+ # 手动触发补全,以便显示 rule 和其他补全选项
827
+ buf.start_completion(select_first=False)
584
828
  return
585
829
  # 先插入 '#'
586
830
  buf.insert_text("#")
@@ -594,7 +838,10 @@ def _get_multiline_input_internal(
594
838
  return
595
839
  except Exception:
596
840
  try:
597
- event.current_buffer.insert_text("#")
841
+ buf = event.current_buffer
842
+ buf.insert_text("#")
843
+ # 即使发生异常,也尝试触发补全
844
+ buf.start_completion(select_first=False)
598
845
  except Exception:
599
846
  pass
600
847
 
@@ -630,6 +877,8 @@ def _get_multiline_input_internal(
630
877
  ("class:bt.key", "Ctrl+T"),
631
878
  ("class:bt.label", " 终端(!SHELL) "),
632
879
  ("class:bt.sep", " • "),
880
+ ("class:bt.label", " '<Quiet>' 静默模式 "),
881
+ ("class:bt.sep", " • "),
633
882
  ("class:bt.key", "Ctrl+C/D"),
634
883
  ("class:bt.label", " 取消 "),
635
884
  ]
@@ -662,16 +911,18 @@ def _get_multiline_input_internal(
662
911
  pass
663
912
 
664
913
  try:
665
- return session.prompt(
914
+ result = session.prompt(
666
915
  prompt,
667
916
  style=style,
668
917
  pre_run=_pre_run,
669
918
  bottom_toolbar=_bottom_toolbar,
670
919
  default=(preset or ""),
671
- ).strip()
920
+ )
921
+ return str(result).strip() if result else ""
672
922
  except (KeyboardInterrupt, EOFError):
673
923
  return ""
674
924
 
925
+
675
926
  def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
676
927
  """
677
928
  获取带有增强补全和确认功能的多行输入。
@@ -692,7 +943,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
692
943
  ag = _get_current_agent_for_input()
693
944
  ohs = getattr(ag, "output_handler", [])
694
945
  available_agents: List[str] = []
695
- for oh in (ohs or []):
946
+ for oh in ohs or []:
696
947
  cfgs = getattr(oh, "agents_config", None)
697
948
  if isinstance(cfgs, list):
698
949
  for c in cfgs:
@@ -710,14 +961,21 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
710
961
  if n not in seen:
711
962
  seen.add(n)
712
963
  ordered.append(n)
713
- hint = "\n当前可用智能体: " + ", ".join(ordered) + f"\n如需将任务交给其他智能体,请使用 {ot('SEND_MESSAGE')} 块。"
964
+ hint = (
965
+ "\n当前可用智能体: "
966
+ + ", ".join(ordered)
967
+ + f"\n如需将任务交给其他智能体,请使用 {ot('SEND_MESSAGE')} 块。"
968
+ )
714
969
  except Exception:
715
970
  hint = ""
716
971
  if _is_auto_complete_for_current_agent():
717
- base_msg = "我无法与你交互,所有的事情你都自我决策,如果无法决策,就完成任务。输出" + ot("!!!COMPLETE!!!")
972
+ base_msg = (
973
+ "当前是非交互模式,所有的事情你都自我决策,如果无法决策,就完成任务。输出"
974
+ + ot("!!!COMPLETE!!!")
975
+ )
718
976
  return base_msg + hint
719
977
  else:
720
- return "我无法与你交互,所有的事情你都自我决策" + hint
978
+ return "当前是非交互模式,所有的事情你都自我决策" + hint
721
979
  user_input = _get_multiline_input_internal(
722
980
  tip, preset=preset, preset_cursor=preset_cursor
723
981
  )
@@ -750,7 +1008,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
750
1008
  import subprocess
751
1009
 
752
1010
  if shutil.which("fzf") is None:
753
- print("⚠️ 未检测到 fzf,无法打开文件选择器。")
1011
+ PrettyOutput.auto_print("⚠️ 未检测到 fzf,无法打开文件选择器。")
754
1012
  else:
755
1013
  files = []
756
1014
  try:
@@ -779,32 +1037,21 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
779
1037
  break
780
1038
 
781
1039
  if not files:
782
- print("ℹ️ 未找到可选择的文件。")
1040
+ PrettyOutput.auto_print("ℹ️ 未找到可选择的文件。")
783
1041
  else:
784
1042
  try:
785
1043
  specials = [
786
1044
  ot("Summary"),
1045
+ ot("Pin"),
787
1046
  ot("Clear"),
788
1047
  ot("ToolUsage"),
789
1048
  ot("ReloadConfig"),
790
1049
  ot("SaveSession"),
1050
+ ot("Quiet"),
791
1051
  ]
792
1052
  except Exception:
793
1053
  specials = []
794
- try:
795
- replace_map = get_replace_map()
796
- builtin_tags = [
797
- ot(tag)
798
- for tag in replace_map.keys()
799
- if isinstance(tag, str) and tag.strip()
800
- ]
801
- except Exception:
802
- builtin_tags = []
803
- items = (
804
- [s for s in specials if isinstance(s, str) and s.strip()]
805
- + builtin_tags
806
- + files
807
- )
1054
+ items = _get_fzf_completion_items(specials, files)
808
1055
  proc = subprocess.run(
809
1056
  [
810
1057
  "fzf",
@@ -823,7 +1070,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
823
1070
  if sel:
824
1071
  selected_path = sel
825
1072
  except Exception as e:
826
- print(f"❌ FZF 执行失败: {e}")
1073
+ PrettyOutput.auto_print(f"❌ FZF 执行失败: {e}")
827
1074
 
828
1075
  # Compute new text based on selection (or keep original if none)
829
1076
  if selected_path:
@@ -881,7 +1128,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
881
1128
  import subprocess
882
1129
 
883
1130
  if shutil.which("fzf") is None:
884
- print("⚠️ 未检测到 fzf,无法打开文件选择器。")
1131
+ PrettyOutput.auto_print("⚠️ 未检测到 fzf,无法打开文件选择器。")
885
1132
  else:
886
1133
  files = []
887
1134
  try:
@@ -902,11 +1149,12 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
902
1149
  files = []
903
1150
 
904
1151
  if not files:
905
- print("ℹ️ 未找到可选择的文件。")
1152
+ PrettyOutput.auto_print("ℹ️ 未找到可选择的文件。")
906
1153
  else:
907
1154
  try:
908
1155
  specials = [
909
1156
  ot("Summary"),
1157
+ ot("Pin"),
910
1158
  ot("Clear"),
911
1159
  ot("ToolUsage"),
912
1160
  ot("ReloadConfig"),
@@ -914,20 +1162,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
914
1162
  ]
915
1163
  except Exception:
916
1164
  specials = []
917
- try:
918
- replace_map = get_replace_map()
919
- builtin_tags = [
920
- ot(tag)
921
- for tag in replace_map.keys()
922
- if isinstance(tag, str) and tag.strip()
923
- ]
924
- except Exception:
925
- builtin_tags = []
926
- items = (
927
- [s for s in specials if isinstance(s, str) and s.strip()]
928
- + builtin_tags
929
- + files
930
- )
1165
+ items = _get_fzf_completion_items(specials, files)
931
1166
  proc = subprocess.run(
932
1167
  [
933
1168
  "fzf",
@@ -946,7 +1181,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
946
1181
  if sel:
947
1182
  selected_path = sel
948
1183
  except Exception as e:
949
- print(f"❌ FZF 执行失败: {e}")
1184
+ PrettyOutput.auto_print(f"❌ FZF 执行失败: {e}")
950
1185
 
951
1186
  # Compute new text based on selection (or keep original if none)
952
1187
  if selected_path:
@@ -1000,5 +1235,5 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
1000
1235
  continue
1001
1236
  else:
1002
1237
  if not user_input and print_on_empty:
1003
- print("ℹ️ 输入已取消")
1238
+ PrettyOutput.auto_print("ℹ️ 输入已取消")
1004
1239
  return user_input