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_sec/workflow.py
CHANGED
|
@@ -16,14 +16,18 @@ Jarvis 安全分析套件 —— Workflow(含可复现直扫基线)
|
|
|
16
16
|
|
|
17
17
|
from dataclasses import asdict
|
|
18
18
|
from pathlib import Path
|
|
19
|
-
from typing import Any
|
|
20
|
-
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
-
from
|
|
19
|
+
from typing import Any
|
|
20
|
+
from typing import Dict
|
|
21
|
+
from typing import Iterable
|
|
22
|
+
from typing import List
|
|
23
|
+
from typing import Optional
|
|
24
|
+
from typing import cast
|
|
25
|
+
|
|
26
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
27
|
+
from jarvis.jarvis_sec.checkers import analyze_c_files
|
|
28
|
+
from jarvis.jarvis_sec.checkers import analyze_rust_files
|
|
24
29
|
from jarvis.jarvis_sec.types import Issue
|
|
25
30
|
|
|
26
|
-
|
|
27
31
|
# ---------------------------
|
|
28
32
|
# 数据结构
|
|
29
33
|
# ---------------------------
|
|
@@ -50,7 +54,57 @@ def _iter_source_files(
|
|
|
50
54
|
return
|
|
51
55
|
|
|
52
56
|
exts = set((languages or ["c", "cpp", "h", "hpp", "rs"]))
|
|
53
|
-
excludes = set(
|
|
57
|
+
excludes = set(
|
|
58
|
+
exclude_dirs
|
|
59
|
+
or [
|
|
60
|
+
".git",
|
|
61
|
+
"build",
|
|
62
|
+
"out",
|
|
63
|
+
"target",
|
|
64
|
+
"dist",
|
|
65
|
+
"bin",
|
|
66
|
+
"obj",
|
|
67
|
+
"third_party",
|
|
68
|
+
"vendor",
|
|
69
|
+
"deps",
|
|
70
|
+
"dependencies",
|
|
71
|
+
"libs",
|
|
72
|
+
"libraries",
|
|
73
|
+
"external",
|
|
74
|
+
"node_modules",
|
|
75
|
+
"test",
|
|
76
|
+
"tests",
|
|
77
|
+
"__tests__",
|
|
78
|
+
"spec",
|
|
79
|
+
"testsuite",
|
|
80
|
+
"testdata",
|
|
81
|
+
"benchmark",
|
|
82
|
+
"benchmarks",
|
|
83
|
+
"perf",
|
|
84
|
+
"performance",
|
|
85
|
+
"bench",
|
|
86
|
+
"benches",
|
|
87
|
+
"profiling",
|
|
88
|
+
"profiler",
|
|
89
|
+
"example",
|
|
90
|
+
"examples",
|
|
91
|
+
"tmp",
|
|
92
|
+
"temp",
|
|
93
|
+
"cache",
|
|
94
|
+
".cache",
|
|
95
|
+
"docs",
|
|
96
|
+
"doc",
|
|
97
|
+
"documentation",
|
|
98
|
+
"generated",
|
|
99
|
+
"gen",
|
|
100
|
+
"mocks",
|
|
101
|
+
"fixtures",
|
|
102
|
+
"samples",
|
|
103
|
+
"sample",
|
|
104
|
+
"playground",
|
|
105
|
+
"sandbox",
|
|
106
|
+
]
|
|
107
|
+
)
|
|
54
108
|
|
|
55
109
|
for p in entry.rglob("*"):
|
|
56
110
|
if not p.is_file():
|
|
@@ -69,11 +123,11 @@ def _iter_source_files(
|
|
|
69
123
|
yield p.relative_to(entry)
|
|
70
124
|
|
|
71
125
|
|
|
72
|
-
|
|
73
126
|
# ---------------------------
|
|
74
127
|
# 汇总与报告
|
|
75
128
|
# ---------------------------
|
|
76
129
|
|
|
130
|
+
|
|
77
131
|
def direct_scan(
|
|
78
132
|
entry_path: str,
|
|
79
133
|
languages: Optional[List[str]] = None,
|
|
@@ -85,9 +139,56 @@ def direct_scan(
|
|
|
85
139
|
"""
|
|
86
140
|
base = Path(entry_path).resolve()
|
|
87
141
|
# 计算实际使用的排除目录列表
|
|
88
|
-
default_excludes = [
|
|
142
|
+
default_excludes = [
|
|
143
|
+
".git",
|
|
144
|
+
"build",
|
|
145
|
+
"out",
|
|
146
|
+
"target",
|
|
147
|
+
"dist",
|
|
148
|
+
"bin",
|
|
149
|
+
"obj",
|
|
150
|
+
"third_party",
|
|
151
|
+
"vendor",
|
|
152
|
+
"deps",
|
|
153
|
+
"dependencies",
|
|
154
|
+
"libs",
|
|
155
|
+
"libraries",
|
|
156
|
+
"external",
|
|
157
|
+
"node_modules",
|
|
158
|
+
"test",
|
|
159
|
+
"tests",
|
|
160
|
+
"__tests__",
|
|
161
|
+
"spec",
|
|
162
|
+
"testsuite",
|
|
163
|
+
"testdata",
|
|
164
|
+
"benchmark",
|
|
165
|
+
"benchmarks",
|
|
166
|
+
"perf",
|
|
167
|
+
"performance",
|
|
168
|
+
"bench",
|
|
169
|
+
"benches",
|
|
170
|
+
"profiling",
|
|
171
|
+
"profiler",
|
|
172
|
+
"example",
|
|
173
|
+
"examples",
|
|
174
|
+
"tmp",
|
|
175
|
+
"temp",
|
|
176
|
+
"cache",
|
|
177
|
+
".cache",
|
|
178
|
+
"docs",
|
|
179
|
+
"doc",
|
|
180
|
+
"documentation",
|
|
181
|
+
"generated",
|
|
182
|
+
"gen",
|
|
183
|
+
"mocks",
|
|
184
|
+
"fixtures",
|
|
185
|
+
"samples",
|
|
186
|
+
"sample",
|
|
187
|
+
"playground",
|
|
188
|
+
"sandbox",
|
|
189
|
+
]
|
|
89
190
|
actual_excludes = exclude_dirs if exclude_dirs is not None else default_excludes
|
|
90
|
-
|
|
191
|
+
|
|
91
192
|
# 检查代码库中实际存在的排除目录
|
|
92
193
|
excludes_set = set(actual_excludes)
|
|
93
194
|
actual_excluded_dirs = []
|
|
@@ -96,14 +197,16 @@ def direct_scan(
|
|
|
96
197
|
rel_path = item.relative_to(base)
|
|
97
198
|
if str(rel_path) not in actual_excluded_dirs:
|
|
98
199
|
actual_excluded_dirs.append(str(rel_path))
|
|
99
|
-
|
|
200
|
+
|
|
100
201
|
if actual_excluded_dirs:
|
|
101
|
-
|
|
202
|
+
PrettyOutput.auto_print("[jarvis-sec] 实际排除的目录:")
|
|
102
203
|
for dir_path in sorted(actual_excluded_dirs):
|
|
103
|
-
|
|
204
|
+
PrettyOutput.auto_print(f" - {dir_path}")
|
|
104
205
|
else:
|
|
105
|
-
|
|
106
|
-
|
|
206
|
+
PrettyOutput.auto_print(
|
|
207
|
+
f"[jarvis-sec] 未发现需要排除的目录(配置的排除目录: {', '.join(sorted(actual_excludes))})"
|
|
208
|
+
)
|
|
209
|
+
|
|
107
210
|
files = list(_iter_source_files(entry_path, languages, exclude_dirs))
|
|
108
211
|
|
|
109
212
|
# 按语言分组
|
|
@@ -114,10 +217,11 @@ def direct_scan(
|
|
|
114
217
|
|
|
115
218
|
# 调用检查器(保持相对路径,基于 base_path 解析)
|
|
116
219
|
issues_c = analyze_c_files(str(base), [str(p) for p in c_files]) if c_files else []
|
|
117
|
-
issues_r =
|
|
220
|
+
issues_r = (
|
|
221
|
+
analyze_rust_files(str(base), [str(p) for p in r_files]) if r_files else []
|
|
222
|
+
)
|
|
118
223
|
issues: List[Issue] = issues_c + issues_r
|
|
119
224
|
|
|
120
|
-
|
|
121
225
|
summary: Dict[str, Any] = {
|
|
122
226
|
"total": len(issues),
|
|
123
227
|
"by_language": {"c/cpp": 0, "rust": 0},
|
|
@@ -135,7 +239,9 @@ def direct_scan(
|
|
|
135
239
|
cat_counts[it.category] = cat_counts.get(it.category, 0) + 1
|
|
136
240
|
file_score[it.file] = file_score.get(it.file, 0) + 1
|
|
137
241
|
# Top 风险文件
|
|
138
|
-
summary["top_risk_files"] = [
|
|
242
|
+
summary["top_risk_files"] = [
|
|
243
|
+
f for f, _ in sorted(file_score.items(), key=lambda x: x[1], reverse=True)[:10]
|
|
244
|
+
]
|
|
139
245
|
|
|
140
246
|
result = {
|
|
141
247
|
"summary": summary,
|
|
@@ -159,7 +265,9 @@ def format_markdown_report(result_json: Dict) -> str:
|
|
|
159
265
|
md.append("")
|
|
160
266
|
md.append("## 统计概览")
|
|
161
267
|
by_lang = s.get("by_language", {})
|
|
162
|
-
md.append(
|
|
268
|
+
md.append(
|
|
269
|
+
f"- 按语言: c/cpp={by_lang.get('c/cpp', 0)}, rust={by_lang.get('rust', 0)}"
|
|
270
|
+
)
|
|
163
271
|
md.append("- 按类别:")
|
|
164
272
|
for k, v in s.get("by_category", {}).items():
|
|
165
273
|
md.append(f" - {k}: {v}")
|
|
@@ -170,7 +278,9 @@ def format_markdown_report(result_json: Dict) -> str:
|
|
|
170
278
|
md.append("")
|
|
171
279
|
md.append("## 详细问题")
|
|
172
280
|
for i, it in enumerate(issues, start=1):
|
|
173
|
-
md.append(
|
|
281
|
+
md.append(
|
|
282
|
+
f"### [{i}] {it.get('file')}:{it.get('line')} ({it.get('language')}, {it.get('category')})"
|
|
283
|
+
)
|
|
174
284
|
md.append(f"- 模式: {it.get('pattern')}")
|
|
175
285
|
md.append(f"- 证据: `{it.get('evidence')}`")
|
|
176
286
|
md.append(f"- 描述: {it.get('description')}")
|
|
@@ -205,6 +315,7 @@ def run_with_agent(
|
|
|
205
315
|
- enable_verification: 是否启用二次验证(默认 True),关闭后分析Agent确认的问题将直接写入报告
|
|
206
316
|
"""
|
|
207
317
|
from jarvis.jarvis_sec import run_security_analysis # 延迟导入,避免循环
|
|
318
|
+
|
|
208
319
|
return run_security_analysis(
|
|
209
320
|
entry_path,
|
|
210
321
|
languages=languages,
|
|
@@ -223,4 +334,4 @@ __all__ = [
|
|
|
223
334
|
"direct_scan",
|
|
224
335
|
"format_markdown_report",
|
|
225
336
|
"run_with_agent",
|
|
226
|
-
]
|
|
337
|
+
]
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
import os
|
|
4
|
-
from typing import Optional
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from typing import Tuple
|
|
5
6
|
|
|
6
7
|
import typer
|
|
7
8
|
|
|
8
9
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
9
|
-
from jarvis.jarvis_utils.config import get_shell_name
|
|
10
|
+
from jarvis.jarvis_utils.config import get_shell_name
|
|
11
|
+
from jarvis.jarvis_utils.config import set_config
|
|
10
12
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
13
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
11
14
|
from jarvis.jarvis_utils.utils import init_env
|
|
12
15
|
|
|
13
16
|
app = typer.Typer(
|
|
@@ -22,7 +25,7 @@ Example:
|
|
|
22
25
|
|
|
23
26
|
def execute_command(command: str, should_run: bool) -> None:
|
|
24
27
|
"""Print command without execution"""
|
|
25
|
-
|
|
28
|
+
PrettyOutput.auto_print(command)
|
|
26
29
|
if should_run:
|
|
27
30
|
os.system(command)
|
|
28
31
|
|
|
@@ -114,7 +117,7 @@ def install_jss_completion(
|
|
|
114
117
|
) -> None:
|
|
115
118
|
"""为指定的shell安装'命令未找到'处理器,实现自然语言命令建议"""
|
|
116
119
|
if shell not in ("fish", "bash", "zsh"):
|
|
117
|
-
|
|
120
|
+
PrettyOutput.auto_print(
|
|
118
121
|
f"❌ 错误: 不支持的shell类型: {shell}, 仅支持fish, bash, zsh"
|
|
119
122
|
)
|
|
120
123
|
raise typer.Exit(code=1)
|
|
@@ -124,7 +127,7 @@ def install_jss_completion(
|
|
|
124
127
|
start_marker, end_marker = _get_markers()
|
|
125
128
|
|
|
126
129
|
if not os.path.exists(config_file):
|
|
127
|
-
|
|
130
|
+
PrettyOutput.auto_print("ℹ️ 未找到 config.fish 文件,将创建新文件")
|
|
128
131
|
os.makedirs(os.path.dirname(config_file), exist_ok=True)
|
|
129
132
|
with open(config_file, "w") as f:
|
|
130
133
|
f.write("")
|
|
@@ -133,7 +136,7 @@ def install_jss_completion(
|
|
|
133
136
|
content = f.read()
|
|
134
137
|
|
|
135
138
|
if start_marker in content:
|
|
136
|
-
|
|
139
|
+
PrettyOutput.auto_print(
|
|
137
140
|
"✅ JSS fish completion 已安装,请执行: source ~/.config/fish/config.fish"
|
|
138
141
|
)
|
|
139
142
|
return
|
|
@@ -155,7 +158,7 @@ end
|
|
|
155
158
|
{end_marker}
|
|
156
159
|
"""
|
|
157
160
|
)
|
|
158
|
-
|
|
161
|
+
PrettyOutput.auto_print(
|
|
159
162
|
"✅ JSS fish completion 已安装,请执行: source ~/.config/fish/config.fish"
|
|
160
163
|
)
|
|
161
164
|
elif shell == "bash":
|
|
@@ -163,7 +166,7 @@ end
|
|
|
163
166
|
start_marker, end_marker = _get_bash_markers()
|
|
164
167
|
|
|
165
168
|
if not os.path.exists(config_file):
|
|
166
|
-
|
|
169
|
+
PrettyOutput.auto_print("ℹ️ 未找到 ~/.bashrc 文件,将创建新文件")
|
|
167
170
|
os.makedirs(os.path.dirname(config_file), exist_ok=True)
|
|
168
171
|
with open(config_file, "w") as f:
|
|
169
172
|
f.write("")
|
|
@@ -172,7 +175,7 @@ end
|
|
|
172
175
|
content = f.read()
|
|
173
176
|
|
|
174
177
|
if start_marker in content:
|
|
175
|
-
|
|
178
|
+
PrettyOutput.auto_print(
|
|
176
179
|
"✅ JSS bash completion 已安装,请执行: source ~/.bashrc"
|
|
177
180
|
)
|
|
178
181
|
return
|
|
@@ -217,7 +220,7 @@ command_not_found_handle() {{
|
|
|
217
220
|
{end_marker}
|
|
218
221
|
"""
|
|
219
222
|
)
|
|
220
|
-
|
|
223
|
+
PrettyOutput.auto_print(
|
|
221
224
|
"✅ JSS bash completion 已安装,请执行: source ~/.bashrc"
|
|
222
225
|
)
|
|
223
226
|
elif shell == "zsh":
|
|
@@ -225,7 +228,7 @@ command_not_found_handle() {{
|
|
|
225
228
|
start_marker, end_marker = _get_zsh_markers()
|
|
226
229
|
|
|
227
230
|
if not os.path.exists(config_file):
|
|
228
|
-
|
|
231
|
+
PrettyOutput.auto_print("ℹ️ 未找到 ~/.zshrc 文件,将创建新文件")
|
|
229
232
|
os.makedirs(os.path.dirname(config_file), exist_ok=True)
|
|
230
233
|
with open(config_file, "w") as f:
|
|
231
234
|
f.write("")
|
|
@@ -234,7 +237,7 @@ command_not_found_handle() {{
|
|
|
234
237
|
content = f.read()
|
|
235
238
|
|
|
236
239
|
if start_marker in content:
|
|
237
|
-
|
|
240
|
+
PrettyOutput.auto_print(
|
|
238
241
|
"✅ JSS zsh completion 已安装,请执行: source ~/.zshrc"
|
|
239
242
|
)
|
|
240
243
|
return
|
|
@@ -283,9 +286,7 @@ command_not_found_handler() {{
|
|
|
283
286
|
{end_marker}
|
|
284
287
|
"""
|
|
285
288
|
)
|
|
286
|
-
|
|
287
|
-
"✅ JSS zsh completion 已安装,请执行: source ~/.zshrc"
|
|
288
|
-
)
|
|
289
|
+
PrettyOutput.auto_print("✅ JSS zsh completion 已安装,请执行: source ~/.zshrc")
|
|
289
290
|
return
|
|
290
291
|
|
|
291
292
|
|
|
@@ -295,7 +296,7 @@ def uninstall_jss_completion(
|
|
|
295
296
|
) -> None:
|
|
296
297
|
"""卸载JSS shell'命令未找到'处理器"""
|
|
297
298
|
if shell not in ("fish", "bash", "zsh"):
|
|
298
|
-
|
|
299
|
+
PrettyOutput.auto_print(
|
|
299
300
|
f"❌ 错误: 不支持的shell类型: {shell}, 仅支持fish, bash, zsh"
|
|
300
301
|
)
|
|
301
302
|
raise typer.Exit(code=1)
|
|
@@ -305,18 +306,14 @@ def uninstall_jss_completion(
|
|
|
305
306
|
start_marker, end_marker = _get_markers()
|
|
306
307
|
|
|
307
308
|
if not os.path.exists(config_file):
|
|
308
|
-
|
|
309
|
-
"ℹ️ 未找到 JSS fish completion 配置,无需卸载"
|
|
310
|
-
)
|
|
309
|
+
PrettyOutput.auto_print("ℹ️ 未找到 JSS fish completion 配置,无需卸载")
|
|
311
310
|
return
|
|
312
311
|
|
|
313
312
|
with open(config_file, "r") as f:
|
|
314
313
|
content = f.read()
|
|
315
314
|
|
|
316
315
|
if start_marker not in content:
|
|
317
|
-
|
|
318
|
-
"ℹ️ 未找到 JSS fish completion 配置,无需卸载"
|
|
319
|
-
)
|
|
316
|
+
PrettyOutput.auto_print("ℹ️ 未找到 JSS fish completion 配置,无需卸载")
|
|
320
317
|
return
|
|
321
318
|
|
|
322
319
|
new_content = content.split(start_marker)[0] + content.split(end_marker)[-1]
|
|
@@ -324,7 +321,7 @@ def uninstall_jss_completion(
|
|
|
324
321
|
with open(config_file, "w") as f:
|
|
325
322
|
f.write(new_content)
|
|
326
323
|
|
|
327
|
-
|
|
324
|
+
PrettyOutput.auto_print(
|
|
328
325
|
"✅ JSS fish completion 已卸载,请执行: source ~/.config/fish/config.fish"
|
|
329
326
|
)
|
|
330
327
|
elif shell == "bash":
|
|
@@ -332,18 +329,14 @@ def uninstall_jss_completion(
|
|
|
332
329
|
start_marker, end_marker = _get_bash_markers()
|
|
333
330
|
|
|
334
331
|
if not os.path.exists(config_file):
|
|
335
|
-
|
|
336
|
-
"ℹ️ 未找到 JSS bash completion 配置,无需卸载"
|
|
337
|
-
)
|
|
332
|
+
PrettyOutput.auto_print("ℹ️ 未找到 JSS bash completion 配置,无需卸载")
|
|
338
333
|
return
|
|
339
334
|
|
|
340
335
|
with open(config_file, "r") as f:
|
|
341
336
|
content = f.read()
|
|
342
337
|
|
|
343
338
|
if start_marker not in content:
|
|
344
|
-
|
|
345
|
-
"ℹ️ 未找到 JSS bash completion 配置,无需卸载"
|
|
346
|
-
)
|
|
339
|
+
PrettyOutput.auto_print("ℹ️ 未找到 JSS bash completion 配置,无需卸载")
|
|
347
340
|
return
|
|
348
341
|
|
|
349
342
|
new_content = content.split(start_marker)[0] + content.split(end_marker)[-1]
|
|
@@ -351,7 +344,7 @@ def uninstall_jss_completion(
|
|
|
351
344
|
with open(config_file, "w") as f:
|
|
352
345
|
f.write(new_content)
|
|
353
346
|
|
|
354
|
-
|
|
347
|
+
PrettyOutput.auto_print(
|
|
355
348
|
"✅ JSS bash completion 已卸载,请执行: source ~/.bashrc"
|
|
356
349
|
)
|
|
357
350
|
elif shell == "zsh":
|
|
@@ -359,18 +352,14 @@ def uninstall_jss_completion(
|
|
|
359
352
|
start_marker, end_marker = _get_zsh_markers()
|
|
360
353
|
|
|
361
354
|
if not os.path.exists(config_file):
|
|
362
|
-
|
|
363
|
-
"ℹ️ 未找到 JSS zsh completion 配置,无需卸载"
|
|
364
|
-
)
|
|
355
|
+
PrettyOutput.auto_print("ℹ️ 未找到 JSS zsh completion 配置,无需卸载")
|
|
365
356
|
return
|
|
366
357
|
|
|
367
358
|
with open(config_file, "r") as f:
|
|
368
359
|
content = f.read()
|
|
369
360
|
|
|
370
361
|
if start_marker not in content:
|
|
371
|
-
|
|
372
|
-
"ℹ️ 未找到 JSS zsh completion 配置,无需卸载"
|
|
373
|
-
)
|
|
362
|
+
PrettyOutput.auto_print("ℹ️ 未找到 JSS zsh completion 配置,无需卸载")
|
|
374
363
|
return
|
|
375
364
|
|
|
376
365
|
new_content = content.split(start_marker)[0] + content.split(end_marker)[-1]
|
|
@@ -378,9 +367,7 @@ def uninstall_jss_completion(
|
|
|
378
367
|
with open(config_file, "w") as f:
|
|
379
368
|
f.write(new_content)
|
|
380
369
|
|
|
381
|
-
|
|
382
|
-
"✅ JSS zsh completion 已卸载,请执行: source ~/.zshrc"
|
|
383
|
-
)
|
|
370
|
+
PrettyOutput.auto_print("✅ JSS zsh completion 已卸载,请执行: source ~/.zshrc")
|
|
384
371
|
|
|
385
372
|
|
|
386
373
|
def process_request(request: str) -> Optional[str]:
|
|
@@ -437,7 +424,7 @@ def process_request(request: str) -> Optional[str]:
|
|
|
437
424
|
def request_command(
|
|
438
425
|
request: Optional[str] = typer.Argument(
|
|
439
426
|
None, help="描述您想要执行的操作(用自然语言描述),如果未提供则从标准输入读取"
|
|
440
|
-
)
|
|
427
|
+
),
|
|
441
428
|
):
|
|
442
429
|
"""描述您想要执行的操作(用自然语言描述)"""
|
|
443
430
|
should_run = False
|
|
@@ -459,7 +446,7 @@ def request_command(
|
|
|
459
446
|
def cli():
|
|
460
447
|
"""Typer application entry point"""
|
|
461
448
|
init_env("")
|
|
462
|
-
set_config("
|
|
449
|
+
set_config("print_prompt", "false")
|
|
463
450
|
app()
|
|
464
451
|
|
|
465
452
|
|
jarvis/jarvis_stats/cli.py
CHANGED
|
@@ -5,17 +5,23 @@
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import builtins
|
|
8
|
-
from datetime import datetime
|
|
9
|
-
from
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from datetime import timedelta
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Dict
|
|
12
|
+
from typing import List
|
|
13
|
+
from typing import Optional
|
|
14
|
+
from typing import Set
|
|
15
|
+
|
|
10
16
|
import typer
|
|
17
|
+
from rich import print as rprint
|
|
11
18
|
from rich.console import Console
|
|
12
19
|
from rich.table import Table
|
|
13
|
-
from rich import print as rprint
|
|
14
|
-
from pathlib import Path
|
|
15
20
|
|
|
16
|
-
from .stats import StatsManager
|
|
17
|
-
from jarvis.jarvis_utils.utils import init_env
|
|
18
21
|
from jarvis.jarvis_utils.config import get_data_dir
|
|
22
|
+
from jarvis.jarvis_utils.utils import init_env
|
|
23
|
+
|
|
24
|
+
from .stats import StatsManager
|
|
19
25
|
|
|
20
26
|
app = typer.Typer(help="Jarvis 统计模块命令行工具")
|
|
21
27
|
console = Console()
|
|
@@ -117,7 +123,6 @@ def show(
|
|
|
117
123
|
|
|
118
124
|
stats.show(
|
|
119
125
|
metric_name=metric,
|
|
120
|
-
|
|
121
126
|
aggregation=aggregation,
|
|
122
127
|
tags=tag_dict if tag_dict else None,
|
|
123
128
|
)
|
|
@@ -198,7 +203,7 @@ def list():
|
|
|
198
203
|
count = len(records)
|
|
199
204
|
|
|
200
205
|
# 收集所有唯一的标签
|
|
201
|
-
all_tags = {}
|
|
206
|
+
all_tags: Dict[str, Set[str]] = {}
|
|
202
207
|
for record in records:
|
|
203
208
|
tags = record.get("tags", {})
|
|
204
209
|
for k, v in tags.items():
|
|
@@ -248,16 +253,13 @@ def clean(
|
|
|
248
253
|
@app.command()
|
|
249
254
|
def export(
|
|
250
255
|
metric: str = typer.Argument(..., help="指标名称"),
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
256
|
tags: Optional[List[str]] = typer.Option(
|
|
255
257
|
None, "--tag", "-t", help="标签过滤,格式: key=value"
|
|
256
258
|
),
|
|
257
259
|
):
|
|
258
260
|
"""导出统计数据"""
|
|
259
|
-
import json
|
|
260
261
|
import csv
|
|
262
|
+
import json
|
|
261
263
|
import sys
|
|
262
264
|
|
|
263
265
|
stats = StatsManager(_get_stats_dir())
|
jarvis/jarvis_stats/stats.py
CHANGED
|
@@ -4,12 +4,19 @@
|
|
|
4
4
|
提供统计数据的增加、查看、分析等功能的主接口
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
|
|
7
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
8
|
+
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from datetime import timedelta
|
|
11
|
+
from typing import Any
|
|
12
|
+
from typing import Dict
|
|
13
|
+
from typing import List
|
|
14
|
+
from typing import Optional
|
|
15
|
+
from typing import Union
|
|
9
16
|
|
|
10
17
|
from jarvis.jarvis_stats.storage import StatsStorage
|
|
11
18
|
from jarvis.jarvis_stats.visualizer import StatsVisualizer
|
|
12
|
-
from jarvis.jarvis_utils.output import OutputType
|
|
19
|
+
from jarvis.jarvis_utils.output import OutputType # 保留用于语法高亮
|
|
13
20
|
|
|
14
21
|
|
|
15
22
|
class StatsManager:
|
|
@@ -191,10 +198,14 @@ class StatsManager:
|
|
|
191
198
|
created_at = info.get("created_at")
|
|
192
199
|
last_updated = info.get("last_updated")
|
|
193
200
|
start_dt = start_time or (
|
|
194
|
-
datetime.fromisoformat(created_at)
|
|
201
|
+
datetime.fromisoformat(created_at)
|
|
202
|
+
if created_at
|
|
203
|
+
else datetime.now()
|
|
195
204
|
)
|
|
196
205
|
end_dt = end_time or (
|
|
197
|
-
datetime.fromisoformat(last_updated)
|
|
206
|
+
datetime.fromisoformat(last_updated)
|
|
207
|
+
if last_updated
|
|
208
|
+
else datetime.now()
|
|
198
209
|
)
|
|
199
210
|
except Exception:
|
|
200
211
|
start_dt = start_time or (datetime.now() - timedelta(days=7))
|
|
@@ -270,10 +281,14 @@ class StatsManager:
|
|
|
270
281
|
created_at = info.get("created_at")
|
|
271
282
|
last_updated = info.get("last_updated")
|
|
272
283
|
start_dt = start_time or (
|
|
273
|
-
datetime.fromisoformat(created_at)
|
|
284
|
+
datetime.fromisoformat(created_at)
|
|
285
|
+
if created_at
|
|
286
|
+
else datetime.now()
|
|
274
287
|
)
|
|
275
288
|
end_dt = end_time or (
|
|
276
|
-
datetime.fromisoformat(last_updated)
|
|
289
|
+
datetime.fromisoformat(last_updated)
|
|
290
|
+
if last_updated
|
|
291
|
+
else datetime.now()
|
|
277
292
|
)
|
|
278
293
|
except Exception:
|
|
279
294
|
start_dt = start_time or (datetime.now() - timedelta(days=7))
|
|
@@ -422,8 +437,6 @@ class StatsManager:
|
|
|
422
437
|
if start_time is None:
|
|
423
438
|
start_time = end_time - timedelta(days=7)
|
|
424
439
|
|
|
425
|
-
|
|
426
|
-
|
|
427
440
|
# 计算时间范围列标题
|
|
428
441
|
if start_time is None or end_time is None:
|
|
429
442
|
period_label = "值"
|
|
@@ -446,7 +459,7 @@ class StatsManager:
|
|
|
446
459
|
displayed_count = 0
|
|
447
460
|
for metric in metrics:
|
|
448
461
|
# 获取该指标的记录(全历史或指定范围)
|
|
449
|
-
if
|
|
462
|
+
if "all_time" in locals() and all_time:
|
|
450
463
|
_start = None
|
|
451
464
|
_end = None
|
|
452
465
|
try:
|
|
@@ -549,9 +562,7 @@ class StatsManager:
|
|
|
549
562
|
)
|
|
550
563
|
|
|
551
564
|
if not aggregated:
|
|
552
|
-
|
|
553
|
-
f"⚠️ 没有找到指标 '{metric_name}' 的数据"
|
|
554
|
-
)
|
|
565
|
+
PrettyOutput.auto_print(f"⚠️ 没有找到指标 '{metric_name}' 的数据")
|
|
555
566
|
return
|
|
556
567
|
|
|
557
568
|
# 获取指标信息
|
|
@@ -588,8 +599,8 @@ class StatsManager:
|
|
|
588
599
|
PrettyOutput.print(chart, OutputType.CODE, lang="text") # 保留用于语法高亮
|
|
589
600
|
|
|
590
601
|
# 显示时间范围
|
|
591
|
-
from rich.panel import Panel
|
|
592
602
|
from rich.console import Console
|
|
603
|
+
from rich.panel import Panel
|
|
593
604
|
|
|
594
605
|
console = Console()
|
|
595
606
|
console.print(
|
|
@@ -681,9 +692,7 @@ class StatsManager:
|
|
|
681
692
|
)
|
|
682
693
|
|
|
683
694
|
if not aggregated:
|
|
684
|
-
|
|
685
|
-
f"⚠️ 没有找到指标 '{metric_name}' 的数据"
|
|
686
|
-
)
|
|
695
|
+
PrettyOutput.auto_print(f"⚠️ 没有找到指标 '{metric_name}' 的数据")
|
|
687
696
|
return
|
|
688
697
|
|
|
689
698
|
# 获取指标信息
|
|
@@ -693,11 +702,11 @@ class StatsManager:
|
|
|
693
702
|
# 显示汇总
|
|
694
703
|
summary = visualizer.show_summary(aggregated, metric_name, unit, tags)
|
|
695
704
|
if summary: # 如果返回了内容才打印(兼容性)
|
|
696
|
-
|
|
705
|
+
PrettyOutput.auto_print(f"ℹ️ {summary}")
|
|
697
706
|
|
|
698
707
|
# 显示时间范围
|
|
699
|
-
from rich.panel import Panel
|
|
700
708
|
from rich.console import Console
|
|
709
|
+
from rich.panel import Panel
|
|
701
710
|
|
|
702
711
|
console = Console()
|
|
703
712
|
console.print(
|