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.
- 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.16.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.16.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
jarvis/jarvis_agent/jarvis.py
CHANGED
|
@@ -1,38 +1,41 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
"""Jarvis AI 助手主入口模块"""
|
|
3
|
-
|
|
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.
|
|
14
|
-
from jarvis.jarvis_utils.config import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
28
|
-
import
|
|
29
|
-
from
|
|
30
|
-
import
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
216
|
+
PrettyOutput.auto_print(f"✅ 配置已更新: {config_path}")
|
|
212
217
|
return True
|
|
213
218
|
except Exception as e:
|
|
214
|
-
|
|
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
|
-
|
|
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
|
-
|
|
245
|
+
PrettyOutput.auto_print(f"✅ 数据已成功备份到: {archive_path}")
|
|
241
246
|
except Exception as e:
|
|
242
|
-
|
|
247
|
+
PrettyOutput.auto_print(f"❌ 数据备份失败: {e}")
|
|
243
248
|
|
|
244
249
|
return True
|
|
245
250
|
|
|
246
251
|
|
|
247
|
-
def handle_restore_option(
|
|
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
|
-
|
|
262
|
+
PrettyOutput.auto_print(f"❌ 指定的恢复文件不存在: {restore_file}")
|
|
256
263
|
return True
|
|
257
264
|
|
|
258
265
|
# 在恢复数据时不要触发完整环境初始化,避免引导流程或网络请求
|
|
259
|
-
# 优先从配置文件解析
|
|
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("
|
|
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
|
-
|
|
290
|
+
PrettyOutput.auto_print("ℹ️ 恢复操作已取消。")
|
|
284
291
|
return True
|
|
285
292
|
try:
|
|
286
293
|
shutil.rmtree(data_dir)
|
|
287
294
|
except Exception as e:
|
|
288
|
-
|
|
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
|
-
|
|
301
|
+
PrettyOutput.auto_print(f"✅ 数据已从 '{restore_path}' 成功恢复到 '{data_dir}'")
|
|
295
302
|
|
|
296
303
|
except Exception as e:
|
|
297
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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("
|
|
453
|
-
|
|
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
|
-
|
|
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): ",
|
|
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
|
-
|
|
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,
|
|
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(
|
|
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("
|
|
746
|
+
set_config("llm_group", str(model_group))
|
|
729
747
|
if tool_group:
|
|
730
|
-
set_config("
|
|
748
|
+
set_config("tool_group", str(tool_group))
|
|
731
749
|
if disable_methodology_analysis:
|
|
732
|
-
set_config("
|
|
733
|
-
set_config("
|
|
750
|
+
set_config("use_methodology", False)
|
|
751
|
+
set_config("use_analysis", False)
|
|
734
752
|
if restore_session:
|
|
735
|
-
set_config("
|
|
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
|
-
|
|
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 =
|
|
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
|
|
785
|
-
if pf_alt and pf_alt.exists():
|
|
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
|
-
|
|
825
|
+
PrettyOutput.auto_print(
|
|
826
|
+
f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。"
|
|
827
|
+
)
|
|
803
828
|
killed_any = True
|
|
804
829
|
except Exception as e:
|
|
805
|
-
|
|
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(
|
|
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[
|
|
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(
|
|
824
|
-
|
|
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
|
-
|
|
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
|
-
|
|
881
|
+
PrettyOutput.auto_print(
|
|
882
|
+
f"✅ 已停止后台 Web 服务 (PID {p})。"
|
|
883
|
+
)
|
|
845
884
|
killed_any = True
|
|
846
885
|
except Exception as e:
|
|
847
|
-
|
|
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
|
-
|
|
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
|
-
|
|
912
|
+
PrettyOutput.auto_print(
|
|
913
|
+
f"✅ 已向后台 Web 服务发送停止信号 (PID {pid})。"
|
|
914
|
+
)
|
|
870
915
|
killed = True
|
|
871
916
|
except Exception as e:
|
|
872
|
-
|
|
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(
|
|
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[
|
|
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
|
-
|
|
961
|
+
PrettyOutput.auto_print(
|
|
962
|
+
f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。"
|
|
963
|
+
)
|
|
913
964
|
killed = True
|
|
914
965
|
except Exception as e:
|
|
915
|
-
|
|
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 =
|
|
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
|
-
|
|
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("
|
|
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["
|
|
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
|
-
|
|
1037
|
+
PrettyOutput.auto_print(
|
|
1038
|
+
f"✅ Web 服务已在后台启动 (PID {proc.pid}),地址: http://{web_host}:{web_port}"
|
|
1039
|
+
)
|
|
984
1040
|
except Exception as e:
|
|
985
|
-
|
|
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("
|
|
1066
|
+
set_config("llm_group", str(model_group))
|
|
1011
1067
|
if tool_group:
|
|
1012
|
-
set_config("
|
|
1068
|
+
set_config("tool_group", str(tool_group))
|
|
1013
1069
|
if disable_methodology_analysis:
|
|
1014
|
-
set_config("
|
|
1015
|
-
set_config("
|
|
1070
|
+
set_config("use_methodology", False)
|
|
1071
|
+
set_config("use_analysis", False)
|
|
1016
1072
|
if restore_session:
|
|
1017
|
-
set_config("
|
|
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
|
-
|
|
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
|
-
|
|
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("
|
|
1083
|
-
|
|
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("
|
|
1088
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1202
|
+
|
|
1203
|
+
PrettyOutput.auto_print(
|
|
1204
|
+
"ℹ️ 以 Web 模式启动,请在浏览器中打开提供的地址进行交互。"
|
|
1205
|
+
)
|
|
1139
1206
|
# 启动 Web 服务(阻塞调用),传入启动命令
|
|
1140
|
-
start_web_server(
|
|
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
|
-
|
|
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
|
-
|
|
1223
|
+
PrettyOutput.auto_print(f"❌ 初始化错误: {str(err)}")
|
|
1152
1224
|
raise typer.Exit(code=1)
|
|
1153
1225
|
|
|
1154
1226
|
|