jarvis-ai-assistant 0.7.0__py3-none-any.whl → 0.7.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +243 -139
- jarvis/jarvis_agent/agent_manager.py +5 -10
- jarvis/jarvis_agent/builtin_input_handler.py +2 -6
- jarvis/jarvis_agent/config_editor.py +2 -7
- jarvis/jarvis_agent/event_bus.py +82 -12
- jarvis/jarvis_agent/file_context_handler.py +265 -15
- jarvis/jarvis_agent/file_methodology_manager.py +3 -4
- jarvis/jarvis_agent/jarvis.py +113 -98
- jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
- jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
- jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
- jarvis/jarvis_agent/language_support_info.py +486 -0
- jarvis/jarvis_agent/main.py +6 -12
- jarvis/jarvis_agent/memory_manager.py +7 -16
- jarvis/jarvis_agent/methodology_share_manager.py +10 -16
- jarvis/jarvis_agent/prompt_manager.py +1 -1
- jarvis/jarvis_agent/prompts.py +193 -171
- jarvis/jarvis_agent/protocols.py +8 -12
- jarvis/jarvis_agent/run_loop.py +77 -14
- jarvis/jarvis_agent/session_manager.py +2 -3
- jarvis/jarvis_agent/share_manager.py +12 -21
- jarvis/jarvis_agent/shell_input_handler.py +1 -2
- jarvis/jarvis_agent/task_analyzer.py +26 -4
- jarvis/jarvis_agent/task_manager.py +11 -27
- jarvis/jarvis_agent/tool_executor.py +2 -3
- jarvis/jarvis_agent/tool_share_manager.py +12 -24
- jarvis/jarvis_agent/web_server.py +55 -20
- jarvis/jarvis_c2rust/__init__.py +5 -5
- jarvis/jarvis_c2rust/cli.py +461 -499
- jarvis/jarvis_c2rust/collector.py +45 -53
- jarvis/jarvis_c2rust/constants.py +26 -0
- jarvis/jarvis_c2rust/library_replacer.py +264 -132
- jarvis/jarvis_c2rust/llm_module_agent.py +162 -190
- jarvis/jarvis_c2rust/loaders.py +207 -0
- jarvis/jarvis_c2rust/models.py +28 -0
- jarvis/jarvis_c2rust/optimizer.py +1592 -395
- jarvis/jarvis_c2rust/transpiler.py +1722 -1064
- jarvis/jarvis_c2rust/utils.py +385 -0
- jarvis/jarvis_code_agent/build_validation_config.py +2 -3
- jarvis/jarvis_code_agent/code_agent.py +394 -320
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +3 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +4 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +17 -2
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +3 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +36 -4
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +9 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +9 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +12 -1
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +22 -5
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +57 -32
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +62 -6
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +8 -9
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +290 -5
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +21 -3
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +72 -4
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +35 -3
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +52 -2
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +73 -1
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +306 -152
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +193 -18
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +18 -8
- jarvis/jarvis_code_agent/lint.py +258 -27
- jarvis/jarvis_code_agent/utils.py +0 -1
- jarvis/jarvis_code_analysis/code_review.py +19 -24
- jarvis/jarvis_data/config_schema.json +53 -26
- jarvis/jarvis_git_squash/main.py +4 -5
- jarvis/jarvis_git_utils/git_commiter.py +44 -49
- jarvis/jarvis_mcp/sse_mcp_client.py +20 -27
- jarvis/jarvis_mcp/stdio_mcp_client.py +11 -12
- jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
- jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
- jarvis/jarvis_methodology/main.py +32 -48
- jarvis/jarvis_multi_agent/__init__.py +79 -61
- jarvis/jarvis_multi_agent/main.py +3 -7
- jarvis/jarvis_platform/base.py +469 -199
- jarvis/jarvis_platform/human.py +7 -8
- jarvis/jarvis_platform/kimi.py +30 -36
- jarvis/jarvis_platform/openai.py +65 -27
- jarvis/jarvis_platform/registry.py +26 -10
- jarvis/jarvis_platform/tongyi.py +24 -25
- jarvis/jarvis_platform/yuanbao.py +31 -42
- jarvis/jarvis_platform_manager/main.py +66 -77
- jarvis/jarvis_platform_manager/service.py +8 -13
- jarvis/jarvis_rag/cli.py +49 -51
- jarvis/jarvis_rag/embedding_manager.py +13 -18
- jarvis/jarvis_rag/llm_interface.py +8 -9
- jarvis/jarvis_rag/query_rewriter.py +10 -21
- jarvis/jarvis_rag/rag_pipeline.py +24 -27
- jarvis/jarvis_rag/reranker.py +4 -5
- jarvis/jarvis_rag/retriever.py +28 -30
- jarvis/jarvis_sec/__init__.py +220 -3520
- jarvis/jarvis_sec/agents.py +143 -0
- jarvis/jarvis_sec/analysis.py +276 -0
- jarvis/jarvis_sec/cli.py +29 -6
- jarvis/jarvis_sec/clustering.py +1439 -0
- jarvis/jarvis_sec/file_manager.py +427 -0
- jarvis/jarvis_sec/parsers.py +73 -0
- jarvis/jarvis_sec/prompts.py +268 -0
- jarvis/jarvis_sec/report.py +83 -4
- jarvis/jarvis_sec/review.py +453 -0
- jarvis/jarvis_sec/utils.py +499 -0
- jarvis/jarvis_sec/verification.py +848 -0
- jarvis/jarvis_sec/workflow.py +7 -0
- jarvis/jarvis_smart_shell/main.py +38 -87
- jarvis/jarvis_stats/cli.py +1 -1
- jarvis/jarvis_stats/stats.py +7 -7
- jarvis/jarvis_stats/storage.py +15 -21
- jarvis/jarvis_tools/clear_memory.py +3 -20
- jarvis/jarvis_tools/cli/main.py +20 -23
- jarvis/jarvis_tools/edit_file.py +1066 -0
- jarvis/jarvis_tools/execute_script.py +42 -21
- jarvis/jarvis_tools/file_analyzer.py +6 -9
- jarvis/jarvis_tools/generate_new_tool.py +11 -20
- jarvis/jarvis_tools/lsp_client.py +1552 -0
- jarvis/jarvis_tools/methodology.py +2 -3
- jarvis/jarvis_tools/read_code.py +1525 -87
- jarvis/jarvis_tools/read_symbols.py +2 -3
- jarvis/jarvis_tools/read_webpage.py +7 -10
- jarvis/jarvis_tools/registry.py +370 -181
- jarvis/jarvis_tools/retrieve_memory.py +20 -19
- jarvis/jarvis_tools/rewrite_file.py +105 -0
- jarvis/jarvis_tools/save_memory.py +3 -15
- jarvis/jarvis_tools/search_web.py +3 -7
- jarvis/jarvis_tools/sub_agent.py +17 -6
- jarvis/jarvis_tools/sub_code_agent.py +14 -16
- jarvis/jarvis_tools/virtual_tty.py +54 -32
- jarvis/jarvis_utils/clipboard.py +7 -10
- jarvis/jarvis_utils/config.py +98 -63
- jarvis/jarvis_utils/embedding.py +5 -5
- jarvis/jarvis_utils/fzf.py +8 -8
- jarvis/jarvis_utils/git_utils.py +81 -67
- jarvis/jarvis_utils/input.py +24 -49
- jarvis/jarvis_utils/jsonnet_compat.py +465 -0
- jarvis/jarvis_utils/methodology.py +33 -35
- jarvis/jarvis_utils/utils.py +245 -202
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/METADATA +205 -70
- jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
- jarvis/jarvis_agent/edit_file_handler.py +0 -584
- jarvis/jarvis_agent/rewrite_file_handler.py +0 -141
- jarvis/jarvis_agent/task_planner.py +0 -496
- jarvis/jarvis_platform/ai8.py +0 -332
- jarvis/jarvis_tools/ask_user.py +0 -54
- jarvis_ai_assistant-0.7.0.dist-info/RECORD +0 -192
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
jarvis/jarvis_agent/jarvis.py
CHANGED
|
@@ -6,7 +6,6 @@ from datetime import datetime
|
|
|
6
6
|
|
|
7
7
|
import typer
|
|
8
8
|
|
|
9
|
-
from jarvis.jarvis_agent import OutputType, PrettyOutput
|
|
10
9
|
from jarvis.jarvis_agent.agent_manager import AgentManager
|
|
11
10
|
from jarvis.jarvis_agent.config_editor import ConfigEditor
|
|
12
11
|
from jarvis.jarvis_agent.methodology_share_manager import MethodologyShareManager
|
|
@@ -170,7 +169,7 @@ def handle_interactive_config_option(
|
|
|
170
169
|
config_data, ask_all=True
|
|
171
170
|
)
|
|
172
171
|
if not changed:
|
|
173
|
-
|
|
172
|
+
print("ℹ️ 没有需要更新的配置项,保持现有配置。")
|
|
174
173
|
return True
|
|
175
174
|
|
|
176
175
|
# 剔除与 schema 默认值一致的键,保持配置精简
|
|
@@ -209,10 +208,10 @@ def handle_interactive_config_option(
|
|
|
209
208
|
wf.write(header)
|
|
210
209
|
wf.write(yaml_str)
|
|
211
210
|
|
|
212
|
-
|
|
211
|
+
print(f"✅ 配置已更新: {config_path}")
|
|
213
212
|
return True
|
|
214
213
|
except Exception as e:
|
|
215
|
-
|
|
214
|
+
print(f"❌ 交互式配置失败: {e}")
|
|
216
215
|
return True
|
|
217
216
|
|
|
218
217
|
|
|
@@ -224,7 +223,7 @@ def handle_backup_option(backup_dir_path: Optional[str]) -> bool:
|
|
|
224
223
|
init_env("", config_file=None)
|
|
225
224
|
data_dir = Path(get_data_dir())
|
|
226
225
|
if not data_dir.is_dir():
|
|
227
|
-
|
|
226
|
+
print(f"❌ 数据目录不存在: {data_dir}")
|
|
228
227
|
return True
|
|
229
228
|
|
|
230
229
|
backup_dir_str = backup_dir_path if backup_dir_path.strip() else "~/jarvis_backups"
|
|
@@ -238,9 +237,9 @@ def handle_backup_option(backup_dir_path: Optional[str]) -> bool:
|
|
|
238
237
|
archive_path = shutil.make_archive(
|
|
239
238
|
str(backup_file_base), "zip", root_dir=str(data_dir)
|
|
240
239
|
)
|
|
241
|
-
|
|
240
|
+
print(f"✅ 数据已成功备份到: {archive_path}")
|
|
242
241
|
except Exception as e:
|
|
243
|
-
|
|
242
|
+
print(f"❌ 数据备份失败: {e}")
|
|
244
243
|
|
|
245
244
|
return True
|
|
246
245
|
|
|
@@ -253,7 +252,7 @@ def handle_restore_option(restore_path: Optional[str], config_file: Optional[str
|
|
|
253
252
|
restore_file = Path(os.path.expanduser(os.path.expandvars(restore_path)))
|
|
254
253
|
# 兼容 ~ 与环境变量,避免用户输入未展开路径导致找不到文件
|
|
255
254
|
if not restore_file.is_file():
|
|
256
|
-
|
|
255
|
+
print(f"❌ 指定的恢复文件不存在: {restore_file}")
|
|
257
256
|
return True
|
|
258
257
|
|
|
259
258
|
# 在恢复数据时不要触发完整环境初始化,避免引导流程或网络请求
|
|
@@ -281,23 +280,21 @@ def handle_restore_option(restore_path: Optional[str], config_file: Optional[str
|
|
|
281
280
|
if not user_confirm(
|
|
282
281
|
f"数据目录 '{data_dir}' 已存在,恢复操作将覆盖它。是否继续?", default=False
|
|
283
282
|
):
|
|
284
|
-
|
|
283
|
+
print("ℹ️ 恢复操作已取消。")
|
|
285
284
|
return True
|
|
286
285
|
try:
|
|
287
286
|
shutil.rmtree(data_dir)
|
|
288
287
|
except Exception as e:
|
|
289
|
-
|
|
288
|
+
print(f"❌ 无法移除现有数据目录: {e}")
|
|
290
289
|
return True
|
|
291
290
|
|
|
292
291
|
try:
|
|
293
292
|
data_dir.mkdir(parents=True)
|
|
294
293
|
shutil.unpack_archive(str(restore_file), str(data_dir), "zip")
|
|
295
|
-
|
|
296
|
-
f"数据已从 '{restore_path}' 成功恢复到 '{data_dir}'", OutputType.SUCCESS
|
|
297
|
-
)
|
|
294
|
+
print(f"✅ 数据已从 '{restore_path}' 成功恢复到 '{data_dir}'")
|
|
298
295
|
|
|
299
296
|
except Exception as e:
|
|
300
|
-
|
|
297
|
+
print(f"❌ 数据恢复失败: {e}")
|
|
301
298
|
|
|
302
299
|
return True
|
|
303
300
|
|
|
@@ -333,9 +330,7 @@ def try_switch_to_jca_if_git_repo(
|
|
|
333
330
|
if res.returncode == 0:
|
|
334
331
|
git_root = res.stdout.strip()
|
|
335
332
|
if git_root and os.path.isdir(git_root):
|
|
336
|
-
|
|
337
|
-
f"检测到当前位于 Git 仓库: {git_root}", OutputType.INFO
|
|
338
|
-
)
|
|
333
|
+
print(f"ℹ️ 检测到当前位于 Git 仓库: {git_root}")
|
|
339
334
|
if user_confirm(
|
|
340
335
|
"检测到Git仓库,是否切换到代码开发模式(jca)?", default=False
|
|
341
336
|
):
|
|
@@ -351,10 +346,7 @@ def try_switch_to_jca_if_git_repo(
|
|
|
351
346
|
args += ["--restore-session"]
|
|
352
347
|
if task:
|
|
353
348
|
args += ["-r", task]
|
|
354
|
-
|
|
355
|
-
"正在切换到 'jca'(jarvis-code-agent)以进入代码开发模式...",
|
|
356
|
-
OutputType.INFO,
|
|
357
|
-
)
|
|
349
|
+
print("ℹ️ 正在切换到 'jca'(jarvis-code-agent)以进入代码开发模式...")
|
|
358
350
|
os.execvp(args[0], args)
|
|
359
351
|
except Exception:
|
|
360
352
|
# 静默忽略检测异常,不影响主流程
|
|
@@ -458,10 +450,7 @@ def handle_builtin_config_selector(
|
|
|
458
450
|
# 可选调试输出:查看每类的搜索目录
|
|
459
451
|
try:
|
|
460
452
|
if os.environ.get("JARVIS_DEBUG_BUILTIN_SELECTOR") == "1":
|
|
461
|
-
|
|
462
|
-
f"DEBUG: category={cat} search_dirs=" + ", ".join(str(p) for p in unique_dirs),
|
|
463
|
-
OutputType.INFO,
|
|
464
|
-
)
|
|
453
|
+
print(f"ℹ️ DEBUG: category={cat} search_dirs=" + ", ".join(str(p) for p in unique_dirs))
|
|
465
454
|
except Exception:
|
|
466
455
|
pass
|
|
467
456
|
|
|
@@ -538,7 +527,7 @@ def handle_builtin_config_selector(
|
|
|
538
527
|
},
|
|
539
528
|
)
|
|
540
529
|
|
|
541
|
-
|
|
530
|
+
print("✅ 可用的内置配置")
|
|
542
531
|
# 使用 rich Table 呈现
|
|
543
532
|
table = Table(show_header=True, header_style="bold magenta")
|
|
544
533
|
table.add_column("No.", style="cyan", no_wrap=True)
|
|
@@ -643,9 +632,7 @@ def handle_builtin_config_selector(
|
|
|
643
632
|
args += ["-g", str(model_group)]
|
|
644
633
|
|
|
645
634
|
if args:
|
|
646
|
-
|
|
647
|
-
f"正在启动: {' '.join(args)}", OutputType.INFO
|
|
648
|
-
)
|
|
635
|
+
print(f"ℹ️ 正在启动: {' '.join(args)}")
|
|
649
636
|
os.execvp(args[0], args)
|
|
650
637
|
except Exception:
|
|
651
638
|
# 任何异常都不影响默认流程
|
|
@@ -710,10 +697,14 @@ def run_cli(
|
|
|
710
697
|
non_interactive: bool = typer.Option(
|
|
711
698
|
False, "-n", "--non-interactive", help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟"
|
|
712
699
|
),
|
|
713
|
-
plan: Optional[bool] = typer.Option(None, "--plan/--no-plan", help="启用或禁用任务规划(不指定则从配置加载)"),
|
|
714
700
|
web: bool = typer.Option(False, "--web", help="以 Web 模式启动,通过浏览器 WebSocket 交互"),
|
|
715
701
|
web_host: str = typer.Option("127.0.0.1", "--web-host", help="Web 服务主机"),
|
|
716
702
|
web_port: int = typer.Option(8765, "--web-port", help="Web 服务端口"),
|
|
703
|
+
web_launch_cmd: Optional[str] = typer.Option(
|
|
704
|
+
None,
|
|
705
|
+
"--web-launch-cmd",
|
|
706
|
+
help="交互式终端启动命令(字符串格式,用空格分隔,如: --web-launch-cmd 'jca --task \"xxx\"')",
|
|
707
|
+
),
|
|
717
708
|
stop: bool = typer.Option(False, "--stop", help="停止后台 Web 服务(需与 --web 一起使用)"),
|
|
718
709
|
) -> None:
|
|
719
710
|
"""Jarvis AI assistant command-line interface."""
|
|
@@ -748,10 +739,7 @@ def run_cli(
|
|
|
748
739
|
|
|
749
740
|
# 非交互模式要求从命令行传入任务
|
|
750
741
|
if non_interactive and not (task and str(task).strip()):
|
|
751
|
-
|
|
752
|
-
"非交互模式已启用:必须使用 --task 传入任务内容,因多行输入不可用。",
|
|
753
|
-
OutputType.ERROR,
|
|
754
|
-
)
|
|
742
|
+
print("❌ 非交互模式已启用:必须使用 --task 传入任务内容,因多行输入不可用。")
|
|
755
743
|
raise typer.Exit(code=2)
|
|
756
744
|
|
|
757
745
|
# 处理数据备份
|
|
@@ -811,10 +799,10 @@ def run_cli(
|
|
|
811
799
|
candidate_pid = int(ln.strip())
|
|
812
800
|
try:
|
|
813
801
|
os.kill(candidate_pid, signal.SIGTERM)
|
|
814
|
-
|
|
802
|
+
print(f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。")
|
|
815
803
|
killed_any = True
|
|
816
804
|
except Exception as e:
|
|
817
|
-
|
|
805
|
+
print(f"⚠️ 按端口停止失败: {e}")
|
|
818
806
|
except Exception:
|
|
819
807
|
continue
|
|
820
808
|
except Exception:
|
|
@@ -833,10 +821,10 @@ def run_cli(
|
|
|
833
821
|
candidate_pid = int(pid_str2)
|
|
834
822
|
try:
|
|
835
823
|
os.kill(candidate_pid, signal.SIGTERM)
|
|
836
|
-
|
|
824
|
+
print(f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。")
|
|
837
825
|
killed_any = True
|
|
838
826
|
except Exception as e:
|
|
839
|
-
|
|
827
|
+
print(f"⚠️ 按端口停止失败: {e}")
|
|
840
828
|
break
|
|
841
829
|
except Exception:
|
|
842
830
|
continue
|
|
@@ -853,10 +841,10 @@ def run_cli(
|
|
|
853
841
|
p = int(ptxt)
|
|
854
842
|
try:
|
|
855
843
|
os.kill(p, signal.SIGTERM)
|
|
856
|
-
|
|
844
|
+
print(f"✅ 已停止后台 Web 服务 (PID {p})。")
|
|
857
845
|
killed_any = True
|
|
858
846
|
except Exception as e:
|
|
859
|
-
|
|
847
|
+
print(f"⚠️ 停止 PID {p} 失败: {e}")
|
|
860
848
|
except Exception:
|
|
861
849
|
pass
|
|
862
850
|
try:
|
|
@@ -866,7 +854,7 @@ def run_cli(
|
|
|
866
854
|
except Exception:
|
|
867
855
|
pass
|
|
868
856
|
if not killed_any:
|
|
869
|
-
|
|
857
|
+
print("⚠️ 未找到后台 Web 服务的 PID 文件,可能未启动或已停止。")
|
|
870
858
|
return
|
|
871
859
|
# 优先使用 PID 文件中的 PID
|
|
872
860
|
try:
|
|
@@ -878,10 +866,10 @@ def run_cli(
|
|
|
878
866
|
if pid > 0:
|
|
879
867
|
try:
|
|
880
868
|
os.kill(pid, signal.SIGTERM)
|
|
881
|
-
|
|
869
|
+
print(f"✅ 已向后台 Web 服务发送停止信号 (PID {pid})。")
|
|
882
870
|
killed = True
|
|
883
871
|
except Exception as e:
|
|
884
|
-
|
|
872
|
+
print(f"⚠️ 发送停止信号失败或进程不存在: {e}")
|
|
885
873
|
if not killed:
|
|
886
874
|
# 无 PID 文件或停止失败时,尝试按端口查找进程
|
|
887
875
|
candidate_pid = 0
|
|
@@ -921,10 +909,10 @@ def run_cli(
|
|
|
921
909
|
if candidate_pid:
|
|
922
910
|
try:
|
|
923
911
|
os.kill(candidate_pid, signal.SIGTERM)
|
|
924
|
-
|
|
912
|
+
print(f"✅ 已按端口停止后台 Web 服务 (PID {candidate_pid})。")
|
|
925
913
|
killed = True
|
|
926
914
|
except Exception as e:
|
|
927
|
-
|
|
915
|
+
print(f"⚠️ 按端口停止失败: {e}")
|
|
928
916
|
# 清理可能存在的 PID 文件(两个位置)
|
|
929
917
|
try:
|
|
930
918
|
pidfile.unlink(missing_ok=True) # 家目录位置
|
|
@@ -936,7 +924,7 @@ def run_cli(
|
|
|
936
924
|
except Exception:
|
|
937
925
|
pass
|
|
938
926
|
except Exception as e:
|
|
939
|
-
|
|
927
|
+
print(f"❌ 停止后台 Web 服务失败: {e}")
|
|
940
928
|
finally:
|
|
941
929
|
return
|
|
942
930
|
# 后台启动:父进程拉起子进程并记录 PID
|
|
@@ -970,6 +958,8 @@ def run_cli(
|
|
|
970
958
|
args += ["-D"]
|
|
971
959
|
if non_interactive:
|
|
972
960
|
args += ["-n"]
|
|
961
|
+
if web_launch_cmd:
|
|
962
|
+
args += ["--web-launch-cmd", str(web_launch_cmd)]
|
|
973
963
|
env = os.environ.copy()
|
|
974
964
|
env["JARVIS_WEB_DAEMON"] = "1"
|
|
975
965
|
# 启动子进程(后台运行)
|
|
@@ -990,24 +980,23 @@ def run_cli(
|
|
|
990
980
|
pidfile.write_text(str(proc.pid), encoding="utf-8")
|
|
991
981
|
except Exception:
|
|
992
982
|
pass
|
|
993
|
-
|
|
994
|
-
f"Web 服务已在后台启动 (PID {proc.pid}),地址: http://{web_host}:{web_port}",
|
|
995
|
-
OutputType.SUCCESS,
|
|
996
|
-
)
|
|
983
|
+
print(f"✅ Web 服务已在后台启动 (PID {proc.pid}),地址: http://{web_host}:{web_port}")
|
|
997
984
|
except Exception as e:
|
|
998
|
-
|
|
985
|
+
print(f"❌ 后台启动 Web 服务失败: {e}")
|
|
999
986
|
raise typer.Exit(code=1)
|
|
1000
987
|
return
|
|
1001
988
|
|
|
1002
989
|
# 在初始化环境前检测Git仓库,并可选择自动切换到代码开发模式(jca)
|
|
1003
|
-
|
|
990
|
+
# 如果指定了 -T/--task 参数,跳过切换提示
|
|
991
|
+
if not non_interactive and not task:
|
|
1004
992
|
try_switch_to_jca_if_git_repo(
|
|
1005
993
|
model_group, tool_group, config_file, restore_session, task
|
|
1006
994
|
)
|
|
1007
995
|
|
|
1008
996
|
# 在进入默认通用代理前,列出内置配置供选择(agent/multi_agent/roles)
|
|
1009
997
|
# 非交互模式下跳过内置角色/配置选择
|
|
1010
|
-
|
|
998
|
+
# 如果指定了 -T/--task 参数,跳过配置选择
|
|
999
|
+
if not non_interactive and not task:
|
|
1011
1000
|
handle_builtin_config_selector(model_group, tool_group, config_file, task)
|
|
1012
1001
|
|
|
1013
1002
|
# 初始化环境
|
|
@@ -1051,13 +1040,7 @@ def run_cli(
|
|
|
1051
1040
|
non_interactive=non_interactive,
|
|
1052
1041
|
**extra_kwargs,
|
|
1053
1042
|
)
|
|
1054
|
-
|
|
1055
|
-
# CLI 开关:启用/禁用规划(不依赖 AgentManager 支持,直接设置 Agent 属性)
|
|
1056
|
-
if plan is not None:
|
|
1057
|
-
try:
|
|
1058
|
-
agent.plan = bool(plan)
|
|
1059
|
-
except Exception:
|
|
1060
|
-
pass
|
|
1043
|
+
agent_manager.initialize()
|
|
1061
1044
|
|
|
1062
1045
|
if web:
|
|
1063
1046
|
try:
|
|
@@ -1068,7 +1051,7 @@ def run_cli(
|
|
|
1068
1051
|
try:
|
|
1069
1052
|
import os as _os
|
|
1070
1053
|
_os.environ["COLUMNS"] = "200"
|
|
1071
|
-
# 尝试固定全局 Console
|
|
1054
|
+
# 尝试固定全局 Console 的宽度
|
|
1072
1055
|
try:
|
|
1073
1056
|
from jarvis.jarvis_utils.globals import console as _console
|
|
1074
1057
|
try:
|
|
@@ -1087,45 +1070,77 @@ def run_cli(
|
|
|
1087
1070
|
enable_web_stdin_redirect()
|
|
1088
1071
|
except Exception:
|
|
1089
1072
|
pass
|
|
1090
|
-
#
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
if
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1073
|
+
# 构建用于交互式终端(PTY)重启的启动命令
|
|
1074
|
+
launch_cmd = None
|
|
1075
|
+
# 优先使用命令行参数指定的启动命令
|
|
1076
|
+
if web_launch_cmd and web_launch_cmd.strip():
|
|
1077
|
+
# 解析字符串命令(支持引号)
|
|
1078
|
+
try:
|
|
1079
|
+
import shlex
|
|
1080
|
+
launch_cmd = shlex.split(web_launch_cmd.strip())
|
|
1081
|
+
# 调试输出(可选,可以通过环境变量控制)
|
|
1082
|
+
if os.environ.get("JARVIS_DEBUG_WEB_LAUNCH_CMD") == "1":
|
|
1083
|
+
print(f"🔍 解析后的启动命令: {launch_cmd}")
|
|
1084
|
+
except Exception:
|
|
1085
|
+
# 如果解析失败,使用简单的空格分割
|
|
1086
|
+
launch_cmd = web_launch_cmd.strip().split()
|
|
1087
|
+
if os.environ.get("JARVIS_DEBUG_WEB_LAUNCH_CMD") == "1":
|
|
1088
|
+
print(f"🔍 使用简单分割的启动命令: {launch_cmd}")
|
|
1089
|
+
else:
|
|
1090
|
+
# 如果没有指定,则自动构建(移除 web 相关参数)
|
|
1091
|
+
try:
|
|
1092
|
+
import sys as _sys
|
|
1093
|
+
import os as _os
|
|
1094
|
+
_argv = list(_sys.argv)
|
|
1095
|
+
# 去掉程序名(argv[0]),并过滤 --web 相关参数
|
|
1096
|
+
filtered = []
|
|
1097
|
+
i = 1
|
|
1098
|
+
while i < len(_argv):
|
|
1099
|
+
a = _argv[i]
|
|
1100
|
+
if a == "--web" or a.startswith("--web="):
|
|
1101
|
+
i += 1
|
|
1102
|
+
continue
|
|
1103
|
+
if a == "--web-host":
|
|
1104
|
+
i += 2
|
|
1105
|
+
continue
|
|
1106
|
+
if a.startswith("--web-host="):
|
|
1107
|
+
i += 1
|
|
1108
|
+
continue
|
|
1109
|
+
if a == "--web-port":
|
|
1110
|
+
i += 2
|
|
1111
|
+
continue
|
|
1112
|
+
if a.startswith("--web-port="):
|
|
1113
|
+
i += 1
|
|
1114
|
+
continue
|
|
1115
|
+
if a == "--web-launch-cmd":
|
|
1116
|
+
# 跳过 --web-launch-cmd 及其值
|
|
1117
|
+
i += 2
|
|
1118
|
+
continue
|
|
1119
|
+
if a.startswith("--web-launch-cmd="):
|
|
1120
|
+
i += 1
|
|
1121
|
+
continue
|
|
1122
|
+
filtered.append(a)
|
|
1114
1123
|
i += 1
|
|
1115
|
-
|
|
1116
|
-
filtered
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1124
|
+
# 使用 jvs 命令作为可执行文件,保留其余业务参数
|
|
1125
|
+
launch_cmd = ["jvs"] + filtered
|
|
1126
|
+
except Exception:
|
|
1127
|
+
pass
|
|
1128
|
+
|
|
1129
|
+
# 同时写入环境变量作为备选(向后兼容)
|
|
1130
|
+
if launch_cmd:
|
|
1131
|
+
try:
|
|
1132
|
+
import os as _os
|
|
1133
|
+
import json as _json
|
|
1134
|
+
_os.environ["JARVIS_WEB_LAUNCH_JSON"] = _json.dumps(launch_cmd, ensure_ascii=False)
|
|
1135
|
+
except Exception:
|
|
1136
|
+
pass
|
|
1137
|
+
|
|
1138
|
+
print("ℹ️ 以 Web 模式启动,请在浏览器中打开提供的地址进行交互。")
|
|
1139
|
+
# 启动 Web 服务(阻塞调用),传入启动命令
|
|
1140
|
+
start_web_server(agent_manager, host=web_host, port=web_port, launch_command=launch_cmd)
|
|
1126
1141
|
return
|
|
1127
1142
|
except Exception as e:
|
|
1128
|
-
|
|
1143
|
+
print(f"❌ Web 模式启动失败: {e}")
|
|
1129
1144
|
raise typer.Exit(code=1)
|
|
1130
1145
|
|
|
1131
1146
|
# 默认 CLI 模式:运行任务(可能来自 --task 或交互输入)
|
|
@@ -1133,7 +1148,7 @@ def run_cli(
|
|
|
1133
1148
|
except typer.Exit:
|
|
1134
1149
|
raise
|
|
1135
1150
|
except Exception as err: # pylint: disable=broad-except
|
|
1136
|
-
|
|
1151
|
+
print(f"❌ 初始化错误: {str(err)}")
|
|
1137
1152
|
raise typer.Exit(code=1)
|
|
1138
1153
|
|
|
1139
1154
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Language extractors for file context handler.
|
|
3
|
+
|
|
4
|
+
This module automatically registers all language extractors.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Import all language extractors to trigger registration
|
|
8
|
+
try:
|
|
9
|
+
from .python_extractor import register_python_extractor
|
|
10
|
+
register_python_extractor()
|
|
11
|
+
except (ImportError, Exception):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from .rust_extractor import register_rust_extractor
|
|
16
|
+
register_rust_extractor()
|
|
17
|
+
except (ImportError, Exception):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
from .go_extractor import register_go_extractor
|
|
22
|
+
register_go_extractor()
|
|
23
|
+
except (ImportError, Exception):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
from .c_extractor import register_c_extractor
|
|
28
|
+
register_c_extractor()
|
|
29
|
+
except (ImportError, Exception):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
from .cpp_extractor import register_cpp_extractor
|
|
34
|
+
register_cpp_extractor()
|
|
35
|
+
except (ImportError, Exception):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
from .javascript_extractor import register_javascript_extractor
|
|
40
|
+
register_javascript_extractor()
|
|
41
|
+
except (ImportError, Exception):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
from .typescript_extractor import register_typescript_extractor
|
|
46
|
+
register_typescript_extractor()
|
|
47
|
+
except (ImportError, Exception):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
from .java_extractor import register_java_extractor
|
|
52
|
+
register_java_extractor()
|
|
53
|
+
except (ImportError, Exception):
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
__all__ = []
|
|
57
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""C language symbol extractor."""
|
|
3
|
+
|
|
4
|
+
from typing import Optional, Any
|
|
5
|
+
|
|
6
|
+
from jarvis.jarvis_agent.file_context_handler import register_language_extractor
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def create_c_extractor() -> Optional[Any]:
|
|
10
|
+
"""Create C symbol extractor using tree-sitter."""
|
|
11
|
+
try:
|
|
12
|
+
from jarvis.jarvis_code_agent.code_analyzer.languages.c_cpp_language import CSymbolExtractor
|
|
13
|
+
return CSymbolExtractor()
|
|
14
|
+
except (ImportError, RuntimeError, Exception):
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def register_c_extractor() -> None:
|
|
19
|
+
"""Register C extractor for .c and .h files."""
|
|
20
|
+
register_language_extractor(['.c', '.h'], create_c_extractor)
|
|
21
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""C++ language symbol extractor."""
|
|
3
|
+
|
|
4
|
+
from typing import Optional, Any
|
|
5
|
+
|
|
6
|
+
from jarvis.jarvis_agent.file_context_handler import register_language_extractor
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def create_cpp_extractor() -> Optional[Any]:
|
|
10
|
+
"""Create C++ symbol extractor using tree-sitter."""
|
|
11
|
+
try:
|
|
12
|
+
from jarvis.jarvis_code_agent.code_analyzer.languages.c_cpp_language import CppSymbolExtractor
|
|
13
|
+
return CppSymbolExtractor()
|
|
14
|
+
except (ImportError, RuntimeError, Exception):
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def register_cpp_extractor() -> None:
|
|
19
|
+
"""Register C++ extractor for .cpp, .cc, .cxx, .hpp, .hxx files."""
|
|
20
|
+
register_language_extractor(['.cpp', '.cc', '.cxx', '.hpp', '.hxx'], create_cpp_extractor)
|
|
21
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Go language symbol extractor."""
|
|
3
|
+
|
|
4
|
+
from typing import Optional, Any
|
|
5
|
+
|
|
6
|
+
from jarvis.jarvis_agent.file_context_handler import register_language_extractor
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def create_go_extractor() -> Optional[Any]:
|
|
10
|
+
"""Create Go symbol extractor using tree-sitter."""
|
|
11
|
+
try:
|
|
12
|
+
from jarvis.jarvis_code_agent.code_analyzer.languages.go_language import GoSymbolExtractor
|
|
13
|
+
return GoSymbolExtractor()
|
|
14
|
+
except (ImportError, RuntimeError, Exception):
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def register_go_extractor() -> None:
|
|
19
|
+
"""Register Go extractor for .go files."""
|
|
20
|
+
register_language_extractor('.go', create_go_extractor)
|
|
21
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Java language symbol extractor."""
|
|
3
|
+
|
|
4
|
+
from typing import Optional, Any
|
|
5
|
+
|
|
6
|
+
from jarvis.jarvis_agent.file_context_handler import register_language_extractor
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def create_java_extractor() -> Optional[Any]:
|
|
10
|
+
"""Create Java symbol extractor using tree-sitter."""
|
|
11
|
+
try:
|
|
12
|
+
from jarvis.jarvis_code_agent.code_analyzer.languages.java_language import JavaSymbolExtractor
|
|
13
|
+
return JavaSymbolExtractor()
|
|
14
|
+
except (ImportError, RuntimeError, Exception):
|
|
15
|
+
# 如果 code_analyzer 中没有 Java 支持,尝试直接使用 tree-sitter
|
|
16
|
+
try:
|
|
17
|
+
from tree_sitter import Language, Parser
|
|
18
|
+
import tree_sitter_java
|
|
19
|
+
from jarvis.jarvis_code_agent.code_analyzer.symbol_extractor import Symbol
|
|
20
|
+
|
|
21
|
+
JAVA_LANGUAGE = tree_sitter_java.language()
|
|
22
|
+
JAVA_SYMBOL_QUERY = """
|
|
23
|
+
(method_declaration
|
|
24
|
+
name: (identifier) @method.name)
|
|
25
|
+
|
|
26
|
+
(class_declaration
|
|
27
|
+
name: (identifier) @class.name)
|
|
28
|
+
|
|
29
|
+
(interface_declaration
|
|
30
|
+
name: (identifier) @interface.name)
|
|
31
|
+
|
|
32
|
+
(field_declaration
|
|
33
|
+
(variable_declarator
|
|
34
|
+
name: (identifier) @field.name))
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
class JavaSymbolExtractor:
|
|
38
|
+
def __init__(self):
|
|
39
|
+
# 如果传入的是 PyCapsule,需要转换为 Language 对象
|
|
40
|
+
if not isinstance(JAVA_LANGUAGE, Language):
|
|
41
|
+
self.language = Language(JAVA_LANGUAGE)
|
|
42
|
+
else:
|
|
43
|
+
self.language = JAVA_LANGUAGE
|
|
44
|
+
self.parser = Parser()
|
|
45
|
+
# 使用 language 属性而不是 set_language 方法
|
|
46
|
+
self.parser.language = self.language
|
|
47
|
+
self.symbol_query = JAVA_SYMBOL_QUERY
|
|
48
|
+
|
|
49
|
+
def extract_symbols(self, file_path: str, content: str) -> list:
|
|
50
|
+
try:
|
|
51
|
+
tree = self.parser.parse(bytes(content, "utf8"))
|
|
52
|
+
query = self.language.query(self.symbol_query)
|
|
53
|
+
captures = query.captures(tree.root_node)
|
|
54
|
+
|
|
55
|
+
symbols = []
|
|
56
|
+
for node, name in captures:
|
|
57
|
+
kind_map = {
|
|
58
|
+
"method.name": "method",
|
|
59
|
+
"class.name": "class",
|
|
60
|
+
"interface.name": "interface",
|
|
61
|
+
"field.name": "field",
|
|
62
|
+
}
|
|
63
|
+
symbol_kind = kind_map.get(name)
|
|
64
|
+
if symbol_kind:
|
|
65
|
+
symbols.append(Symbol(
|
|
66
|
+
name=node.text.decode('utf8'),
|
|
67
|
+
kind=symbol_kind,
|
|
68
|
+
file_path=file_path,
|
|
69
|
+
line_start=node.start_point[0] + 1,
|
|
70
|
+
line_end=node.end_point[0] + 1,
|
|
71
|
+
))
|
|
72
|
+
return symbols
|
|
73
|
+
except Exception:
|
|
74
|
+
return []
|
|
75
|
+
|
|
76
|
+
return JavaSymbolExtractor()
|
|
77
|
+
except (ImportError, Exception):
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def register_java_extractor() -> None:
|
|
82
|
+
"""Register Java extractor for .java files."""
|
|
83
|
+
register_language_extractor('.java', create_java_extractor)
|
|
84
|
+
|