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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +567 -222
- jarvis/jarvis_agent/agent_manager.py +19 -12
- jarvis/jarvis_agent/builtin_input_handler.py +79 -11
- jarvis/jarvis_agent/config_editor.py +7 -2
- jarvis/jarvis_agent/event_bus.py +24 -13
- jarvis/jarvis_agent/events.py +19 -1
- jarvis/jarvis_agent/file_context_handler.py +67 -64
- jarvis/jarvis_agent/file_methodology_manager.py +38 -24
- jarvis/jarvis_agent/jarvis.py +186 -114
- jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
- jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
- jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
- jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
- jarvis/jarvis_agent/language_support_info.py +250 -219
- jarvis/jarvis_agent/main.py +19 -23
- jarvis/jarvis_agent/memory_manager.py +9 -6
- jarvis/jarvis_agent/methodology_share_manager.py +21 -15
- jarvis/jarvis_agent/output_handler.py +4 -2
- jarvis/jarvis_agent/prompt_builder.py +7 -6
- jarvis/jarvis_agent/prompt_manager.py +113 -8
- jarvis/jarvis_agent/prompts.py +317 -85
- jarvis/jarvis_agent/protocols.py +5 -2
- jarvis/jarvis_agent/run_loop.py +192 -32
- jarvis/jarvis_agent/session_manager.py +7 -3
- jarvis/jarvis_agent/share_manager.py +23 -13
- jarvis/jarvis_agent/shell_input_handler.py +12 -8
- jarvis/jarvis_agent/stdio_redirect.py +25 -26
- jarvis/jarvis_agent/task_analyzer.py +29 -23
- jarvis/jarvis_agent/task_list.py +869 -0
- jarvis/jarvis_agent/task_manager.py +26 -23
- jarvis/jarvis_agent/tool_executor.py +6 -5
- jarvis/jarvis_agent/tool_share_manager.py +24 -14
- jarvis/jarvis_agent/user_interaction.py +3 -3
- jarvis/jarvis_agent/utils.py +9 -1
- jarvis/jarvis_agent/web_bridge.py +37 -17
- jarvis/jarvis_agent/web_output_sink.py +5 -2
- jarvis/jarvis_agent/web_server.py +165 -36
- jarvis/jarvis_c2rust/__init__.py +1 -1
- jarvis/jarvis_c2rust/cli.py +260 -141
- jarvis/jarvis_c2rust/collector.py +37 -18
- jarvis/jarvis_c2rust/constants.py +60 -0
- jarvis/jarvis_c2rust/library_replacer.py +242 -1010
- jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
- jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
- jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
- jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
- jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
- jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
- jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
- jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
- jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
- jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
- jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
- jarvis/jarvis_c2rust/loaders.py +28 -10
- jarvis/jarvis_c2rust/models.py +5 -2
- jarvis/jarvis_c2rust/optimizer.py +192 -1974
- jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
- jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
- jarvis/jarvis_c2rust/optimizer_config.py +49 -0
- jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
- jarvis/jarvis_c2rust/optimizer_options.py +48 -0
- jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
- jarvis/jarvis_c2rust/optimizer_report.py +52 -0
- jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
- jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
- jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
- jarvis/jarvis_c2rust/scanner.py +229 -166
- jarvis/jarvis_c2rust/transpiler.py +531 -2732
- jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
- jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
- jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
- jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
- jarvis/jarvis_c2rust/transpiler_config.py +178 -0
- jarvis/jarvis_c2rust/transpiler_context.py +122 -0
- jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
- jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
- jarvis/jarvis_c2rust/transpiler_git.py +163 -0
- jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
- jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
- jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
- jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
- jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
- jarvis/jarvis_c2rust/utils.py +269 -79
- jarvis/jarvis_code_agent/after_change.py +233 -0
- jarvis/jarvis_code_agent/build_validation_config.py +37 -30
- jarvis/jarvis_code_agent/builtin_rules.py +68 -0
- jarvis/jarvis_code_agent/code_agent.py +976 -1517
- jarvis/jarvis_code_agent/code_agent_build.py +227 -0
- jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
- jarvis/jarvis_code_agent/code_agent_git.py +525 -0
- jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
- jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
- jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
- jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
- jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
- jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
- jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
- jarvis/jarvis_code_agent/lint.py +223 -524
- jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
- jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
- jarvis/jarvis_code_agent/rules/code_review.md +115 -0
- jarvis/jarvis_code_agent/rules/documentation.md +165 -0
- jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
- jarvis/jarvis_code_agent/rules/performance.md +158 -0
- jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
- jarvis/jarvis_code_agent/rules/security.md +160 -0
- jarvis/jarvis_code_agent/rules/tdd.md +78 -0
- jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
- jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
- jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
- jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
- jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
- jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
- jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
- jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
- jarvis/jarvis_code_agent/utils.py +36 -26
- jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
- jarvis/jarvis_code_analysis/code_review.py +64 -33
- jarvis/jarvis_data/config_schema.json +285 -192
- jarvis/jarvis_git_squash/main.py +8 -6
- jarvis/jarvis_git_utils/git_commiter.py +53 -76
- jarvis/jarvis_mcp/__init__.py +5 -2
- jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
- jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
- jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
- jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
- jarvis/jarvis_methodology/main.py +48 -39
- jarvis/jarvis_multi_agent/__init__.py +56 -23
- jarvis/jarvis_multi_agent/main.py +15 -18
- jarvis/jarvis_platform/base.py +179 -111
- jarvis/jarvis_platform/human.py +27 -16
- jarvis/jarvis_platform/kimi.py +52 -45
- jarvis/jarvis_platform/openai.py +101 -40
- jarvis/jarvis_platform/registry.py +51 -33
- jarvis/jarvis_platform/tongyi.py +68 -38
- jarvis/jarvis_platform/yuanbao.py +59 -43
- jarvis/jarvis_platform_manager/main.py +68 -76
- jarvis/jarvis_platform_manager/service.py +24 -14
- jarvis/jarvis_rag/README_CONFIG.md +314 -0
- jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
- jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
- jarvis/jarvis_rag/__init__.py +57 -4
- jarvis/jarvis_rag/cache.py +3 -1
- jarvis/jarvis_rag/cli.py +48 -68
- jarvis/jarvis_rag/embedding_interface.py +39 -0
- jarvis/jarvis_rag/embedding_manager.py +7 -230
- jarvis/jarvis_rag/embeddings/__init__.py +41 -0
- jarvis/jarvis_rag/embeddings/base.py +114 -0
- jarvis/jarvis_rag/embeddings/cohere.py +66 -0
- jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
- jarvis/jarvis_rag/embeddings/local.py +260 -0
- jarvis/jarvis_rag/embeddings/openai.py +62 -0
- jarvis/jarvis_rag/embeddings/registry.py +293 -0
- jarvis/jarvis_rag/llm_interface.py +8 -6
- jarvis/jarvis_rag/query_rewriter.py +8 -9
- jarvis/jarvis_rag/rag_pipeline.py +61 -52
- jarvis/jarvis_rag/reranker.py +7 -75
- jarvis/jarvis_rag/reranker_interface.py +32 -0
- jarvis/jarvis_rag/rerankers/__init__.py +41 -0
- jarvis/jarvis_rag/rerankers/base.py +109 -0
- jarvis/jarvis_rag/rerankers/cohere.py +67 -0
- jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
- jarvis/jarvis_rag/rerankers/jina.py +79 -0
- jarvis/jarvis_rag/rerankers/local.py +89 -0
- jarvis/jarvis_rag/rerankers/registry.py +293 -0
- jarvis/jarvis_rag/retriever.py +58 -43
- jarvis/jarvis_sec/__init__.py +66 -141
- jarvis/jarvis_sec/agents.py +21 -17
- jarvis/jarvis_sec/analysis.py +80 -33
- jarvis/jarvis_sec/checkers/__init__.py +7 -13
- jarvis/jarvis_sec/checkers/c_checker.py +356 -164
- jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
- jarvis/jarvis_sec/cli.py +43 -21
- jarvis/jarvis_sec/clustering.py +430 -272
- jarvis/jarvis_sec/file_manager.py +99 -55
- jarvis/jarvis_sec/parsers.py +9 -6
- jarvis/jarvis_sec/prompts.py +4 -3
- jarvis/jarvis_sec/report.py +44 -22
- jarvis/jarvis_sec/review.py +180 -107
- jarvis/jarvis_sec/status.py +50 -41
- jarvis/jarvis_sec/types.py +3 -0
- jarvis/jarvis_sec/utils.py +160 -83
- jarvis/jarvis_sec/verification.py +411 -181
- jarvis/jarvis_sec/workflow.py +132 -21
- jarvis/jarvis_smart_shell/main.py +28 -41
- jarvis/jarvis_stats/cli.py +14 -12
- jarvis/jarvis_stats/stats.py +28 -19
- jarvis/jarvis_stats/storage.py +14 -8
- jarvis/jarvis_stats/visualizer.py +12 -7
- jarvis/jarvis_tools/base.py +5 -2
- jarvis/jarvis_tools/clear_memory.py +13 -9
- jarvis/jarvis_tools/cli/main.py +23 -18
- jarvis/jarvis_tools/edit_file.py +572 -873
- jarvis/jarvis_tools/execute_script.py +10 -7
- jarvis/jarvis_tools/file_analyzer.py +7 -8
- jarvis/jarvis_tools/meta_agent.py +287 -0
- jarvis/jarvis_tools/methodology.py +5 -3
- jarvis/jarvis_tools/read_code.py +305 -1438
- jarvis/jarvis_tools/read_symbols.py +50 -17
- jarvis/jarvis_tools/read_webpage.py +19 -18
- jarvis/jarvis_tools/registry.py +435 -156
- jarvis/jarvis_tools/retrieve_memory.py +16 -11
- jarvis/jarvis_tools/save_memory.py +8 -6
- jarvis/jarvis_tools/search_web.py +31 -31
- jarvis/jarvis_tools/sub_agent.py +32 -28
- jarvis/jarvis_tools/sub_code_agent.py +44 -60
- jarvis/jarvis_tools/task_list_manager.py +1811 -0
- jarvis/jarvis_tools/virtual_tty.py +29 -19
- jarvis/jarvis_utils/__init__.py +4 -0
- jarvis/jarvis_utils/builtin_replace_map.py +2 -1
- jarvis/jarvis_utils/clipboard.py +9 -8
- jarvis/jarvis_utils/collections.py +331 -0
- jarvis/jarvis_utils/config.py +699 -194
- jarvis/jarvis_utils/dialogue_recorder.py +294 -0
- jarvis/jarvis_utils/embedding.py +6 -3
- jarvis/jarvis_utils/file_processors.py +7 -1
- jarvis/jarvis_utils/fzf.py +9 -3
- jarvis/jarvis_utils/git_utils.py +71 -42
- jarvis/jarvis_utils/globals.py +116 -32
- jarvis/jarvis_utils/http.py +6 -2
- jarvis/jarvis_utils/input.py +318 -83
- jarvis/jarvis_utils/jsonnet_compat.py +119 -104
- jarvis/jarvis_utils/methodology.py +37 -28
- jarvis/jarvis_utils/output.py +201 -44
- jarvis/jarvis_utils/utils.py +986 -628
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
- jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
- jarvis/jarvis_tools/generate_new_tool.py +0 -205
- jarvis/jarvis_tools/lsp_client.py +0 -1552
- jarvis/jarvis_tools/rewrite_file.py +0 -105
- jarvis_ai_assistant-0.7.8.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
jarvis/jarvis_utils/input.py
CHANGED
|
@@ -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
|
|
14
|
-
from typing import
|
|
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
|
|
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
|
-
|
|
24
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
666
|
+
PrettyOutput.auto_print("ℹ️ 没有历史记录可供选择。")
|
|
435
667
|
break
|
|
436
668
|
choice = len(history) - 1
|
|
437
669
|
elif choice_str.lower() == "c":
|
|
438
|
-
|
|
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
|
-
|
|
678
|
+
PrettyOutput.auto_print(f"✅ 已复制消息: {selected_msg[:70]}...")
|
|
447
679
|
break
|
|
448
680
|
else:
|
|
449
|
-
|
|
681
|
+
PrettyOutput.auto_print("⚠️ 无效的序号,请重试。")
|
|
450
682
|
except ValueError:
|
|
451
|
-
|
|
683
|
+
PrettyOutput.auto_print("⚠️ 无效的输入,请输入数字。")
|
|
452
684
|
except (KeyboardInterrupt, EOFError):
|
|
453
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
535
|
-
return "!env
|
|
769
|
+
return f"!env terminal=1 {name}"
|
|
770
|
+
return "!env terminal=1 bash"
|
|
536
771
|
except Exception:
|
|
537
|
-
return "!env
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
)
|
|
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
|
|
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 =
|
|
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 =
|
|
972
|
+
base_msg = (
|
|
973
|
+
"当前是非交互模式,所有的事情你都自我决策,如果无法决策,就完成任务。输出"
|
|
974
|
+
+ ot("!!!COMPLETE!!!")
|
|
975
|
+
)
|
|
718
976
|
return base_msg + hint
|
|
719
977
|
else:
|
|
720
|
-
return "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1238
|
+
PrettyOutput.auto_print("ℹ️ 输入已取消")
|
|
1004
1239
|
return user_input
|