code2llm 0.5.145__tar.gz → 0.5.147__tar.gz
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.
- {code2llm-0.5.145/code2llm.egg-info → code2llm-0.5.147}/PKG-INFO +9 -9
- {code2llm-0.5.145 → code2llm-0.5.147}/README.md +8 -8
- code2llm-0.5.147/VERSION +1 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/__init__.py +1 -1
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/smells.py +11 -7
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_exports/formats.py +26 -6
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_exports/orchestrator.py +52 -1
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_exports/orchestrator_handlers.py +36 -11
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_exports/prompt.py +6 -1
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/evolution/computation.py +32 -13
- code2llm-0.5.147/code2llm/exporters/evolution/exclusion.py +17 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/flow_constants.py +5 -7
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/project_yaml/core.py +1 -1
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/toon/helpers.py +41 -9
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/toon/metrics.py +1 -1
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/toon/metrics_core.py +49 -57
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/nlp/__init__.py +1 -1
- {code2llm-0.5.145 → code2llm-0.5.147/code2llm.egg-info}/PKG-INFO +9 -9
- {code2llm-0.5.145 → code2llm-0.5.147}/pyproject.toml +1 -1
- code2llm-0.5.145/VERSION +0 -1
- code2llm-0.5.145/code2llm/exporters/evolution/exclusion.py +0 -17
- {code2llm-0.5.145 → code2llm-0.5.147}/LICENSE +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/MANIFEST.in +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/__main__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/call_graph.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/cfg.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/coupling.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/data_analysis.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/dfg.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/pipeline_classifier.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/pipeline_detector.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/pipeline_resolver.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/side_effects.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/type_inference.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/utils/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/analysis/utils/ast_helpers.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/api.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_analysis.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_commands.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_exports/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_exports/code2logic.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_exports/orchestrator_chunked.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_exports/orchestrator_constants.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/cli_parser.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/analyzer.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/ast_registry.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/config.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/export_pipeline.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/file_analyzer.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/file_cache.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/file_filter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/gitignore.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/incremental.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/base.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/cpp.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/csharp.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/generic.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/go_lang.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/java.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/php.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/ruby.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/rust.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/ts_extractors.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/ts_parser.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/lang/typescript.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/large_repo.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/models.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/persistent_cache.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/refactoring.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/repo_files.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/streaming/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/streaming/cache.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/streaming/incremental.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/streaming/prioritizer.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/streaming/scanner.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/streaming/strategies.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/streaming_analyzer.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/core/toon_size_manager.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/article_view.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/base.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/context_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/context_view.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/dashboard_data.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/dashboard_renderer.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/evolution/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/evolution/constants.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/evolution/render.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/evolution/yaml_export.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/evolution_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/flow_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/flow_renderer.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/html_dashboard.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/index_generator/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/index_generator/renderer.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/index_generator/scanner.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/index_generator.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/json_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/llm_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/map/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/map/alerts.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/map/details.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/map/header.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/map/module_list.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/map/utils.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/map/yaml_export.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/map_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/mermaid/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/mermaid/calls.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/mermaid/classic.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/mermaid/compact.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/mermaid/flow_compact.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/mermaid/flow_detailed.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/mermaid/flow_full.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/mermaid/utils.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/mermaid_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/mermaid_flow_helpers.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/project_yaml/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/project_yaml/constants.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/project_yaml/evolution.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/project_yaml/health.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/project_yaml/hotspots.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/project_yaml/modules.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/project_yaml_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/readme/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/readme/content.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/readme/files.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/readme/insights.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/readme/sections.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/readme_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/report_generators.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/toon/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/toon/metrics_duplicates.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/toon/metrics_health.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/toon/module_detail.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/toon/renderer.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/toon.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/toon_view.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/validate_project.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/exporters/yaml_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/_utils.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/llm_flow/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/llm_flow/analysis.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/llm_flow/cli.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/llm_flow/generator.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/llm_flow/nodes.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/llm_flow/parsing.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/llm_flow/utils.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/llm_flow.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/llm_task.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/mermaid/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/mermaid/fix.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/mermaid/png.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/mermaid/validation.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/generators/mermaid.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/nlp/config.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/nlp/entity_resolution.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/nlp/intent_matching.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/nlp/normalization.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/nlp/pipeline.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/parsers/toon_parser.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/patterns/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/patterns/detector.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/refactor/__init__.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm/refactor/prompt_engine.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm.egg-info/SOURCES.txt +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm.egg-info/dependency_links.txt +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm.egg-info/entry_points.txt +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm.egg-info/requires.txt +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/code2llm.egg-info/top_level.txt +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/setup.cfg +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/setup.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_advanced_analysis.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_analyzer.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_cache_invalidation_e2e.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_calls_toon_export.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_declarative_collection.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_deep_analysis.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_edge_cases.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_file_analyzer_tagging.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_flow_exporter.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_format_quality.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_multilanguage_e2e.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_nlp_pipeline.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_nonpython_cc_calls.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_orchestrator_cache_mtime.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_persistent_cache.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_pipeline_detector.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_project_toon_export.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_prompt_engine.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_prompt_txt.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_refactoring_engine.py +0 -0
- {code2llm-0.5.145 → code2llm-0.5.147}/tests/test_toon_v2.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2llm
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.147
|
|
4
4
|
Summary: High-performance Python code flow analysis with optimized TOON format - CFG, DFG, call graphs, and intelligent code queries
|
|
5
5
|
Home-page: https://github.com/wronai/stts
|
|
6
6
|
Author: STTS Project
|
|
@@ -64,20 +64,20 @@ Dynamic: requires-python
|
|
|
64
64
|
|
|
65
65
|
# code2llm - Generated Analysis Files
|
|
66
66
|
|
|
67
|
-
|
|
68
67
|
## AI Cost Tracking
|
|
69
68
|
|
|
70
|
-
     
|
|
70
|
+
  
|
|
72
71
|
|
|
73
|
-
- 🤖 **LLM usage:** $7.5000 (
|
|
74
|
-
- 👤 **Human dev:** ~$
|
|
72
|
+
- 🤖 **LLM usage:** $7.5000 (199 commits)
|
|
73
|
+
- 👤 **Human dev:** ~$7258 (72.6h @ $100/h, 30min dedup)
|
|
75
74
|
|
|
76
75
|
Generated on 2026-05-06 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
77
76
|
|
|
78
77
|
---
|
|
79
78
|
|
|
80
79
|
|
|
80
|
+
<!-- generated in 0.00s -->
|
|
81
81
|
|
|
82
82
|
This directory contains the complete analysis of your project generated by `code2llm`. Each file serves a specific purpose for understanding, refactoring, and documenting your codebase.
|
|
83
83
|
|
|
@@ -408,9 +408,9 @@ code2llm ./ -f yaml --separate-orphans
|
|
|
408
408
|
|
|
409
409
|
**Generated by**: `code2llm ./ -f all --readme`
|
|
410
410
|
**Analysis Date**: 2026-05-06
|
|
411
|
-
**Total Functions**:
|
|
412
|
-
**Total Classes**:
|
|
413
|
-
**Modules**:
|
|
411
|
+
**Total Functions**: 3800
|
|
412
|
+
**Total Classes**: 259
|
|
413
|
+
**Modules**: 497
|
|
414
414
|
|
|
415
415
|
For more information about code2llm, visit: https://github.com/tom-sapletta/code2llm
|
|
416
416
|
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
# code2llm - Generated Analysis Files
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
## AI Cost Tracking
|
|
5
4
|
|
|
6
|
-
     
|
|
6
|
+
  
|
|
8
7
|
|
|
9
|
-
- 🤖 **LLM usage:** $7.5000 (
|
|
10
|
-
- 👤 **Human dev:** ~$
|
|
8
|
+
- 🤖 **LLM usage:** $7.5000 (199 commits)
|
|
9
|
+
- 👤 **Human dev:** ~$7258 (72.6h @ $100/h, 30min dedup)
|
|
11
10
|
|
|
12
11
|
Generated on 2026-05-06 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
13
12
|
|
|
14
13
|
---
|
|
15
14
|
|
|
16
15
|
|
|
16
|
+
<!-- generated in 0.00s -->
|
|
17
17
|
|
|
18
18
|
This directory contains the complete analysis of your project generated by `code2llm`. Each file serves a specific purpose for understanding, refactoring, and documenting your codebase.
|
|
19
19
|
|
|
@@ -344,9 +344,9 @@ code2llm ./ -f yaml --separate-orphans
|
|
|
344
344
|
|
|
345
345
|
**Generated by**: `code2llm ./ -f all --readme`
|
|
346
346
|
**Analysis Date**: 2026-05-06
|
|
347
|
-
**Total Functions**:
|
|
348
|
-
**Total Classes**:
|
|
349
|
-
**Modules**:
|
|
347
|
+
**Total Functions**: 3800
|
|
348
|
+
**Total Classes**: 259
|
|
349
|
+
**Modules**: 497
|
|
350
350
|
|
|
351
351
|
For more information about code2llm, visit: https://github.com/tom-sapletta/code2llm
|
|
352
352
|
|
code2llm-0.5.147/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.5.147
|
|
@@ -8,7 +8,7 @@ Includes NLP Processing Pipeline for query normalization, intent matching,
|
|
|
8
8
|
and entity resolution with multilingual support.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
__version__ = "0.5.
|
|
11
|
+
__version__ = "0.5.147"
|
|
12
12
|
__author__ = "STTS Project"
|
|
13
13
|
|
|
14
14
|
# Core analysis components (lightweight, always needed)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Detection of code smells using analysis metrics."""
|
|
2
|
+
from collections import defaultdict
|
|
2
3
|
from typing import List, Dict, Any
|
|
3
4
|
from code2llm.core.models import AnalysisResult, CodeSmell
|
|
4
5
|
|
|
@@ -7,6 +8,10 @@ class SmellDetector:
|
|
|
7
8
|
|
|
8
9
|
def __init__(self, result: AnalysisResult):
|
|
9
10
|
self.result = result
|
|
11
|
+
# Pre-index mutations by scope — avoids O(n×m) full scans
|
|
12
|
+
self._mutations_by_scope: Dict[str, list] = defaultdict(list)
|
|
13
|
+
for m in result.mutations:
|
|
14
|
+
self._mutations_by_scope[m.scope].append(m)
|
|
10
15
|
|
|
11
16
|
def detect(self) -> List[CodeSmell]:
|
|
12
17
|
"""Record and return detected code smells."""
|
|
@@ -28,7 +33,7 @@ class SmellDetector:
|
|
|
28
33
|
for func_name, func_info in self.result.functions.items():
|
|
29
34
|
metrics = self.result.metrics.get(func_name, {})
|
|
30
35
|
fan_out = metrics.get('fan_out', 0)
|
|
31
|
-
mutation_count = len(
|
|
36
|
+
mutation_count = len(self._mutations_by_scope.get(func_name, []))
|
|
32
37
|
|
|
33
38
|
# Use cyclomatic complexity (now mapped to 'cc' in FunctionInfo.complexity)
|
|
34
39
|
complexity = func_info.complexity.get('cyclomatic_complexity', 1)
|
|
@@ -78,12 +83,11 @@ class SmellDetector:
|
|
|
78
83
|
mut_mod = func_name.split('.')[0]
|
|
79
84
|
foreign_mutations = []
|
|
80
85
|
|
|
81
|
-
for mutation in self.
|
|
82
|
-
if
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
foreign_mutations.append(mutation.variable)
|
|
86
|
+
for mutation in self._mutations_by_scope.get(func_name, []):
|
|
87
|
+
if '.' in mutation.variable:
|
|
88
|
+
origin_mod = mutation.variable.split('.')[0]
|
|
89
|
+
if origin_mod != mut_mod:
|
|
90
|
+
foreign_mutations.append(mutation.variable)
|
|
87
91
|
|
|
88
92
|
if len(set(foreign_mutations)) >= 3:
|
|
89
93
|
smells.append(CodeSmell(
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
|
+
import time
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Optional
|
|
7
8
|
|
|
@@ -13,6 +14,7 @@ from code2llm.exporters import (
|
|
|
13
14
|
ArticleViewGenerator, HTMLDashboardGenerator,
|
|
14
15
|
load_project_yaml, IndexHTMLGenerator,
|
|
15
16
|
)
|
|
17
|
+
from .orchestrator import _inject_generation_time as _inject_time
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
def _export_evolution(args, result, output_dir: Path):
|
|
@@ -21,9 +23,12 @@ def _export_evolution(args, result, output_dir: Path):
|
|
|
21
23
|
return
|
|
22
24
|
exporter = EvolutionExporter()
|
|
23
25
|
filepath = output_dir / 'evolution.toon.yaml'
|
|
26
|
+
t0 = time.monotonic()
|
|
24
27
|
exporter.export(result, str(filepath))
|
|
28
|
+
elapsed = time.monotonic() - t0
|
|
29
|
+
_inject_time(filepath, elapsed)
|
|
25
30
|
if args.verbose:
|
|
26
|
-
print(f" - EVOLUTION (refactoring queue): {filepath}")
|
|
31
|
+
print(f" - EVOLUTION (refactoring queue): {filepath} ({elapsed:.2f}s)")
|
|
27
32
|
|
|
28
33
|
|
|
29
34
|
def _export_data_structures(args, result, output_dir: Path):
|
|
@@ -43,9 +48,12 @@ def _export_context_fallback(args, result, output_dir: Path, formats: list):
|
|
|
43
48
|
return
|
|
44
49
|
exporter = ContextExporter()
|
|
45
50
|
filepath = output_dir / 'context.md'
|
|
51
|
+
t0 = time.monotonic()
|
|
46
52
|
exporter.export(result, str(filepath))
|
|
53
|
+
elapsed = time.monotonic() - t0
|
|
54
|
+
_inject_time(filepath, elapsed)
|
|
47
55
|
if args.verbose:
|
|
48
|
-
print(f" - CONTEXT (LLM narrative): {filepath}")
|
|
56
|
+
print(f" - CONTEXT (LLM narrative): {filepath} ({elapsed:.2f}s)")
|
|
49
57
|
|
|
50
58
|
|
|
51
59
|
def _export_readme(args, result, output_dir: Path):
|
|
@@ -54,18 +62,24 @@ def _export_readme(args, result, output_dir: Path):
|
|
|
54
62
|
return
|
|
55
63
|
exporter = READMEExporter()
|
|
56
64
|
filepath = output_dir / 'README.md'
|
|
65
|
+
t0 = time.monotonic()
|
|
57
66
|
exporter.export(result, str(filepath))
|
|
67
|
+
elapsed = time.monotonic() - t0
|
|
68
|
+
_inject_time(filepath, elapsed)
|
|
58
69
|
if args.verbose:
|
|
59
|
-
print(f" - README (documentation): {filepath}")
|
|
70
|
+
print(f" - README (documentation): {filepath} ({elapsed:.2f}s)")
|
|
60
71
|
|
|
61
72
|
|
|
62
73
|
def _export_project_yaml(args, result, output_dir: Path):
|
|
63
74
|
"""Export unified project.yaml — single source of truth."""
|
|
64
75
|
exporter = ProjectYAMLExporter()
|
|
65
76
|
filepath = output_dir / 'project.yaml'
|
|
77
|
+
t0 = time.monotonic()
|
|
66
78
|
exporter.export(result, str(filepath))
|
|
79
|
+
elapsed = time.monotonic() - t0
|
|
80
|
+
_inject_time(filepath, elapsed)
|
|
67
81
|
if getattr(args, 'verbose', False):
|
|
68
|
-
print(f" - PROJECT-YAML (single source of truth): {filepath}")
|
|
82
|
+
print(f" - PROJECT-YAML (single source of truth): {filepath} ({elapsed:.2f}s)")
|
|
69
83
|
return filepath
|
|
70
84
|
|
|
71
85
|
|
|
@@ -79,10 +93,13 @@ def _export_project_toon(args, result, output_dir: Path):
|
|
|
79
93
|
|
|
80
94
|
exporter = ToonViewGenerator()
|
|
81
95
|
filepath = output_dir / 'project.toon.yaml'
|
|
96
|
+
t0 = time.monotonic()
|
|
82
97
|
exporter.generate(data, str(filepath))
|
|
98
|
+
elapsed = time.monotonic() - t0
|
|
99
|
+
_inject_time(filepath, elapsed)
|
|
83
100
|
|
|
84
101
|
if getattr(args, 'verbose', False):
|
|
85
|
-
print(f" - PROJECT-TOON (project overview): {filepath}")
|
|
102
|
+
print(f" - PROJECT-TOON (project overview): {filepath} ({elapsed:.2f}s)")
|
|
86
103
|
|
|
87
104
|
return filepath
|
|
88
105
|
|
|
@@ -129,9 +146,12 @@ def _export_simple_formats(args, result, output_dir: Path, formats):
|
|
|
129
146
|
exporter = exporter_cls()
|
|
130
147
|
# Export as plain text TOON format with .toon.yaml extension
|
|
131
148
|
filepath = output_dir / filename
|
|
149
|
+
t0 = time.monotonic()
|
|
132
150
|
exporter.export(result, str(filepath))
|
|
151
|
+
elapsed = time.monotonic() - t0
|
|
152
|
+
_inject_time(filepath, elapsed)
|
|
133
153
|
if args.verbose:
|
|
134
|
-
print(f" - {label}: {filepath}")
|
|
154
|
+
print(f" - {label}: {filepath} ({elapsed:.2f}s)")
|
|
135
155
|
|
|
136
156
|
# Unified project.yaml (single source of truth)
|
|
137
157
|
if 'project-yaml' in formats:
|
|
@@ -7,6 +7,7 @@ Maintains backward compatibility with all existing --format values.
|
|
|
7
7
|
import os
|
|
8
8
|
import shutil
|
|
9
9
|
import sys
|
|
10
|
+
import time
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import Optional, List, Dict, Any
|
|
12
13
|
|
|
@@ -280,9 +281,12 @@ def _export_registry_formats(args, result, output_dir: Path, formats: List[str])
|
|
|
280
281
|
kwargs = _get_format_kwargs(fmt, args)
|
|
281
282
|
|
|
282
283
|
try:
|
|
284
|
+
t0 = time.monotonic()
|
|
283
285
|
exporter.export(result, str(filepath), **kwargs)
|
|
286
|
+
elapsed = time.monotonic() - t0
|
|
287
|
+
_inject_generation_time(filepath, elapsed)
|
|
284
288
|
if args.verbose:
|
|
285
|
-
print(f" - {label}: {filepath}")
|
|
289
|
+
print(f" - {label}: {filepath} ({elapsed:.2f}s)")
|
|
286
290
|
except Exception as e:
|
|
287
291
|
if args.verbose:
|
|
288
292
|
print(f" - {label} export failed: {e}", file=sys.stderr)
|
|
@@ -306,6 +310,53 @@ def _export_chunked(
|
|
|
306
310
|
_chunked_impl(args, result, output_dir, source_path, formats, requested_formats)
|
|
307
311
|
|
|
308
312
|
|
|
313
|
+
def _inject_generation_time(filepath: Path, elapsed: float) -> None:
|
|
314
|
+
"""Inject generation time comment into the second line of an exported file."""
|
|
315
|
+
try:
|
|
316
|
+
path = Path(filepath)
|
|
317
|
+
if not path.exists():
|
|
318
|
+
return
|
|
319
|
+
suffix = path.suffix.lower()
|
|
320
|
+
name = path.name.lower()
|
|
321
|
+
|
|
322
|
+
# Only inject into text-based files
|
|
323
|
+
if suffix not in ('.yaml', '.yml', '.md', '.txt', '.mmd', '.html', '.json', '.export'):
|
|
324
|
+
return
|
|
325
|
+
|
|
326
|
+
content = path.read_text(encoding='utf-8')
|
|
327
|
+
if not content:
|
|
328
|
+
return
|
|
329
|
+
|
|
330
|
+
tag = f"generated in {elapsed:.2f}s"
|
|
331
|
+
|
|
332
|
+
if suffix in ('.yaml', '.yml', '.mmd', '.export', '.txt') or name.endswith('.toon.yaml'):
|
|
333
|
+
# YAML/Mermaid/text: insert '# generated in X.XXs' after first line
|
|
334
|
+
lines = content.split('\n', 1)
|
|
335
|
+
if len(lines) == 2:
|
|
336
|
+
content = f"{lines[0]}\n# {tag}\n{lines[1]}"
|
|
337
|
+
else:
|
|
338
|
+
content = f"{lines[0]}\n# {tag}\n"
|
|
339
|
+
elif suffix == '.md':
|
|
340
|
+
# Markdown: insert HTML comment after first line
|
|
341
|
+
lines = content.split('\n', 1)
|
|
342
|
+
if len(lines) == 2:
|
|
343
|
+
content = f"{lines[0]}\n<!-- {tag} -->\n{lines[1]}"
|
|
344
|
+
else:
|
|
345
|
+
content = f"{lines[0]}\n<!-- {tag} -->\n"
|
|
346
|
+
elif suffix == '.html':
|
|
347
|
+
# HTML: insert comment after <!DOCTYPE or <html>
|
|
348
|
+
content = content.replace('\n', f'\n<!-- {tag} -->\n', 1)
|
|
349
|
+
elif suffix == '.json':
|
|
350
|
+
# JSON doesn't support comments — skip
|
|
351
|
+
return
|
|
352
|
+
else:
|
|
353
|
+
return
|
|
354
|
+
|
|
355
|
+
path.write_text(content, encoding='utf-8')
|
|
356
|
+
except Exception:
|
|
357
|
+
pass # Never fail the export pipeline for a comment
|
|
358
|
+
|
|
359
|
+
|
|
309
360
|
# Backward-compatible aliases
|
|
310
361
|
_export_single_project = _export_single
|
|
311
362
|
_export_chunked_results = _export_chunked
|
|
@@ -4,6 +4,7 @@ This module contains all the individual export handler functions
|
|
|
4
4
|
that were extracted from orchestrator.py to reduce its size.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import time
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from typing import Any, Dict, List
|
|
9
10
|
|
|
@@ -20,10 +21,14 @@ from .orchestrator_constants import FORMAT_LABELS
|
|
|
20
21
|
|
|
21
22
|
def _export_mermaid(args, result, output_dir: Path):
|
|
22
23
|
"""Export mermaid diagrams."""
|
|
24
|
+
from .orchestrator import _inject_generation_time
|
|
25
|
+
|
|
23
26
|
exporter = MermaidExporter()
|
|
24
27
|
include_examples = getattr(args, 'flow_include_examples', False)
|
|
25
28
|
|
|
26
29
|
# Core diagrams
|
|
30
|
+
mmd_files = ['flow.mmd', 'calls.mmd', 'compact_flow.mmd']
|
|
31
|
+
t0 = time.monotonic()
|
|
27
32
|
exporter.export_flow_compact(result, str(output_dir / 'flow.mmd'), include_examples)
|
|
28
33
|
exporter.export_call_graph(result, str(output_dir / 'calls.mmd'))
|
|
29
34
|
exporter.export_compact(result, str(output_dir / 'compact_flow.mmd'))
|
|
@@ -31,21 +36,27 @@ def _export_mermaid(args, result, output_dir: Path):
|
|
|
31
36
|
# Optional detailed diagrams
|
|
32
37
|
if getattr(args, 'flow_detail', False):
|
|
33
38
|
exporter.export_flow_detailed(result, str(output_dir / 'flow_detailed.mmd'), include_examples)
|
|
39
|
+
mmd_files.append('flow_detailed.mmd')
|
|
34
40
|
if getattr(args, 'flow_full', False):
|
|
35
41
|
exporter.export_flow_full(result, str(output_dir / 'flow_full.mmd'), include_examples)
|
|
42
|
+
mmd_files.append('flow_full.mmd')
|
|
43
|
+
elapsed_mmd = time.monotonic() - t0
|
|
44
|
+
|
|
45
|
+
# Inject timing into each .mmd file
|
|
46
|
+
for mf in mmd_files:
|
|
47
|
+
_inject_generation_time(output_dir / mf, elapsed_mmd)
|
|
36
48
|
|
|
37
49
|
# Also export calls.yaml/toon
|
|
38
50
|
yaml_exporter = YAMLExporter()
|
|
51
|
+
t0 = time.monotonic()
|
|
39
52
|
yaml_exporter.export_calls(result, str(output_dir / 'calls.yaml'))
|
|
40
53
|
yaml_exporter.export_calls_toon(result, str(output_dir / 'calls.toon.yaml'))
|
|
54
|
+
elapsed_calls = time.monotonic() - t0
|
|
55
|
+
_inject_generation_time(output_dir / 'calls.toon.yaml', elapsed_calls)
|
|
41
56
|
|
|
42
57
|
if args.verbose:
|
|
43
|
-
files =
|
|
44
|
-
|
|
45
|
-
files.append('flow_detailed.mmd')
|
|
46
|
-
if getattr(args, 'flow_full', False):
|
|
47
|
-
files.append('flow_full.mmd')
|
|
48
|
-
print(f" - Mermaid: {output_dir}/*.mmd ({', '.join(files)})")
|
|
58
|
+
files = mmd_files + ['calls.yaml']
|
|
59
|
+
print(f" - Mermaid: {output_dir}/*.mmd ({', '.join(files)}) ({elapsed_mmd:.2f}s)")
|
|
49
60
|
|
|
50
61
|
# PNG generation
|
|
51
62
|
_export_mermaid_pngs(args, output_dir)
|
|
@@ -99,28 +110,38 @@ def _export_data_structures(args, result, output_dir: Path):
|
|
|
99
110
|
def _export_project_toon(args, result, output_dir: Path):
|
|
100
111
|
"""Export project.toon.yaml from project.yaml data."""
|
|
101
112
|
from ..exporters.project_yaml_exporter import ProjectYAMLExporter
|
|
113
|
+
from .orchestrator import _inject_generation_time
|
|
102
114
|
|
|
103
115
|
project_yaml_exporter = ProjectYAMLExporter()
|
|
104
116
|
prev_evolution = load_previous_evolution(output_dir / 'project.yaml')
|
|
105
117
|
data = project_yaml_exporter._build_project_yaml(result, prev_evolution)
|
|
106
118
|
|
|
107
119
|
generator = ToonViewGenerator()
|
|
108
|
-
|
|
120
|
+
filepath = output_dir / 'project.toon.yaml'
|
|
121
|
+
t0 = time.monotonic()
|
|
122
|
+
generator.generate(data, str(filepath))
|
|
123
|
+
elapsed = time.monotonic() - t0
|
|
124
|
+
_inject_generation_time(filepath, elapsed)
|
|
109
125
|
|
|
110
126
|
if args.verbose:
|
|
111
|
-
print(f" - PROJECT-TOON (project overview): {
|
|
127
|
+
print(f" - PROJECT-TOON (project overview): {filepath} ({elapsed:.2f}s)")
|
|
112
128
|
|
|
113
129
|
|
|
114
130
|
def _export_readme(args, result, output_dir: Path):
|
|
115
131
|
"""Export README.md."""
|
|
116
132
|
if getattr(args, 'no_readme', False):
|
|
117
133
|
return
|
|
134
|
+
from .orchestrator import _inject_generation_time
|
|
118
135
|
exporter_cls = get_exporter('readme')
|
|
119
136
|
if exporter_cls:
|
|
120
137
|
exporter = exporter_cls()
|
|
121
|
-
|
|
138
|
+
filepath = output_dir / 'README.md'
|
|
139
|
+
t0 = time.monotonic()
|
|
140
|
+
exporter.export(result, str(filepath))
|
|
141
|
+
elapsed = time.monotonic() - t0
|
|
142
|
+
_inject_generation_time(filepath, elapsed)
|
|
122
143
|
if args.verbose:
|
|
123
|
-
print(f" - README (documentation): {
|
|
144
|
+
print(f" - README (documentation): {filepath} ({elapsed:.2f}s)")
|
|
124
145
|
|
|
125
146
|
|
|
126
147
|
def _export_index_html(args, output_dir: Path):
|
|
@@ -128,10 +149,14 @@ def _export_index_html(args, output_dir: Path):
|
|
|
128
149
|
if 'all' not in getattr(args, 'format', ''):
|
|
129
150
|
return
|
|
130
151
|
try:
|
|
152
|
+
from .orchestrator import _inject_generation_time
|
|
131
153
|
generator = IndexHTMLGenerator(output_dir)
|
|
154
|
+
t0 = time.monotonic()
|
|
132
155
|
index_path = generator.generate()
|
|
156
|
+
elapsed = time.monotonic() - t0
|
|
157
|
+
_inject_generation_time(index_path, elapsed)
|
|
133
158
|
if args.verbose:
|
|
134
|
-
print(f" - INDEX (file browser): {index_path}")
|
|
159
|
+
print(f" - INDEX (file browser): {index_path} ({elapsed:.2f}s)")
|
|
135
160
|
except Exception as e:
|
|
136
161
|
if args.verbose:
|
|
137
162
|
print(f" - INDEX generation failed: {e}", file=__import__('sys').stderr)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Prompt generation — prompt.txt for LLM consumption (regular and chunked)."""
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
|
+
import time
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import List, Optional, Tuple
|
|
6
7
|
|
|
@@ -30,9 +31,13 @@ def _export_prompt_txt(args, output_dir: Path, formats: list[str], source_path:
|
|
|
30
31
|
lines.extend(_build_prompt_footer(chunked=False, file_analysis=file_analysis))
|
|
31
32
|
|
|
32
33
|
prompt_path = output_dir / 'prompt.txt'
|
|
34
|
+
t0 = time.monotonic()
|
|
33
35
|
prompt_path.write_text("\n".join(lines) + "\n", encoding='utf-8')
|
|
36
|
+
elapsed = time.monotonic() - t0
|
|
37
|
+
from .orchestrator import _inject_generation_time
|
|
38
|
+
_inject_generation_time(prompt_path, elapsed)
|
|
34
39
|
if args.verbose:
|
|
35
|
-
print(f" - PROMPT: {prompt_path}")
|
|
40
|
+
print(f" - PROMPT: {prompt_path} ({elapsed:.2f}s)")
|
|
36
41
|
|
|
37
42
|
|
|
38
43
|
def _export_chunked_prompt_txt(args, output_dir: Path, formats: list[str], source_path: Optional[Path] = None, subprojects: list = None) -> None:
|
|
@@ -29,21 +29,40 @@ def compute_func_data(result: AnalysisResult) -> List[Dict]:
|
|
|
29
29
|
return sorted(func_data, key=lambda x: x["impact"], reverse=True)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def scan_file_sizes(project_path: Optional[Path]) -> Dict[str, int]:
|
|
33
|
-
"""
|
|
32
|
+
def scan_file_sizes(project_path: Optional[Path], result: Optional[AnalysisResult] = None) -> Dict[str, int]:
|
|
33
|
+
"""Return per-file line counts, preferring already-analyzed module data."""
|
|
34
34
|
file_lines: Dict[str, int] = {}
|
|
35
|
+
|
|
36
|
+
# Fast path: derive from AnalysisResult modules (no I/O)
|
|
37
|
+
if result and result.modules:
|
|
38
|
+
for mi in result.modules.values():
|
|
39
|
+
if mi.file and not is_excluded(mi.file):
|
|
40
|
+
lc = mi.line_count if hasattr(mi, 'line_count') and mi.line_count else 0
|
|
41
|
+
if lc == 0:
|
|
42
|
+
lc = len(mi.functions) + len(mi.classes)
|
|
43
|
+
if lc > 0:
|
|
44
|
+
file_lines[mi.file] = lc
|
|
45
|
+
if file_lines:
|
|
46
|
+
return file_lines
|
|
47
|
+
|
|
48
|
+
# Slow fallback: single os.walk (only if result is unavailable)
|
|
35
49
|
if not project_path or not project_path.is_dir():
|
|
36
50
|
return file_lines
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
|
|
52
|
+
import os
|
|
53
|
+
exclude = {'.git', '__pycache__', 'node_modules', 'venv', '.venv',
|
|
54
|
+
'env', '.env', 'site-packages', 'dist', 'build', '.tox'}
|
|
55
|
+
for dirpath, dirnames, filenames in os.walk(str(project_path)):
|
|
56
|
+
dirnames[:] = [d for d in dirnames if d not in exclude]
|
|
57
|
+
for fn in filenames:
|
|
58
|
+
if not fn.endswith('.py'):
|
|
59
|
+
continue
|
|
60
|
+
fpath = os.path.join(dirpath, fn)
|
|
61
|
+
try:
|
|
62
|
+
with open(fpath, encoding='utf-8', errors='ignore') as f:
|
|
63
|
+
file_lines[fpath] = sum(1 for _ in f)
|
|
64
|
+
except Exception:
|
|
65
|
+
pass
|
|
47
66
|
return file_lines
|
|
48
67
|
|
|
49
68
|
|
|
@@ -109,7 +128,7 @@ def compute_god_modules(result: AnalysisResult) -> List[Dict]:
|
|
|
109
128
|
"""Identify god modules (≥500 lines) from project files."""
|
|
110
129
|
pp = Path(result.project_path) if result.project_path else None
|
|
111
130
|
|
|
112
|
-
file_lines = scan_file_sizes(pp)
|
|
131
|
+
file_lines = scan_file_sizes(pp, result)
|
|
113
132
|
file_stats = aggregate_file_stats(result, file_lines)
|
|
114
133
|
return filter_god_modules(file_stats, pp)
|
|
115
134
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Evolution exporter exclusion logic — path filtering."""
|
|
2
|
+
|
|
3
|
+
from functools import lru_cache
|
|
4
|
+
|
|
5
|
+
from .constants import EXCLUDE_PATTERNS
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@lru_cache(maxsize=4096)
|
|
9
|
+
def is_excluded(path: str) -> bool:
|
|
10
|
+
"""Check if path should be excluded (venv, site-packages, etc.)."""
|
|
11
|
+
if not path:
|
|
12
|
+
return False
|
|
13
|
+
parts = set(path.lower().replace('\\', '/').split('/'))
|
|
14
|
+
return bool(parts & EXCLUDE_PATTERNS)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__all__ = ['is_excluded']
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
Zawiera progi, wzorce wykluczeń i rekomendacje dotyczące podziału typów hub.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from functools import lru_cache
|
|
7
|
+
|
|
6
8
|
# Progi dla wykrywania problemów
|
|
7
9
|
CC_HIGH = 15
|
|
8
10
|
FAN_OUT_THRESHOLD = 10
|
|
@@ -19,17 +21,13 @@ EXCLUDE_PATTERNS = {
|
|
|
19
21
|
'virtualenv', '.virtualenv', 'envs', '.envs',
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
@lru_cache(maxsize=4096)
|
|
22
25
|
def is_excluded_path(path: str) -> bool:
|
|
23
26
|
"""Return True if *path* matches any standard exclusion pattern (venv, cache, etc.)."""
|
|
24
27
|
if not path:
|
|
25
28
|
return False
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if f'/{pattern}/' in path_lower or path_lower.startswith(f'{pattern}/'):
|
|
29
|
-
return True
|
|
30
|
-
if pattern in path_lower.split('/'):
|
|
31
|
-
return True
|
|
32
|
-
return False
|
|
29
|
+
parts = set(path.lower().replace('\\', '/').split('/'))
|
|
30
|
+
return bool(parts & EXCLUDE_PATTERNS)
|
|
33
31
|
|
|
34
32
|
|
|
35
33
|
# Rekomendacje podziału typów hub: typ -> sugerowane pod-interfejsy
|
|
@@ -48,7 +48,7 @@ class ProjectYAMLExporter(BaseExporter):
|
|
|
48
48
|
self, result: AnalysisResult, prev_evolution: List[Dict]
|
|
49
49
|
) -> Dict[str, Any]:
|
|
50
50
|
"""Build complete project.yaml structure."""
|
|
51
|
-
line_counts = _scan_line_counts(result.project_path)
|
|
51
|
+
line_counts = _scan_line_counts(result.project_path, result=result)
|
|
52
52
|
# Filter out venv/site-packages/etc — only count lines of non-excluded files
|
|
53
53
|
filtered_lines = {
|
|
54
54
|
k: v for k, v in line_counts.items()
|
|
@@ -10,6 +10,7 @@ from code2llm.core.models import AnalysisResult, FunctionInfo
|
|
|
10
10
|
from ..flow_constants import is_excluded_path as _is_excluded
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
@lru_cache(maxsize=4096)
|
|
13
14
|
def _rel_path(fpath: str, project_path: str) -> str:
|
|
14
15
|
if not project_path or not fpath:
|
|
15
16
|
return fpath or ""
|
|
@@ -83,15 +84,12 @@ def _hotspot_description(fi: FunctionInfo, fan_out: int) -> str:
|
|
|
83
84
|
return f"calls {fan_out} functions"
|
|
84
85
|
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
"""Scan project directory for all source file line counts.
|
|
87
|
+
def _scan_line_counts(project_path, result=None) -> Dict[str, int]:
|
|
88
|
+
"""Get line counts for project files.
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
Fast path: derive from AnalysisResult modules (already parsed, no extra I/O).
|
|
91
|
+
Slow fallback: single os.walk pass reading files from disk.
|
|
92
92
|
"""
|
|
93
|
-
from ...core.config import ALL_EXTENSIONS
|
|
94
|
-
|
|
95
93
|
line_counts: Dict[str, int] = {}
|
|
96
94
|
if not project_path:
|
|
97
95
|
return line_counts
|
|
@@ -99,8 +97,35 @@ def _scan_line_counts(project_path) -> Dict[str, int]:
|
|
|
99
97
|
if not pp.is_dir():
|
|
100
98
|
return line_counts
|
|
101
99
|
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
# Fast path: use already-analyzed file data when available
|
|
101
|
+
if result is not None:
|
|
102
|
+
for mname, mi in getattr(result, 'modules', {}).items():
|
|
103
|
+
fpath = mi.file
|
|
104
|
+
if not fpath:
|
|
105
|
+
continue
|
|
106
|
+
try:
|
|
107
|
+
lc = len(Path(fpath).read_text(encoding="utf-8", errors="ignore").splitlines())
|
|
108
|
+
rel = str(Path(fpath).relative_to(pp))
|
|
109
|
+
line_counts[str(fpath)] = lc
|
|
110
|
+
line_counts[rel] = lc
|
|
111
|
+
except Exception:
|
|
112
|
+
pass
|
|
113
|
+
return line_counts
|
|
114
|
+
|
|
115
|
+
# Slow fallback: single walk instead of 73 rglob calls
|
|
116
|
+
from ...core.config import ALL_EXTENSIONS
|
|
117
|
+
ext_set = set(ALL_EXTENSIONS)
|
|
118
|
+
for root, dirs, files in Path(project_path).walk() if hasattr(Path, 'walk') else _walk_compat(pp):
|
|
119
|
+
# Prune excluded directories
|
|
120
|
+
dirs[:] = [d for d in dirs if d not in {
|
|
121
|
+
'venv', '.venv', 'node_modules', '__pycache__', '.git',
|
|
122
|
+
'dist', 'build', '.tox', '.mypy_cache', 'egg-info',
|
|
123
|
+
}]
|
|
124
|
+
for fname in files:
|
|
125
|
+
ext = Path(fname).suffix
|
|
126
|
+
if ext not in ext_set:
|
|
127
|
+
continue
|
|
128
|
+
src_file = root / fname
|
|
104
129
|
try:
|
|
105
130
|
lc = len(src_file.read_text(encoding="utf-8", errors="ignore").splitlines())
|
|
106
131
|
rel = str(src_file.relative_to(pp))
|
|
@@ -109,3 +134,10 @@ def _scan_line_counts(project_path) -> Dict[str, int]:
|
|
|
109
134
|
except Exception:
|
|
110
135
|
pass
|
|
111
136
|
return line_counts
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _walk_compat(path):
|
|
140
|
+
"""os.walk compatibility wrapper for Path (Python < 3.12)."""
|
|
141
|
+
import os
|
|
142
|
+
for root, dirs, files in os.walk(path):
|
|
143
|
+
yield Path(root), dirs, files
|