vigil-codeintel 0.1.0__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.
- vigil_codeintel-0.1.0.dist-info/METADATA +780 -0
- vigil_codeintel-0.1.0.dist-info/RECORD +131 -0
- vigil_codeintel-0.1.0.dist-info/WHEEL +5 -0
- vigil_codeintel-0.1.0.dist-info/entry_points.txt +3 -0
- vigil_codeintel-0.1.0.dist-info/licenses/LICENSE +21 -0
- vigil_codeintel-0.1.0.dist-info/top_level.txt +3 -0
- vigil_forensic/__init__.py +224 -0
- vigil_forensic/_git_utils.py +178 -0
- vigil_forensic/_shared.py +510 -0
- vigil_forensic/_stubs.py +156 -0
- vigil_forensic/gate_checks/__init__.py +1 -0
- vigil_forensic/gate_checks/_ast_helpers.py +629 -0
- vigil_forensic/gate_checks/_deployment_detector.py +573 -0
- vigil_forensic/gate_checks/atomic_write_checks.py +1143 -0
- vigil_forensic/gate_checks/authority_checks.py +95 -0
- vigil_forensic/gate_checks/boundary_breach_checks.py +202 -0
- vigil_forensic/gate_checks/broad_except_checks.py +301 -0
- vigil_forensic/gate_checks/broad_except_hidden_sentinel_checks.py +365 -0
- vigil_forensic/gate_checks/common.py +253 -0
- vigil_forensic/gate_checks/config_safety_checks.py +704 -0
- vigil_forensic/gate_checks/config_ssot_checks.py +78 -0
- vigil_forensic/gate_checks/conflict_checks.py +193 -0
- vigil_forensic/gate_checks/context_fallback_checks.py +697 -0
- vigil_forensic/gate_checks/context_health_checks.py +289 -0
- vigil_forensic/gate_checks/contract_shape_drift_checks.py +459 -0
- vigil_forensic/gate_checks/dirty_baseline_check.py +274 -0
- vigil_forensic/gate_checks/duplication_checks.py +387 -0
- vigil_forensic/gate_checks/embedded_string_checks.py +123 -0
- vigil_forensic/gate_checks/empty_output_checks.py +87 -0
- vigil_forensic/gate_checks/encoding_checks.py +847 -0
- vigil_forensic/gate_checks/export_completeness_checks.py +156 -0
- vigil_forensic/gate_checks/fallback_checks.py +41 -0
- vigil_forensic/gate_checks/file_proliferation_checks.py +171 -0
- vigil_forensic/gate_checks/fix_without_test_checks.py +69 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/__init__.py +9 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/_helpers.py +71 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/advanced_checks.py +322 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/core.py +273 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/integrity_checks.py +203 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/quality_checks.py +666 -0
- vigil_forensic/gate_checks/forensic_clusters/__init__.py +193 -0
- vigil_forensic/gate_checks/forensic_clusters/allowlist.py +426 -0
- vigil_forensic/gate_checks/forensic_clusters/allowlist_writer.py +302 -0
- vigil_forensic/gate_checks/forensic_clusters/api_protocol.py +231 -0
- vigil_forensic/gate_checks/forensic_clusters/async_quality.py +1156 -0
- vigil_forensic/gate_checks/forensic_clusters/code_style.py +808 -0
- vigil_forensic/gate_checks/forensic_clusters/core.py +319 -0
- vigil_forensic/gate_checks/forensic_clusters/data_quality.py +763 -0
- vigil_forensic/gate_checks/forensic_clusters/dead_code.py +480 -0
- vigil_forensic/gate_checks/forensic_clusters/edit_mutation.py +842 -0
- vigil_forensic/gate_checks/forensic_clusters/exception_boundary.py +240 -0
- vigil_forensic/gate_checks/forensic_clusters/legacy_debt.py +556 -0
- vigil_forensic/gate_checks/forensic_clusters/static_analysis.py +834 -0
- vigil_forensic/gate_checks/forensic_clusters/structural_quality.py +298 -0
- vigil_forensic/gate_checks/god_object_zones_checks.py +173 -0
- vigil_forensic/gate_checks/hallucination_checks.py +566 -0
- vigil_forensic/gate_checks/hunter_artifact_completeness_check.py +139 -0
- vigil_forensic/gate_checks/implementation_overfit_checks.py +380 -0
- vigil_forensic/gate_checks/import_integrity_checks.py +233 -0
- vigil_forensic/gate_checks/imports_in_function_checks.py +283 -0
- vigil_forensic/gate_checks/ml_checks.py +318 -0
- vigil_forensic/gate_checks/performance_checks.py +106 -0
- vigil_forensic/gate_checks/project_specific_runner.py +691 -0
- vigil_forensic/gate_checks/provider_capability_checks.py +73 -0
- vigil_forensic/gate_checks/refactor_completeness_checks.py +274 -0
- vigil_forensic/gate_checks/reliability_checks.py +389 -0
- vigil_forensic/gate_checks/reporting_checks.py +55 -0
- vigil_forensic/gate_checks/runtime_behavior_checks.py +220 -0
- vigil_forensic/gate_checks/security_injection_checks.py +332 -0
- vigil_forensic/gate_checks/semantic_intent_checks.py +139 -0
- vigil_forensic/gate_checks/size_complexity_checks.py +336 -0
- vigil_forensic/gate_checks/stuck_feature_flag_checks.py +354 -0
- vigil_forensic/gate_checks/syntax_validity_checks.py +217 -0
- vigil_forensic/gate_checks/temporal_freshness_checks.py +79 -0
- vigil_forensic/gate_checks/test_quality_checks.py +946 -0
- vigil_forensic/gate_checks/testing_checks.py +149 -0
- vigil_forensic/gate_checks/toctou_checks.py +367 -0
- vigil_forensic/gate_checks/type_checking_checks.py +316 -0
- vigil_forensic/gate_models.py +392 -0
- vigil_forensic/gate_packs/__init__.py +1 -0
- vigil_forensic/gate_packs/universal.py +179 -0
- vigil_forensic/gate_profile.json +31 -0
- vigil_forensic/gate_registry.py +21 -0
- vigil_forensic/language_profiles.py +219 -0
- vigil_forensic/meta_findings.py +207 -0
- vigil_forensic/self_audit.py +725 -0
- vigil_forensic/source_analysis.py +175 -0
- vigil_mapper/__init__.py +103 -0
- vigil_mapper/_ast_helpers_minimal.py +229 -0
- vigil_mapper/_extract_imports_impl.py +123 -0
- vigil_mapper/_file_count_guard.py +129 -0
- vigil_mapper/_git_utils.py +178 -0
- vigil_mapper/_runtime_ast.py +438 -0
- vigil_mapper/_runtime_dispatch.py +137 -0
- vigil_mapper/_seed_helpers.py +82 -0
- vigil_mapper/authority_builder.py +1102 -0
- vigil_mapper/cli_entry.py +731 -0
- vigil_mapper/conflict_builder.py +818 -0
- vigil_mapper/data_contract_builder.py +446 -0
- vigil_mapper/findings_builder.py +716 -0
- vigil_mapper/fingerprint.py +53 -0
- vigil_mapper/hotspot_builder.py +539 -0
- vigil_mapper/map_common.py +449 -0
- vigil_mapper/map_errors.py +55 -0
- vigil_mapper/map_models.py +431 -0
- vigil_mapper/map_models_ext.py +206 -0
- vigil_mapper/map_models_findings.py +130 -0
- vigil_mapper/map_storage.py +455 -0
- vigil_mapper/parse_cache.py +795 -0
- vigil_mapper/refactor_boundary_builder.py +266 -0
- vigil_mapper/runtime_builder.py +527 -0
- vigil_mapper/runtime_tracer.py +243 -0
- vigil_mapper/runtime_tracer_entry.py +199 -0
- vigil_mapper/semantic_diff.py +71 -0
- vigil_mapper/source_adapters/__init__.py +109 -0
- vigil_mapper/source_adapters/_base.py +264 -0
- vigil_mapper/source_adapters/_ir.py +156 -0
- vigil_mapper/source_adapters/_lexer.py +309 -0
- vigil_mapper/source_adapters/_patterns.py +212 -0
- vigil_mapper/source_adapters/_treesitter.py +182 -0
- vigil_mapper/source_adapters/go.py +553 -0
- vigil_mapper/source_adapters/java.py +541 -0
- vigil_mapper/source_adapters/javascript.py +626 -0
- vigil_mapper/source_adapters/python.py +325 -0
- vigil_mapper/source_adapters/typescript.py +749 -0
- vigil_mapper/structural_builder.py +586 -0
- vigil_mcp/__init__.py +1 -0
- vigil_mcp/_jobs.py +587 -0
- vigil_mcp/_paths.py +93 -0
- vigil_mcp/forensic_server.py +419 -0
- vigil_mcp/map_server.py +452 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
vigil_codeintel-0.1.0.dist-info/licenses/LICENSE,sha256=G2pHFIBvoEe4OpTuMyExwovPm3MztKOENi3Kk-M67gY,1062
|
|
2
|
+
vigil_forensic/__init__.py,sha256=ztEStgYGEcqRg7tEuc6jfZ8zRpxBdUALpqtebQEGyLE,8495
|
|
3
|
+
vigil_forensic/_git_utils.py,sha256=yS7dr3fQj5sLdGs8hvJza8WuEqUhPdT9x5DTRlJQXV8,5572
|
|
4
|
+
vigil_forensic/_shared.py,sha256=IBMC7WQI9XLLApvQZrtsJNZA1_44nYN-ux3QOeLb-xE,17930
|
|
5
|
+
vigil_forensic/_stubs.py,sha256=ssnke9spSeSjy_YI38-BhC1rFHSEMPdOwB9KRrr_K1o,6955
|
|
6
|
+
vigil_forensic/gate_models.py,sha256=pmXN6geOFnNnTD884unZSfkNKs2G8ZWpFcrBrVO-inc,16229
|
|
7
|
+
vigil_forensic/gate_profile.json,sha256=2JUfR3VhXwrbCl2wb1q5PzRXcjXen-DFtevdwFlH3Aw,957
|
|
8
|
+
vigil_forensic/gate_registry.py,sha256=P6whCRbytvFKd0Bb19_p2GHxdOv7wivE_jZALCT7u88,546
|
|
9
|
+
vigil_forensic/language_profiles.py,sha256=Sziyu6ejbEJbQp6Ns3gPwnELLyUYXfa_gjuFnK3gQas,7692
|
|
10
|
+
vigil_forensic/meta_findings.py,sha256=vLkZZC5s4yY9ACG4g04c8dqqucAgXOpJXqp-BdtYsM4,6955
|
|
11
|
+
vigil_forensic/self_audit.py,sha256=7hRXFHTua9iheVIisqMoRMxmiJsAQ7W7fCrnk_gScCU,32738
|
|
12
|
+
vigil_forensic/source_analysis.py,sha256=eHF5XMf8zcf44nd-maLQqX68uvsTEgkg8CAC6qjuBsE,5694
|
|
13
|
+
vigil_forensic/gate_checks/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
14
|
+
vigil_forensic/gate_checks/_ast_helpers.py,sha256=mJOYmh6KVfgLDrwtosiWZvkzuHA8dJXytJBuBWY4wyg,23612
|
|
15
|
+
vigil_forensic/gate_checks/_deployment_detector.py,sha256=UxTiOuC_eJ_cIj030LobQ_OaJmm4q6pjZaHl-4f9Bus,21372
|
|
16
|
+
vigil_forensic/gate_checks/atomic_write_checks.py,sha256=LjLpagkaGRMV8YsehK2W1Eu0Fl2D4ubqJIONra9KRWA,44090
|
|
17
|
+
vigil_forensic/gate_checks/authority_checks.py,sha256=gXQJlQ5-N0_qNgpJgzCWPNaZght96BRJMyFy-F3DyEs,3929
|
|
18
|
+
vigil_forensic/gate_checks/boundary_breach_checks.py,sha256=0i01WU0zoAo8hOkgMN0asYgJWW2XqQ8QliZK1G1nOWI,7638
|
|
19
|
+
vigil_forensic/gate_checks/broad_except_checks.py,sha256=t7ap7sIpOIP52RTsttSaTK1NT00_TzPoQxnfC7Lw3e0,13090
|
|
20
|
+
vigil_forensic/gate_checks/broad_except_hidden_sentinel_checks.py,sha256=vQtGg7nsMoX-sZRLiMGZyv--GZruq13XwnUbJs7Wtg4,14614
|
|
21
|
+
vigil_forensic/gate_checks/common.py,sha256=Iw1MKeDSyuhlgfWLSXEw0omnKJcwBPLWs2-IXrvRMkc,9158
|
|
22
|
+
vigil_forensic/gate_checks/config_safety_checks.py,sha256=MtMmvC4-tOcCAZ5eAFevhp67fcDElPJOTjSS5n4H-iw,31394
|
|
23
|
+
vigil_forensic/gate_checks/config_ssot_checks.py,sha256=73leRSbo0WxQkPRGHLX9TuHDBAMAyYqhhl99l67gPaM,4054
|
|
24
|
+
vigil_forensic/gate_checks/conflict_checks.py,sha256=13aPgHjBLukzpEa4m94z7ePx8sCYEztXqk6SdxgsYug,7566
|
|
25
|
+
vigil_forensic/gate_checks/context_fallback_checks.py,sha256=WYYCwEAYbzQwSCIzt0O9hqX7IJH4DAihd-qAMJYuXiU,29831
|
|
26
|
+
vigil_forensic/gate_checks/context_health_checks.py,sha256=vt6PChyS7EBn3cTktmNlNzdm7P91oSmX3KKXT-jcRaM,12561
|
|
27
|
+
vigil_forensic/gate_checks/contract_shape_drift_checks.py,sha256=Wy4R_J1H8z7SlxSPtiTuQXMshkHJZUMzFyS7tVlQII4,20221
|
|
28
|
+
vigil_forensic/gate_checks/dirty_baseline_check.py,sha256=oGVdrwsLxOFr3gtT0HSo0j-Sxaf90J4cs04pj-4si7s,9848
|
|
29
|
+
vigil_forensic/gate_checks/duplication_checks.py,sha256=3FaOtVAwfbz4yExiA6Cx1yqEel55kSw7612BltkdwQY,19397
|
|
30
|
+
vigil_forensic/gate_checks/embedded_string_checks.py,sha256=docNGY8uLZfrz7FxvqtTj-4N7DgyHlU9Ow3Y8I0J-K4,5762
|
|
31
|
+
vigil_forensic/gate_checks/empty_output_checks.py,sha256=WuALy0UbgLoBnKK588Ussepi-oFcegY5kZyzrfDMSb8,3792
|
|
32
|
+
vigil_forensic/gate_checks/encoding_checks.py,sha256=f-i8sMJmiT3svqDLGPdeJy8eEe4tjc-VRpED_T2zy7E,36926
|
|
33
|
+
vigil_forensic/gate_checks/export_completeness_checks.py,sha256=XSAvko-vx1-6In927kmvKNouYTf27Th4ybV7_ijtUNs,6351
|
|
34
|
+
vigil_forensic/gate_checks/fallback_checks.py,sha256=vHRFnqWr4fIxRSHTU8nO3CGeuoZBzMLg8KFrcfwIjfM,2193
|
|
35
|
+
vigil_forensic/gate_checks/file_proliferation_checks.py,sha256=aP9VHBeAABJjh0BrwQb0XoAEx7IPB_66p2urADamRJY,8405
|
|
36
|
+
vigil_forensic/gate_checks/fix_without_test_checks.py,sha256=RoC3LWCTf9jRsWHrDtj9G1gCGh8a-DoVf933UIYkVec,3154
|
|
37
|
+
vigil_forensic/gate_checks/god_object_zones_checks.py,sha256=t-yjWogWLlljrZlZNUvE-fybOtRHRHhETLi56RqJa7o,5684
|
|
38
|
+
vigil_forensic/gate_checks/hallucination_checks.py,sha256=aey86cBSJEpoYGdX5bhLVLlzEBSR85LkWfB5_72Dd9w,25206
|
|
39
|
+
vigil_forensic/gate_checks/hunter_artifact_completeness_check.py,sha256=MHPGjZHabMVJXGtbHC1pxEbHvZugcasRODRbiiDbjBw,6535
|
|
40
|
+
vigil_forensic/gate_checks/implementation_overfit_checks.py,sha256=R9t0qh7zXiR7k5uvucy1PjNhD7C546JddyzXYHqtIDA,14297
|
|
41
|
+
vigil_forensic/gate_checks/import_integrity_checks.py,sha256=ppnzzA7j89ScLPS_49P3IQNBLW4oZQ1JM3vkKvJQpx4,9894
|
|
42
|
+
vigil_forensic/gate_checks/imports_in_function_checks.py,sha256=BpK96Bg7Supo3xziKPq7VqWXHVqktns3DRLxTs18eM8,11209
|
|
43
|
+
vigil_forensic/gate_checks/ml_checks.py,sha256=vnHzUWZmwSntMN6MfFt6xQoNNdy1DqYiqnCHdZrxqHQ,13025
|
|
44
|
+
vigil_forensic/gate_checks/performance_checks.py,sha256=Ftksl3zrv9h81VoflSMMVjtoC2MqzKl4ZxBSX8OYHUY,4580
|
|
45
|
+
vigil_forensic/gate_checks/project_specific_runner.py,sha256=htTX0RFgvfxz6fbg_qgpByqTjrUQSdUc6HEM4HD2Bc0,27218
|
|
46
|
+
vigil_forensic/gate_checks/provider_capability_checks.py,sha256=GmFkTs6MKgZJP5rYjo6n1OOdx8LfkXfF655blNVxX-4,2876
|
|
47
|
+
vigil_forensic/gate_checks/refactor_completeness_checks.py,sha256=Ec7HiDFp5fOAp2L_bgHKIYU6e_oLv5o-SkjOHBKJtyQ,10832
|
|
48
|
+
vigil_forensic/gate_checks/reliability_checks.py,sha256=TPY9BoUv-jPYTAOBdHezubm8sGahzfZT6L2BqQu8tDk,15981
|
|
49
|
+
vigil_forensic/gate_checks/reporting_checks.py,sha256=c5sBYT0aJ8afzlV47J4P5TBqPhrqb56yIx-ID3iKmlo,2580
|
|
50
|
+
vigil_forensic/gate_checks/runtime_behavior_checks.py,sha256=HNQufbDMMpZOiKBujlmC51B2BKwuwWP5gTDkUL7gzxk,9185
|
|
51
|
+
vigil_forensic/gate_checks/security_injection_checks.py,sha256=-Li5D2Nyq4gN96VotgAgx0eCBmLVN4CCtItq3uZxHm0,13921
|
|
52
|
+
vigil_forensic/gate_checks/semantic_intent_checks.py,sha256=ggZF4Hp5jlOfLtSvuzq5hpSr6_fHjIj6c8jxEgmZHVo,5758
|
|
53
|
+
vigil_forensic/gate_checks/size_complexity_checks.py,sha256=vXKOhQVKCgKD5cphShE2NxfnOZAMHdYNRUmYd8ZyOQk,17085
|
|
54
|
+
vigil_forensic/gate_checks/stuck_feature_flag_checks.py,sha256=XkKbmwizrcrVw1-b8tXB2By5Xc7sAzKo1V9fC2bF15Y,13523
|
|
55
|
+
vigil_forensic/gate_checks/syntax_validity_checks.py,sha256=CkSo4PZ5zk3NBRS82t_hSZASs4fnTIEuFgcnWr527lA,8363
|
|
56
|
+
vigil_forensic/gate_checks/temporal_freshness_checks.py,sha256=luNFPGcuW1SJL4KeGwdZzo4zJecc8DCMfBFoxtJLhGE,3357
|
|
57
|
+
vigil_forensic/gate_checks/test_quality_checks.py,sha256=iOXa1lonFsfp-9REBkcu8iUOwIxsmnu1rdfH6A4zcLM,39904
|
|
58
|
+
vigil_forensic/gate_checks/testing_checks.py,sha256=oOyGE-Eh0RDd949yH0_JAXb6jfNJO0aAHflGHgm4Qgc,7713
|
|
59
|
+
vigil_forensic/gate_checks/toctou_checks.py,sha256=9oqBXkOPuXroUGc-rncW5iZfUCB5ltUYSYXh4j9aVpM,14754
|
|
60
|
+
vigil_forensic/gate_checks/type_checking_checks.py,sha256=yEj20q1mu-sgmIpIhlyh99uErqTizcUX2sp7PGsIR9g,14015
|
|
61
|
+
vigil_forensic/gate_checks/forensic_cluster_runners/__init__.py,sha256=G9V7s3i81VFDtyQ8NclIZe0tZCWVZL4WSQH7UfpD4eE,346
|
|
62
|
+
vigil_forensic/gate_checks/forensic_cluster_runners/_helpers.py,sha256=V8XGLqh8BhWGGsyfMA2sXPiffgof81-XT0852Q3P4UE,3230
|
|
63
|
+
vigil_forensic/gate_checks/forensic_cluster_runners/advanced_checks.py,sha256=w7brafGnfsRqWAKlPLbfP1c3MeVKr62PbQZWJ0VsgZc,11555
|
|
64
|
+
vigil_forensic/gate_checks/forensic_cluster_runners/core.py,sha256=IdVCMKFM8HX-Az--NwlrNtz3Idge0PmqOHp53Emekso,13530
|
|
65
|
+
vigil_forensic/gate_checks/forensic_cluster_runners/integrity_checks.py,sha256=vrd_pt5TJ_T1QFdcASqwl0tV8TStGjtvaqMYI_Z9I_c,7902
|
|
66
|
+
vigil_forensic/gate_checks/forensic_cluster_runners/quality_checks.py,sha256=V3vpIUiNsW_74N7VN2dcyJG8083NiOTZmHnQ98r7EZI,24505
|
|
67
|
+
vigil_forensic/gate_checks/forensic_clusters/__init__.py,sha256=E7nSAEpwa-m4OTBIZZMNpiIWhb9YVYCA-CYfa8_7xro,5311
|
|
68
|
+
vigil_forensic/gate_checks/forensic_clusters/allowlist.py,sha256=8-1i5ZoCwkT2hTx6-01EvXGjQajMglByTXihmh7kDfM,15904
|
|
69
|
+
vigil_forensic/gate_checks/forensic_clusters/allowlist_writer.py,sha256=ZV7dUcGIb-Sj4881KLMUICNxVOPlBTUYqanfIJbeNyQ,11170
|
|
70
|
+
vigil_forensic/gate_checks/forensic_clusters/api_protocol.py,sha256=F0z6RVHQl1YNVXoB0TGPXy9nmU9dlY9R4BjZCKIGEqU,10380
|
|
71
|
+
vigil_forensic/gate_checks/forensic_clusters/async_quality.py,sha256=kFDbxpVe5UzgXzqZrx6RO9ZCokNqcGMiGikG1NFUcOo,49447
|
|
72
|
+
vigil_forensic/gate_checks/forensic_clusters/code_style.py,sha256=2WIT33zmsYU29IeRiiw80BrkwUSjt7KHfhjqZzX949g,34230
|
|
73
|
+
vigil_forensic/gate_checks/forensic_clusters/core.py,sha256=jkNE8xfHoXI-GfLvrJ5t9M05FeGfqPnMNlF1Gtme0Jk,12803
|
|
74
|
+
vigil_forensic/gate_checks/forensic_clusters/data_quality.py,sha256=TqgmY_p1ecW2TE3BwIVI53GrVAgNUJl6QpGVrb8j0es,34952
|
|
75
|
+
vigil_forensic/gate_checks/forensic_clusters/dead_code.py,sha256=2nxQfuDEzvSN1601EM5gNy7LW7XCUPtyWUjw5cueTzg,19895
|
|
76
|
+
vigil_forensic/gate_checks/forensic_clusters/edit_mutation.py,sha256=rDrEr_GsB9BtmANCS6GM-fxQP2zDDqte6uQHtquyEsk,35761
|
|
77
|
+
vigil_forensic/gate_checks/forensic_clusters/exception_boundary.py,sha256=zF_uCIfXdhVg0HuwBS0qD7aroO2qiHh9jzvXQxD2Gqg,11403
|
|
78
|
+
vigil_forensic/gate_checks/forensic_clusters/legacy_debt.py,sha256=UFrErFRRhkT4RmWI47oKXL9InnWBjFspXRcKPxBrKNA,21283
|
|
79
|
+
vigil_forensic/gate_checks/forensic_clusters/static_analysis.py,sha256=qVUSCDDeiEO5eisR1PhQ0DpJbjxV43cYhQQ1yxqiPbY,36931
|
|
80
|
+
vigil_forensic/gate_checks/forensic_clusters/structural_quality.py,sha256=K12qQ6TUcgEeJ4vvieWavuUXmH9Uehd3UbN4dvFIBrI,12972
|
|
81
|
+
vigil_forensic/gate_packs/__init__.py,sha256=19PwrW5hqaOdzEh_b2s-Dx2_c6WHizwT8ya1HavqjAE,36
|
|
82
|
+
vigil_forensic/gate_packs/universal.py,sha256=DyqAffKJTsYucs10ErmRMCvsTldSby-0Z3v4XiG8E-w,11990
|
|
83
|
+
vigil_mapper/__init__.py,sha256=SeinM7MVoZWqse33Ek5eJVhHhaooLZAwL3HmoRNaHMY,3497
|
|
84
|
+
vigil_mapper/_ast_helpers_minimal.py,sha256=wT2eYRia1E0ZRbY832ysWcBB3f-jGzBAqtyINXF-CEg,7854
|
|
85
|
+
vigil_mapper/_extract_imports_impl.py,sha256=-MhkutstDl3BZZWL947KfuSXrBMT7Uv2b0qQAeCmJSk,4868
|
|
86
|
+
vigil_mapper/_file_count_guard.py,sha256=Hdm11ukWBJKwkH_akEMlwvk7Gz4-rQJs54Dnjf6ynho,4727
|
|
87
|
+
vigil_mapper/_git_utils.py,sha256=yS7dr3fQj5sLdGs8hvJza8WuEqUhPdT9x5DTRlJQXV8,5572
|
|
88
|
+
vigil_mapper/_runtime_ast.py,sha256=NbeLPotsmUGOHiiVtsa3vMrIA-ZYuMl5bOGfgQFyBTg,16809
|
|
89
|
+
vigil_mapper/_runtime_dispatch.py,sha256=wtq6ynMLsexxxhL3BOev4EVW1fZi7GEBFFHJ-PGOsGo,6089
|
|
90
|
+
vigil_mapper/_seed_helpers.py,sha256=9qnPLPbVA-_ocDGP0nT1sTUptGAtSvmh5Rh3rINJn-s,2968
|
|
91
|
+
vigil_mapper/authority_builder.py,sha256=KOTcW8ZQtTOICIu804lUp-jDntfsBcbhd8jq39J82RQ,47207
|
|
92
|
+
vigil_mapper/cli_entry.py,sha256=XUhn2gCMddQX6qfg9D447qgqQbk4GjFX7ReO1AjHFo8,29330
|
|
93
|
+
vigil_mapper/conflict_builder.py,sha256=WumSNeh16HDVgwMfr1vByYM_aVrPApQ2leYojS20ALk,29131
|
|
94
|
+
vigil_mapper/data_contract_builder.py,sha256=ZLnKNDIa3N7vatEUiGgOfTOZr5W1e_uShn-zMqp3vsE,17238
|
|
95
|
+
vigil_mapper/findings_builder.py,sha256=pbcca_Qnqb5w2luj8VltELANfddjB5P8y6ymuuF-_JM,27226
|
|
96
|
+
vigil_mapper/fingerprint.py,sha256=K5X8GPcecpZs9KAr7F-ys-S9gna-vanfN-AUZzvBYR8,1732
|
|
97
|
+
vigil_mapper/hotspot_builder.py,sha256=xnPyEZrXx34NhkjKYtbRJrFz-aTqm4kc6jQ542IEShs,19977
|
|
98
|
+
vigil_mapper/map_common.py,sha256=NG4liaJsvSGQ3NqjhUncw7N65qJl8N4jz0JvcArJJsg,16097
|
|
99
|
+
vigil_mapper/map_errors.py,sha256=y0gC45SLfwvDJBvsbHQbfBAsln8RJGXQtn2TJ9WxsBE,1395
|
|
100
|
+
vigil_mapper/map_models.py,sha256=kEdfY3EQ2lyUxUVUAitDjWRceue1pD-mInAktN45yig,17269
|
|
101
|
+
vigil_mapper/map_models_ext.py,sha256=-m7w2OY39S6OuQQNUQlnH769Cui68sYgbdAW7aHrLmU,7262
|
|
102
|
+
vigil_mapper/map_models_findings.py,sha256=RqrbFIVlcNQlWOwe7YUftRLJw9azDhJToNh5a6HcYrg,4780
|
|
103
|
+
vigil_mapper/map_storage.py,sha256=Sz3CinNcHlywUtnh7M42psHxDJUB3YLP7HEduD7o9nQ,17565
|
|
104
|
+
vigil_mapper/parse_cache.py,sha256=JfC5TWhFZYenETO9J0A61ZSLoUZIPhjIJGD54dGJU8g,29983
|
|
105
|
+
vigil_mapper/refactor_boundary_builder.py,sha256=n_mBmfxgSsoAtRvsyz2BNIHdm0STQKh7ck0pfWMnIy8,9750
|
|
106
|
+
vigil_mapper/runtime_builder.py,sha256=iXGEt6Quk_pyUb2-cvKT9HviAEbFna8zzPNNLi374tM,20058
|
|
107
|
+
vigil_mapper/runtime_tracer.py,sha256=HvmmfiL-BsNI037NzjN93HD-0hpYOuTzKfJzipjl6cc,8088
|
|
108
|
+
vigil_mapper/runtime_tracer_entry.py,sha256=y8nUf7rXJFOXMs08hsAhJnrhvDhVO3OQOBMGo3Xdgzw,7284
|
|
109
|
+
vigil_mapper/semantic_diff.py,sha256=ImGQH8cmPUvNHVeIYQG0I8xAx334C76rTUpSeoozYns,2799
|
|
110
|
+
vigil_mapper/structural_builder.py,sha256=FWxOYhO3IfNGkwkFyy5PBuToLslGMAa7UayWQT_eiV8,22260
|
|
111
|
+
vigil_mapper/source_adapters/__init__.py,sha256=8cfHxkm5-BBXG0jfX2FAKhtFb5WWEfH4PhsNJQHuATI,3695
|
|
112
|
+
vigil_mapper/source_adapters/_base.py,sha256=Dh41x0Uh2nDjlq5Cu2e9qWKxiapCSJjUtBzZW7MODjM,10550
|
|
113
|
+
vigil_mapper/source_adapters/_ir.py,sha256=MjnqMn4CXAZpUX88HdL3ZffNqdWUKy6o0FpTa4rmZHg,5277
|
|
114
|
+
vigil_mapper/source_adapters/_lexer.py,sha256=osWo-5I5piqWN163XPDXgTsGa64Eh7eOspL5TA8o7KU,11057
|
|
115
|
+
vigil_mapper/source_adapters/_patterns.py,sha256=yZC7QyXhQp7lD32Q8He4Ev9Yn__vnqNR3pRID5fpWOs,6692
|
|
116
|
+
vigil_mapper/source_adapters/_treesitter.py,sha256=dsOFj7LKWzUMjgiMe9kqs2ZRQ760dx6YdB71IF-6hLE,5695
|
|
117
|
+
vigil_mapper/source_adapters/go.py,sha256=cJ3-G4hRsZGgBym21pyIoTorViK-LQdtXITo50HPV0E,23504
|
|
118
|
+
vigil_mapper/source_adapters/java.py,sha256=BNLAXeEBv4ad81X4Uab-UxB2Gv1XuzMbuGU24pzX_08,21817
|
|
119
|
+
vigil_mapper/source_adapters/javascript.py,sha256=TpS0J_yAoB2ylZV7LW2Y0TJ1mwTh4cBeLe8PUeG0trU,26497
|
|
120
|
+
vigil_mapper/source_adapters/python.py,sha256=FfU04OtRmqGFr8qssgIh_KXcNQ_9cNsiyg-ijt_BHeg,13050
|
|
121
|
+
vigil_mapper/source_adapters/typescript.py,sha256=SMbLwpkojd2ARF3i1mNG4Kycl-oxrZjfb92VCg-BCUI,31079
|
|
122
|
+
vigil_mcp/__init__.py,sha256=LIk3_JrCxyTC4zv_pVCdahqIJ0lGFzNV7Jl1K80-dSQ,84
|
|
123
|
+
vigil_mcp/_jobs.py,sha256=r2doRMvffcvNKJW4Vpz2f3LP-gjTsNFhLBZ-50vkTPA,23716
|
|
124
|
+
vigil_mcp/_paths.py,sha256=lP-qRiTXr_SdE-f6Jym_wsBJUJoDEGLZ3ZceBRdntIg,3257
|
|
125
|
+
vigil_mcp/forensic_server.py,sha256=UVHbRDL_R0qi7WyMmqWG7craTghy52qoKvZbm-ZzFdU,16152
|
|
126
|
+
vigil_mcp/map_server.py,sha256=IHrM3rO5MGD0hayVJ-tQKyZ-_IebSaRaEjm0u41LOPc,17852
|
|
127
|
+
vigil_codeintel-0.1.0.dist-info/METADATA,sha256=OCGd43cZ2z5Syacs3gzmCUcgtgF1-LiRcPg7UU3WYVc,45607
|
|
128
|
+
vigil_codeintel-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
129
|
+
vigil_codeintel-0.1.0.dist-info/entry_points.txt,sha256=UZ9zWBfDOUC-Girrfq4ANLucwkIXgtgM74pYlpmpYLY,115
|
|
130
|
+
vigil_codeintel-0.1.0.dist-info/top_level.txt,sha256=t29Bu-mTMgwyWNFiPPnW7bOH_y_tLm7mkcHj39EVLPY,38
|
|
131
|
+
vigil_codeintel-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Julio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"""vigil_forensic — standalone static forensic gate package.
|
|
2
|
+
|
|
3
|
+
Public API
|
|
4
|
+
----------
|
|
5
|
+
run_forensic_audit(project_dir, *, gates=None, severity="LOW", all_languages=True) -> dict
|
|
6
|
+
Run static forensic gates on a project directory and return findings as data.
|
|
7
|
+
|
|
8
|
+
Returned dict shape::
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
"exit_code": int, # 0 = clean, 1 = high/critical findings, 2 = error
|
|
12
|
+
"findings": [ # list of finding dicts (filtered by severity)
|
|
13
|
+
{
|
|
14
|
+
"check_id": str,
|
|
15
|
+
"category": str,
|
|
16
|
+
"title": str,
|
|
17
|
+
"severity": str, # "low" | "medium" | "high" | "critical"
|
|
18
|
+
"impact": str,
|
|
19
|
+
"summary": str,
|
|
20
|
+
"recommendation": str,
|
|
21
|
+
"evidence": [{"kind": str, "path": str, "detail": str}],
|
|
22
|
+
"fingerprint": str,
|
|
23
|
+
"confidence": float,
|
|
24
|
+
"applicability": str,
|
|
25
|
+
"analysis_mode": str,
|
|
26
|
+
"applicability_reason": str,
|
|
27
|
+
},
|
|
28
|
+
...
|
|
29
|
+
],
|
|
30
|
+
"meta": {
|
|
31
|
+
"project_dir": str,
|
|
32
|
+
"source_files_scanned": int,
|
|
33
|
+
"gates_attempted": int,
|
|
34
|
+
"gates_succeeded": int,
|
|
35
|
+
"gates_errored": int,
|
|
36
|
+
"total_findings": int,
|
|
37
|
+
"severity_counts": {"low": int, "medium": int, ...},
|
|
38
|
+
"category_counts": {str: int},
|
|
39
|
+
"schema_version": "1.1",
|
|
40
|
+
"gates_skipped": [{"gate_id": str, "reason": str}],
|
|
41
|
+
...
|
|
42
|
+
},
|
|
43
|
+
"errors": [{"check_id": str, "error": str}],
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
Zero imports from BRAIN, SYSTEM, or INTERFACE. May import vigil_mapper
|
|
47
|
+
(sibling standalone package).
|
|
48
|
+
"""
|
|
49
|
+
from __future__ import annotations
|
|
50
|
+
|
|
51
|
+
from pathlib import Path
|
|
52
|
+
from typing import Any, Optional
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def run_forensic_audit(
|
|
56
|
+
project_dir: str | Path,
|
|
57
|
+
*,
|
|
58
|
+
gates: Optional[list[str]] = None,
|
|
59
|
+
severity: str = "LOW",
|
|
60
|
+
all_languages: bool = True,
|
|
61
|
+
max_files: int = 800,
|
|
62
|
+
cancel_event: Optional[Any] = None,
|
|
63
|
+
) -> dict[str, Any]:
|
|
64
|
+
"""Run static forensic gates on *project_dir* and return structured findings.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
project_dir:
|
|
69
|
+
Path to the project root to audit.
|
|
70
|
+
gates:
|
|
71
|
+
Optional list of gate check_ids to run. None means run all applicable
|
|
72
|
+
file-based gates (skipping runtime-only gates as per skip_in_static policy).
|
|
73
|
+
Gates listed in ``<project_dir>/.cortex/disabled_gates.json`` are always
|
|
74
|
+
skipped (reported in ``meta["gates_skipped"]`` with reason
|
|
75
|
+
``"disabled_by_project"``) regardless of this argument.
|
|
76
|
+
severity:
|
|
77
|
+
Minimum severity floor for the returned ``findings``. One of
|
|
78
|
+
"LOW", "MEDIUM", "HIGH", "CRITICAL" (case-insensitive); ordering is
|
|
79
|
+
LOW < MEDIUM < HIGH < CRITICAL. Defaults to "LOW" (all findings).
|
|
80
|
+
Findings below the floor are removed from ``findings``; the ``meta.*``
|
|
81
|
+
counts are computed BEFORE this filter (so they always reflect the full
|
|
82
|
+
finding set), and ``meta["findings_after_severity_filter"]`` records the
|
|
83
|
+
post-filter count when a non-LOW floor is used.
|
|
84
|
+
all_languages:
|
|
85
|
+
Reserved for future use. Currently all source extensions recognized by
|
|
86
|
+
vigil_mapper.source_adapters are included automatically.
|
|
87
|
+
max_files:
|
|
88
|
+
Anti-hang ceiling on the COLLECTED source-file count. Forensic does a
|
|
89
|
+
per-gate AST walk over every file (~0.4 s/file), so on a repo with
|
|
90
|
+
thousands of files a full scan takes hours and effectively hangs. When
|
|
91
|
+
the collected count exceeds ``max_files`` (default 800 ≈ a ~5 min
|
|
92
|
+
ceiling) NO gates run; instead a FAST structured result is returned with
|
|
93
|
+
``meta["skipped_reason"] == "too_many_files"`` plus ``top_subdirs`` and a
|
|
94
|
+
``suggestion`` to narrow scope. Raise ``max_files`` to force a full scan.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
dict with keys: "exit_code", "findings", "meta", "errors".
|
|
99
|
+
Never raises — errors are captured in the returned dict.
|
|
100
|
+
"""
|
|
101
|
+
import traceback
|
|
102
|
+
from vigil_forensic.self_audit import (
|
|
103
|
+
discover_source_files,
|
|
104
|
+
build_synthetic_context,
|
|
105
|
+
run_gates,
|
|
106
|
+
build_json_report,
|
|
107
|
+
filter_findings_by_severity,
|
|
108
|
+
_load_project_disabled_gates,
|
|
109
|
+
_probe_meta_integrity,
|
|
110
|
+
GateOutcome,
|
|
111
|
+
)
|
|
112
|
+
from vigil_forensic.meta_findings import drain_meta_findings
|
|
113
|
+
|
|
114
|
+
project_dir = Path(project_dir).resolve()
|
|
115
|
+
if not project_dir.is_dir():
|
|
116
|
+
return {
|
|
117
|
+
"exit_code": 2,
|
|
118
|
+
"findings": [],
|
|
119
|
+
"meta": {"error": f"project_dir is not a directory: {project_dir}"},
|
|
120
|
+
"errors": [{"check_id": "init", "error": f"Not a directory: {project_dir}"}],
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
gates_filter: Optional[set[str]] = set(gates) if gates else None
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
source_files = discover_source_files(project_dir)
|
|
127
|
+
except Exception as exc:
|
|
128
|
+
return {
|
|
129
|
+
"exit_code": 2,
|
|
130
|
+
"findings": [],
|
|
131
|
+
"meta": {"error": f"file discovery failed: {exc}"},
|
|
132
|
+
"errors": [{"check_id": "discover", "error": traceback.format_exc()}],
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if not source_files:
|
|
136
|
+
return {
|
|
137
|
+
"exit_code": 0,
|
|
138
|
+
"findings": [],
|
|
139
|
+
"meta": {
|
|
140
|
+
"project_dir": str(project_dir),
|
|
141
|
+
"source_files_scanned": 0,
|
|
142
|
+
"gates_attempted": 0,
|
|
143
|
+
"gates_succeeded": 0,
|
|
144
|
+
"gates_errored": 0,
|
|
145
|
+
"total_findings": 0,
|
|
146
|
+
"severity_counts": {},
|
|
147
|
+
"category_counts": {},
|
|
148
|
+
"schema_version": "1.1",
|
|
149
|
+
"gates_skipped": [],
|
|
150
|
+
"gates_skipped_in_static": [],
|
|
151
|
+
"note": "no source files found",
|
|
152
|
+
},
|
|
153
|
+
"errors": [],
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# Anti-hang file-COUNT guard. Forensic walks every file per gate (~0.4 s/file)
|
|
157
|
+
# so thousands of files = hours. When the collected count exceeds max_files we
|
|
158
|
+
# do NOT build context or run gates; we return a FAST structured skip result
|
|
159
|
+
# (just count + group-by-top-subdir) telling the caller to narrow scope.
|
|
160
|
+
if len(source_files) > max_files:
|
|
161
|
+
from vigil_mapper._file_count_guard import build_too_many_files_meta
|
|
162
|
+
|
|
163
|
+
meta = build_too_many_files_meta(
|
|
164
|
+
source_files, max_files, entry_call="start_forensic_audit"
|
|
165
|
+
)
|
|
166
|
+
meta["project_dir"] = str(project_dir)
|
|
167
|
+
return {
|
|
168
|
+
"exit_code": 0,
|
|
169
|
+
"findings": [],
|
|
170
|
+
"meta": meta,
|
|
171
|
+
"errors": [],
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
ctx = build_synthetic_context(project_dir, source_files)
|
|
176
|
+
except Exception as exc:
|
|
177
|
+
return {
|
|
178
|
+
"exit_code": 2,
|
|
179
|
+
"findings": [],
|
|
180
|
+
"meta": {"error": f"context build failed: {exc}"},
|
|
181
|
+
"errors": [{"check_id": "build_context", "error": traceback.format_exc()}],
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
# Per-project gate opt-out: <project_dir>/.cortex/disabled_gates.json.
|
|
185
|
+
# Malformed file → meta finding + empty set (never raises, never silently
|
|
186
|
+
# disables). Loaded here so the meta finding is drained with the rest below.
|
|
187
|
+
disabled_gates = _load_project_disabled_gates(project_dir)
|
|
188
|
+
|
|
189
|
+
outcomes, gates_skipped = run_gates(
|
|
190
|
+
ctx, gates_filter, workers=1, cancel_event=cancel_event,
|
|
191
|
+
disabled_gates=disabled_gates,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Probe audit infrastructure for corrupted artifacts
|
|
195
|
+
_probe_meta_integrity(project_dir)
|
|
196
|
+
meta_findings = drain_meta_findings()
|
|
197
|
+
if meta_findings:
|
|
198
|
+
outcomes.append(GateOutcome(check_id="meta_integrity_probe", ok=True, findings=list(meta_findings)))
|
|
199
|
+
|
|
200
|
+
report = build_json_report(outcomes, project_dir, len(source_files), gates_skipped=gates_skipped)
|
|
201
|
+
|
|
202
|
+
# Apply severity filter to findings list (meta counts are pre-filter)
|
|
203
|
+
min_sev = severity.lower()
|
|
204
|
+
if min_sev != "low":
|
|
205
|
+
filtered = filter_findings_by_severity(report["findings"], min_sev)
|
|
206
|
+
report = dict(report)
|
|
207
|
+
report["findings"] = filtered
|
|
208
|
+
report["meta"] = dict(report["meta"])
|
|
209
|
+
report["meta"]["findings_after_severity_filter"] = len(filtered)
|
|
210
|
+
|
|
211
|
+
# Compute exit code
|
|
212
|
+
sev_counts = report["meta"].get("severity_counts", {})
|
|
213
|
+
critical_or_high = sev_counts.get("critical", 0) + sev_counts.get("high", 0)
|
|
214
|
+
exit_code = 1 if critical_or_high > 0 else 0
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
"exit_code": exit_code,
|
|
218
|
+
"findings": report["findings"],
|
|
219
|
+
"meta": report["meta"],
|
|
220
|
+
"errors": report.get("errors", []),
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
__all__ = ["run_forensic_audit"]
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""Neutral shared git helpers. Depends only on stdlib.
|
|
2
|
+
|
|
3
|
+
Used by map_builder (churn) and gate_checks (diff-based checks).
|
|
4
|
+
Never imports from gate_checks or map_builder (correct dependency direction).
|
|
5
|
+
|
|
6
|
+
Public API:
|
|
7
|
+
git_show(path, ref, project_dir) -- file content at git ref
|
|
8
|
+
git_log_numstat(project_dir, since) -- churn line counts per file
|
|
9
|
+
git_has_repo(project_dir) -- is inside a git work tree?
|
|
10
|
+
git_head_sha(project_dir) -- current HEAD SHA
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
import subprocess
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
_log = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"git_show",
|
|
22
|
+
"git_log_numstat",
|
|
23
|
+
"git_has_repo",
|
|
24
|
+
"git_head_sha",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def git_show(
|
|
29
|
+
path: str,
|
|
30
|
+
ref: str = "HEAD~1",
|
|
31
|
+
project_dir: Path | None = None,
|
|
32
|
+
) -> str | None:
|
|
33
|
+
"""Return file content at git ref or None on failure.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
path: Relative file path (as stored in git, e.g. "BRAIN/foo.py").
|
|
37
|
+
ref: Git ref to read from. Defaults to "HEAD~1".
|
|
38
|
+
project_dir: If given, passes ``-C project_dir`` to git so the command
|
|
39
|
+
runs in the correct working directory regardless of the caller's cwd.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
File content as a string, or None if the file didn't exist at that ref,
|
|
43
|
+
git is unavailable, or any other error occurs (fail-open).
|
|
44
|
+
"""
|
|
45
|
+
args = ["git"]
|
|
46
|
+
if project_dir is not None:
|
|
47
|
+
args += ["-C", str(project_dir)]
|
|
48
|
+
args += ["show", "%s:%s" % (ref, path)]
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
r = subprocess.run(
|
|
52
|
+
args,
|
|
53
|
+
capture_output=True,
|
|
54
|
+
text=True,
|
|
55
|
+
encoding="utf-8",
|
|
56
|
+
errors="replace",
|
|
57
|
+
timeout=10,
|
|
58
|
+
shell=False,
|
|
59
|
+
)
|
|
60
|
+
if r.returncode != 0:
|
|
61
|
+
return None
|
|
62
|
+
return r.stdout
|
|
63
|
+
except (subprocess.SubprocessError, FileNotFoundError, OSError) as exc:
|
|
64
|
+
_log.debug("git_show failed for %s@%s: %s", path, ref, type(exc).__name__)
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def git_log_numstat(
|
|
69
|
+
project_dir: Path,
|
|
70
|
+
since: str = "90.days",
|
|
71
|
+
) -> dict[str, int]:
|
|
72
|
+
"""Return ``{relative_path: churn_line_count}`` for commits since *since*.
|
|
73
|
+
|
|
74
|
+
Churn is defined as added + deleted lines across all commits in the window.
|
|
75
|
+
Binary files (where git outputs ``-`` for line counts) are skipped.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
project_dir: Absolute path to the project root (must be inside a git repo).
|
|
79
|
+
since: ``--since`` value passed to ``git log``, e.g. ``"90.days"`` or
|
|
80
|
+
``"2025-01-01"``.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Dict mapping each file path to total churn line count. Returns an empty
|
|
84
|
+
dict if the directory is not a git repo, git is unavailable, or any
|
|
85
|
+
subprocess error occurs (fail-open).
|
|
86
|
+
"""
|
|
87
|
+
try:
|
|
88
|
+
r = subprocess.run(
|
|
89
|
+
[
|
|
90
|
+
"git",
|
|
91
|
+
"-C", str(project_dir),
|
|
92
|
+
"log",
|
|
93
|
+
"--numstat",
|
|
94
|
+
"--since=%s" % since,
|
|
95
|
+
"--pretty=format:",
|
|
96
|
+
],
|
|
97
|
+
capture_output=True,
|
|
98
|
+
text=True,
|
|
99
|
+
encoding="utf-8",
|
|
100
|
+
errors="replace",
|
|
101
|
+
timeout=30,
|
|
102
|
+
shell=False,
|
|
103
|
+
)
|
|
104
|
+
if r.returncode != 0:
|
|
105
|
+
return {}
|
|
106
|
+
result: dict[str, int] = {}
|
|
107
|
+
for line in r.stdout.splitlines():
|
|
108
|
+
parts = line.split("\t")
|
|
109
|
+
if len(parts) != 3:
|
|
110
|
+
continue
|
|
111
|
+
added, deleted, path = parts
|
|
112
|
+
# Binary files have "-" for line counts — skip them
|
|
113
|
+
if added == "-" or deleted == "-":
|
|
114
|
+
continue
|
|
115
|
+
try:
|
|
116
|
+
churn = int(added) + int(deleted)
|
|
117
|
+
except ValueError:
|
|
118
|
+
continue
|
|
119
|
+
result[path] = result.get(path, 0) + churn
|
|
120
|
+
return result
|
|
121
|
+
except (subprocess.SubprocessError, FileNotFoundError, OSError) as exc:
|
|
122
|
+
_log.debug("git_log_numstat failed in %s: %s", project_dir, type(exc).__name__)
|
|
123
|
+
return {}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def git_has_repo(project_dir: Path) -> bool:
|
|
127
|
+
"""Return True if *project_dir* is inside a git work tree.
|
|
128
|
+
|
|
129
|
+
Uses ``git rev-parse --is-inside-work-tree``. Returns False on any error,
|
|
130
|
+
including git not installed or directory not being a repo (fail-open).
|
|
131
|
+
"""
|
|
132
|
+
try:
|
|
133
|
+
r = subprocess.run(
|
|
134
|
+
[
|
|
135
|
+
"git",
|
|
136
|
+
"-C", str(project_dir),
|
|
137
|
+
"rev-parse",
|
|
138
|
+
"--is-inside-work-tree",
|
|
139
|
+
],
|
|
140
|
+
capture_output=True,
|
|
141
|
+
text=True,
|
|
142
|
+
encoding="utf-8",
|
|
143
|
+
errors="replace",
|
|
144
|
+
timeout=5,
|
|
145
|
+
shell=False,
|
|
146
|
+
)
|
|
147
|
+
return r.returncode == 0 and r.stdout.strip() == "true"
|
|
148
|
+
except (subprocess.SubprocessError, FileNotFoundError, OSError):
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def git_head_sha(project_dir: Path) -> str | None:
|
|
153
|
+
"""Return current HEAD SHA or None on non-git / error.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
40-character hex SHA string, or None if git is unavailable, the
|
|
157
|
+
directory is not a repo, or any other error occurs (fail-open).
|
|
158
|
+
"""
|
|
159
|
+
try:
|
|
160
|
+
r = subprocess.run(
|
|
161
|
+
[
|
|
162
|
+
"git",
|
|
163
|
+
"-C", str(project_dir),
|
|
164
|
+
"rev-parse",
|
|
165
|
+
"HEAD",
|
|
166
|
+
],
|
|
167
|
+
capture_output=True,
|
|
168
|
+
text=True,
|
|
169
|
+
encoding="utf-8",
|
|
170
|
+
errors="replace",
|
|
171
|
+
timeout=5,
|
|
172
|
+
shell=False,
|
|
173
|
+
)
|
|
174
|
+
if r.returncode != 0:
|
|
175
|
+
return None
|
|
176
|
+
return r.stdout.strip() or None
|
|
177
|
+
except (subprocess.SubprocessError, FileNotFoundError, OSError):
|
|
178
|
+
return None
|