code2llm 0.5.173__tar.gz → 0.5.175__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.173/code2llm.egg-info → code2llm-0.5.175}/PKG-INFO +6 -6
- {code2llm-0.5.173 → code2llm-0.5.175}/README.md +5 -5
- code2llm-0.5.175/VERSION +1 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/__init__.py +1 -1
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_exports/orchestrator.py +4 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/base.py +26 -2
- code2llm-0.5.175/code2llm/exporters/flow_constants.py +109 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/map/header.py +4 -1
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/map_exporter.py +1 -4
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/planfile_tickets.py +51 -19
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/_render_section_helpers.py +2 -1
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/helpers.py +1 -1
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/metrics_duplicates.py +8 -2
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/metrics_health.py +8 -6
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/renderer.py +1 -1
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/mermaid/png.py +36 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/nlp/__init__.py +1 -1
- {code2llm-0.5.173 → code2llm-0.5.175/code2llm.egg-info}/PKG-INFO +6 -6
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm.egg-info/SOURCES.txt +3 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/pyproject.toml +1 -1
- code2llm-0.5.175/tests/test_dup_groups.py +140 -0
- code2llm-0.5.175/tests/test_export_profile_contract.py +28 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_format_quality.py +3 -0
- code2llm-0.5.175/tests/test_mermaid_png.py +29 -0
- code2llm-0.5.173/VERSION +0 -1
- code2llm-0.5.173/code2llm/exporters/flow_constants.py +0 -63
- {code2llm-0.5.173 → code2llm-0.5.175}/LICENSE +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/MANIFEST.in +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/__main__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/_data_impl.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/call_graph.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/cfg.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/coupling.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/data_analysis.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/dfg.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/pipeline_classifier.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/pipeline_detector.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/pipeline_resolver.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/side_effects.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/smells.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/type_inference.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/utils/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/analysis/utils/ast_helpers.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/api.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_analysis.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_commands.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_exports/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_exports/code2logic.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_exports/formats.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_exports/orchestrator_chunked.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_exports/orchestrator_constants.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_exports/orchestrator_handlers.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_exports/prompt.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/cli_parser.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/analyzer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/ast_registry.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/config.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/export_pipeline.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/file_analyzer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/file_cache.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/file_filter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/gitignore.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/incremental.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/_c_parser.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/_calls.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/_complexity.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/base.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/cpp.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/csharp.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/generic.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/go_lang.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/java.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/php.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/ruby.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/rust.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/ts_extractors.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/ts_parser.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/lang/typescript.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/large_repo.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/models.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/persistent_cache.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/refactoring.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/repo_files.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/source_classifier.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/streaming/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/streaming/cache.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/streaming/incremental.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/streaming/prioritizer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/streaming/scanner.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/streaming/strategies.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/streaming_analyzer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/core/toon_size_manager.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/article_view.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/context_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/context_view.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/dashboard_data.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/dashboard_renderer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/evolution/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/evolution/computation.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/evolution/constants.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/evolution/exclusion.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/evolution/render.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/evolution/yaml_export.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/evolution_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/flow_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/flow_renderer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/html_dashboard.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/index_generator/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/index_generator/renderer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/index_generator/scanner.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/index_generator.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/json_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/llm_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/map/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/map/alerts.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/map/details.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/map/module_list.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/map/utils.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/map/yaml_export.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/mermaid/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/mermaid/calls.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/mermaid/classic.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/mermaid/compact.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/mermaid/flow_compact.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/mermaid/flow_detailed.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/mermaid/flow_full.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/mermaid/utils.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/mermaid_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/mermaid_flow_helpers.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/project_yaml/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/project_yaml/constants.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/project_yaml/core.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/project_yaml/evolution.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/project_yaml/health.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/project_yaml/hotspots.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/project_yaml/modules.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/project_yaml_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/readme/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/readme/content.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/readme/files.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/readme/insights.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/readme/sections.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/readme_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/report_generators.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/_render_coupling_helpers.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/constants.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/metrics.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/metrics_core.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon/module_detail.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/toon_view.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/validate_project.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/exporters/yaml_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/_utils.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/llm_flow/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/llm_flow/analysis.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/llm_flow/cli.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/llm_flow/generator.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/llm_flow/nodes.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/llm_flow/parsing.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/llm_flow/utils.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/llm_flow.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/llm_task.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/mermaid/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/mermaid/fix.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/mermaid/validation.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/generators/mermaid.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/nlp/config.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/nlp/entity_resolution.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/nlp/intent_matching.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/nlp/normalization.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/nlp/pipeline.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/parsers/toon_parser.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/patterns/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/patterns/detector.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/refactor/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm/refactor/prompt_engine.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm.egg-info/dependency_links.txt +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm.egg-info/entry_points.txt +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm.egg-info/requires.txt +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/code2llm.egg-info/top_level.txt +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/setup.cfg +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/setup.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_advanced_analysis.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_analyzer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_cache_invalidation_e2e.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_calls_toon_export.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_declarative_collection.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_deep_analysis.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_edge_cases.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_export_cache_flags.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_file_analyzer_tagging.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_flow_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_multilanguage_e2e.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_nlp_pipeline.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_nonpython_cc_calls.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_orchestrator_cache_mtime.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_persistent_cache.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_pipeline_detector.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_planfile_tickets_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_project_toon_export.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_prompt_engine.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_prompt_txt.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_refactoring_engine.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_smells_data_clumps.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/tests/test_smells_shotgun_surgery.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.175}/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.175
|
|
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: Tom Sapletta
|
|
@@ -67,13 +67,13 @@ Dynamic: requires-python
|
|
|
67
67
|
|
|
68
68
|
## AI Cost Tracking
|
|
69
69
|
|
|
70
|
-
    
|
|
71
|
+
  
|
|
72
72
|
|
|
73
|
-
- 🤖 **LLM usage:** $
|
|
74
|
-
- 👤 **Human dev:** ~$
|
|
73
|
+
- 🤖 **LLM usage:** $3.8035 (262 commits)
|
|
74
|
+
- 👤 **Human dev:** ~$10435 (104.3h @ $100/h, 30min dedup)
|
|
75
75
|
|
|
76
|
-
Generated on 2026-
|
|
76
|
+
Generated on 2026-08-01 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/deep/deep-v4-pro)
|
|
77
77
|
|
|
78
78
|
---
|
|
79
79
|
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## AI Cost Tracking
|
|
4
4
|
|
|
5
|
-
    
|
|
6
|
+
  
|
|
7
7
|
|
|
8
|
-
- 🤖 **LLM usage:** $
|
|
9
|
-
- 👤 **Human dev:** ~$
|
|
8
|
+
- 🤖 **LLM usage:** $3.8035 (262 commits)
|
|
9
|
+
- 👤 **Human dev:** ~$10435 (104.3h @ $100/h, 30min dedup)
|
|
10
10
|
|
|
11
|
-
Generated on 2026-
|
|
11
|
+
Generated on 2026-08-01 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/deep/deep-v4-pro)
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
code2llm-0.5.175/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.5.175
|
|
@@ -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.175"
|
|
12
12
|
__author__ = "STTS Project"
|
|
13
13
|
|
|
14
14
|
# Core analysis components (lightweight, always needed)
|
|
@@ -42,6 +42,10 @@ def _build_export_config(args, formats: List[str]) -> Dict[str, Any]:
|
|
|
42
42
|
"""Build config dict for export caching."""
|
|
43
43
|
return {
|
|
44
44
|
"formats": sorted(formats),
|
|
45
|
+
"mode": getattr(args, "mode", None),
|
|
46
|
+
"strategy": getattr(args, "strategy", None),
|
|
47
|
+
"exclude": sorted(str(item) for item in (getattr(args, "exclude", None) or [])),
|
|
48
|
+
"gitignore": getattr(args, "gitignore", None),
|
|
45
49
|
"png": getattr(args, "png", False),
|
|
46
50
|
"no_png": getattr(args, "no_png", False),
|
|
47
51
|
"flow_include_examples": getattr(args, "flow_include_examples", False),
|
|
@@ -7,6 +7,8 @@ Provides:
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from abc import ABC, abstractmethod
|
|
10
|
+
import os
|
|
11
|
+
import tempfile
|
|
10
12
|
from pathlib import Path
|
|
11
13
|
from typing import Any, Dict, Optional, Type, ClassVar
|
|
12
14
|
from code2llm.core.models import AnalysisResult
|
|
@@ -80,9 +82,31 @@ class BaseExporter(ABC):
|
|
|
80
82
|
return path
|
|
81
83
|
|
|
82
84
|
def _write_text(self, output_path: str, content: str) -> Path:
|
|
83
|
-
"""
|
|
85
|
+
"""Atomically write text content, ensuring the directory exists.
|
|
86
|
+
|
|
87
|
+
Analysis artifacts are consumed by background tools immediately after
|
|
88
|
+
generation. A same-directory temporary file plus ``os.replace`` keeps
|
|
89
|
+
readers from observing a truncated map while an export is in progress.
|
|
90
|
+
"""
|
|
84
91
|
path = self._ensure_dir(output_path)
|
|
85
|
-
|
|
92
|
+
temporary = None
|
|
93
|
+
try:
|
|
94
|
+
with tempfile.NamedTemporaryFile(
|
|
95
|
+
mode="w",
|
|
96
|
+
encoding="utf-8",
|
|
97
|
+
dir=path.parent,
|
|
98
|
+
prefix=f".{path.name}.",
|
|
99
|
+
suffix=".tmp",
|
|
100
|
+
delete=False,
|
|
101
|
+
) as handle:
|
|
102
|
+
handle.write(content)
|
|
103
|
+
handle.flush()
|
|
104
|
+
os.fsync(handle.fileno())
|
|
105
|
+
temporary = Path(handle.name)
|
|
106
|
+
os.replace(temporary, path)
|
|
107
|
+
finally:
|
|
108
|
+
if temporary is not None:
|
|
109
|
+
temporary.unlink(missing_ok=True)
|
|
86
110
|
return path
|
|
87
111
|
|
|
88
112
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Stałe dla FlowExporter.
|
|
2
|
+
|
|
3
|
+
Zawiera progi, wzorce wykluczeń i rekomendacje dotyczące podziału typów hub.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from functools import lru_cache
|
|
7
|
+
|
|
8
|
+
# Progi dla wykrywania problemów
|
|
9
|
+
CC_HIGH = 15
|
|
10
|
+
FAN_OUT_THRESHOLD = 10
|
|
11
|
+
HUB_TYPE_THRESHOLD = 10
|
|
12
|
+
|
|
13
|
+
# Wzorce do wykluczenia (venv, cache, etc.)
|
|
14
|
+
EXCLUDE_PATTERNS = {
|
|
15
|
+
"venv",
|
|
16
|
+
".venv",
|
|
17
|
+
"env",
|
|
18
|
+
".env",
|
|
19
|
+
"publish-env",
|
|
20
|
+
"test-env",
|
|
21
|
+
"site-packages",
|
|
22
|
+
"node_modules",
|
|
23
|
+
"__pycache__",
|
|
24
|
+
".git",
|
|
25
|
+
"dist",
|
|
26
|
+
"build",
|
|
27
|
+
"egg-info",
|
|
28
|
+
".tox",
|
|
29
|
+
".mypy_cache",
|
|
30
|
+
# Backup directories that often contain nested venvs
|
|
31
|
+
".algitex",
|
|
32
|
+
".backup",
|
|
33
|
+
"backups",
|
|
34
|
+
".bak",
|
|
35
|
+
# Additional venv patterns
|
|
36
|
+
"virtualenv",
|
|
37
|
+
".virtualenv",
|
|
38
|
+
"envs",
|
|
39
|
+
".envs",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# Paths where duplicate class names are intentional (twin sites, examples, contracts).
|
|
43
|
+
# Excluded from duplicate *detection* only — other metrics still apply.
|
|
44
|
+
INTENTIONAL_DUP_COPY_MARKERS: tuple[str, ...] = (
|
|
45
|
+
"pc1/",
|
|
46
|
+
"pc2/",
|
|
47
|
+
"examples/",
|
|
48
|
+
"-contract-",
|
|
49
|
+
"work/repos/",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# These repositories are deliberately separate execution planes. Classes with
|
|
53
|
+
# similar infrastructure-shaped APIs across two different agents are not
|
|
54
|
+
# consolidation candidates: sharing their implementations would couple the
|
|
55
|
+
# independent diagnostic, repair, and validation boundaries.
|
|
56
|
+
INDEPENDENT_AGENT_REPOSITORIES = frozenset(
|
|
57
|
+
{"doctor-agent", "repair-agent", "validator-agent"}
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@lru_cache(maxsize=4096)
|
|
62
|
+
def is_intentional_duplicate_copy(path: str) -> bool:
|
|
63
|
+
"""True when *path* is an intentional parallel copy (not actionable duplication)."""
|
|
64
|
+
if not path:
|
|
65
|
+
return False
|
|
66
|
+
norm = path.replace("\\", "/").lower()
|
|
67
|
+
return any(marker in norm for marker in INTENTIONAL_DUP_COPY_MARKERS)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@lru_cache(maxsize=4096)
|
|
71
|
+
def _independent_agent_repository(path: str) -> str | None:
|
|
72
|
+
"""Return the independent agent repository segment present in *path*."""
|
|
73
|
+
if not path:
|
|
74
|
+
return None
|
|
75
|
+
parts = path.replace("\\", "/").lower().split("/")
|
|
76
|
+
return next((part for part in parts if part in INDEPENDENT_AGENT_REPOSITORIES), None)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@lru_cache(maxsize=4096)
|
|
80
|
+
def is_intentional_duplicate_pair(path_a: str, path_b: str) -> bool:
|
|
81
|
+
"""True when two similar classes belong to intentionally parallel copies."""
|
|
82
|
+
if is_intentional_duplicate_copy(path_a) or is_intentional_duplicate_copy(path_b):
|
|
83
|
+
return True
|
|
84
|
+
repo_a = _independent_agent_repository(path_a)
|
|
85
|
+
repo_b = _independent_agent_repository(path_b)
|
|
86
|
+
return repo_a is not None and repo_b is not None and repo_a != repo_b
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@lru_cache(maxsize=4096)
|
|
90
|
+
def is_excluded_path(path: str) -> bool:
|
|
91
|
+
"""Return True if *path* matches any standard exclusion pattern (venv, cache, etc.)."""
|
|
92
|
+
if not path:
|
|
93
|
+
return False
|
|
94
|
+
parts = set(path.lower().replace("\\", "/").split("/"))
|
|
95
|
+
return bool(parts & EXCLUDE_PATTERNS)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# Rekomendacje podziału typów hub: typ -> sugerowane pod-interfejsy
|
|
99
|
+
HUB_SPLIT_RECOMMENDATIONS = {
|
|
100
|
+
"AnalysisResult": [
|
|
101
|
+
"StructureResult (modules, classes, functions)",
|
|
102
|
+
"MetricsResult (complexity, coupling)",
|
|
103
|
+
"FlowResult (call_graph, cfg, dfg)",
|
|
104
|
+
],
|
|
105
|
+
"dict": ["replace with typed alternatives (dataclass/TypedDict)"],
|
|
106
|
+
"str": [], # primitive, expected to be ubiquitous
|
|
107
|
+
"list": [],
|
|
108
|
+
"Any": [],
|
|
109
|
+
}
|
|
@@ -8,6 +8,8 @@ from code2llm.core.models import AnalysisResult, FunctionInfo, ModuleInfo
|
|
|
8
8
|
from .utils import count_total_lines, detect_languages
|
|
9
9
|
from .alerts import build_alerts, build_hotspots, load_evolution_trend
|
|
10
10
|
|
|
11
|
+
MAP_PRODUCER_HEADER = "# producer: code2llm | artifact: map.toon.yaml | schema: 1"
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
def render_header(
|
|
13
15
|
result: AnalysisResult, output_path: str, is_excluded_path
|
|
@@ -38,6 +40,7 @@ def render_header(
|
|
|
38
40
|
|
|
39
41
|
lines = [
|
|
40
42
|
f"# {project_name} | {stats_line['files']}f {stats_line['lines']}L | {lang_str} | {datetime.now().strftime('%Y-%m-%d')}", # noqa: E501
|
|
43
|
+
MAP_PRODUCER_HEADER,
|
|
41
44
|
f"# stats: {stats_line['funcs']} func | {stats_line['classes']} cls | {stats_line['files']} mod | CC̄={stats_line['avg_cc']} | critical:{stats_line['critical']} | cycles:{stats_line['cycles']}", # noqa: E501
|
|
42
45
|
alerts_line,
|
|
43
46
|
hotspots_line,
|
|
@@ -78,4 +81,4 @@ def _render_hotspots_line(funcs: List[FunctionInfo]) -> str:
|
|
|
78
81
|
return f"# hotspots[{len(hotspots)}]: {'; '.join(hotspots) if hotspots else 'none'}"
|
|
79
82
|
|
|
80
83
|
|
|
81
|
-
__all__ = ["render_header"]
|
|
84
|
+
__all__ = ["MAP_PRODUCER_HEADER", "render_header"]
|
|
@@ -41,10 +41,7 @@ class MapExporter(BaseExporter):
|
|
|
41
41
|
lines.extend(render_module_list(result, is_excluded_path))
|
|
42
42
|
lines.extend(render_details(result, is_excluded_path))
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
with open(path, "w", encoding="utf-8") as f:
|
|
46
|
-
f.write("\n".join(lines) + "\n")
|
|
47
|
-
return path
|
|
44
|
+
return self._write_text(output_path, "\n".join(lines) + "\n")
|
|
48
45
|
|
|
49
46
|
def export_to_yaml(
|
|
50
47
|
self, result: AnalysisResult, output_path: str, **kwargs
|
|
@@ -256,9 +256,54 @@ def _god_module_tickets(result: AnalysisResult) -> list[PlanfileTicketSuggestion
|
|
|
256
256
|
|
|
257
257
|
|
|
258
258
|
def _duplicate_class_tickets(result: AnalysisResult) -> list[PlanfileTicketSuggestion]:
|
|
259
|
-
"""Yield deduplication
|
|
259
|
+
"""Yield one deduplication ticket per duplicate *class name group* (not per pair)."""
|
|
260
|
+
from collections import defaultdict
|
|
261
|
+
|
|
262
|
+
from code2llm.exporters.flow_constants import is_intentional_duplicate_copy
|
|
263
|
+
|
|
264
|
+
pairs = _duplicate_class_pairs(result)
|
|
265
|
+
groups: dict[str, set[str]] = defaultdict(set)
|
|
266
|
+
for left_name, left_file, right_file in pairs:
|
|
267
|
+
groups[left_name].add(left_file)
|
|
268
|
+
groups[left_name].add(right_file)
|
|
269
|
+
|
|
260
270
|
tickets: list[PlanfileTicketSuggestion] = []
|
|
261
|
-
|
|
271
|
+
for class_name, files in sorted(groups.items()):
|
|
272
|
+
rel_files = tuple(sorted(files))
|
|
273
|
+
if all(is_intentional_duplicate_copy(f) for f in rel_files):
|
|
274
|
+
continue
|
|
275
|
+
tickets.append(
|
|
276
|
+
PlanfileTicketSuggestion(
|
|
277
|
+
signal="code2llm_dup",
|
|
278
|
+
title=f"Consolidate duplicate class {class_name}",
|
|
279
|
+
description=(
|
|
280
|
+
f"code2llm found `{class_name}` in {len(rel_files)} files: "
|
|
281
|
+
f"{', '.join(rel_files)}.\n\n"
|
|
282
|
+
"Extract a shared base/helper or merge the duplicated behavior, then "
|
|
283
|
+
"re-run code2llm to confirm the duplicate signal is gone."
|
|
284
|
+
),
|
|
285
|
+
priority="high",
|
|
286
|
+
labels=("llm-ready", "code2llm", "duplication", "refactor"),
|
|
287
|
+
files=rel_files,
|
|
288
|
+
dedupe_key=f"code2llm:dup:{class_name}",
|
|
289
|
+
),
|
|
290
|
+
)
|
|
291
|
+
return tickets
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _duplicate_class_pairs(result: AnalysisResult) -> list[tuple[str, str, str]]:
|
|
295
|
+
"""Return (class_name, file_a, file_b) for each similar class pair."""
|
|
296
|
+
from code2llm.exporters.flow_constants import (
|
|
297
|
+
is_intentional_duplicate_copy,
|
|
298
|
+
is_intentional_duplicate_pair,
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
pairs: list[tuple[str, str, str]] = []
|
|
302
|
+
classes = [
|
|
303
|
+
c
|
|
304
|
+
for c in result.classes.values()
|
|
305
|
+
if not is_intentional_duplicate_copy(c.file)
|
|
306
|
+
]
|
|
262
307
|
for index, left in enumerate(classes):
|
|
263
308
|
left_methods = _method_names(left)
|
|
264
309
|
if len(left_methods) < 3:
|
|
@@ -266,6 +311,8 @@ def _duplicate_class_tickets(result: AnalysisResult) -> list[PlanfileTicketSugge
|
|
|
266
311
|
for right in classes[index + 1 :]:
|
|
267
312
|
if left.name != right.name:
|
|
268
313
|
continue
|
|
314
|
+
if is_intentional_duplicate_pair(left.file, right.file):
|
|
315
|
+
continue
|
|
269
316
|
right_methods = _method_names(right)
|
|
270
317
|
if len(right_methods) < 3:
|
|
271
318
|
continue
|
|
@@ -275,23 +322,8 @@ def _duplicate_class_tickets(result: AnalysisResult) -> list[PlanfileTicketSugge
|
|
|
275
322
|
continue
|
|
276
323
|
left_file = _rel_path(left.file, result.project_path)
|
|
277
324
|
right_file = _rel_path(right.file, result.project_path)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
signal="code2llm_dup",
|
|
281
|
-
title=f"Consolidate duplicate class {left.name}",
|
|
282
|
-
description=(
|
|
283
|
-
f"code2llm found similar `{left.name}` classes in `{left_file}` "
|
|
284
|
-
f"and `{right_file}` with {len(overlap)} overlapping methods.\n\n"
|
|
285
|
-
"Extract a shared base/helper or merge the duplicated behavior, then "
|
|
286
|
-
"re-run code2llm to confirm the duplicate signal is gone."
|
|
287
|
-
),
|
|
288
|
-
priority="high",
|
|
289
|
-
labels=("llm-ready", "code2llm", "duplication", "refactor"),
|
|
290
|
-
files=(left_file, right_file),
|
|
291
|
-
dedupe_key=f"code2llm:dup:{left.name}:{left_file}:{right_file}",
|
|
292
|
-
),
|
|
293
|
-
)
|
|
294
|
-
return tickets
|
|
325
|
+
pairs.append((left.name, left_file, right_file))
|
|
326
|
+
return pairs
|
|
295
327
|
|
|
296
328
|
|
|
297
329
|
def _smell_tickets(result: AnalysisResult) -> list[PlanfileTicketSuggestion]:
|
|
@@ -54,7 +54,8 @@ def _build_refactor_steps(ctx: Dict[str, Any]) -> List[str]:
|
|
|
54
54
|
"""Build list of refactoring step strings from health, duplicates, and cycles."""
|
|
55
55
|
steps: List[str] = []
|
|
56
56
|
if ctx["duplicates"]:
|
|
57
|
-
|
|
57
|
+
group_count = len({d["class_name"] for d in ctx["duplicates"]})
|
|
58
|
+
steps.append(f"rm duplicates (-{group_count} dup groups)")
|
|
58
59
|
for gi in [h for h in ctx["health"] if h["code"] == "GOD"]:
|
|
59
60
|
steps.append(f"split {gi['message'].split('=')[0].strip()} (god module)")
|
|
60
61
|
cc_issues = [h for h in ctx["health"] if h["code"] == "CC"]
|
|
@@ -5,7 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
from typing import Any, Dict, Set
|
|
6
6
|
|
|
7
7
|
from code2llm.core.models import AnalysisResult, FunctionInfo
|
|
8
|
-
from code2llm.exporters.flow_constants import is_excluded_path
|
|
8
|
+
from code2llm.exporters.flow_constants import is_excluded_path, is_intentional_duplicate_copy
|
|
9
9
|
|
|
10
10
|
# Re-export is_excluded_path from flow_constants to eliminate duplication
|
|
11
11
|
|
|
@@ -7,7 +7,9 @@ from typing import Any, Dict, List, Optional, Set
|
|
|
7
7
|
|
|
8
8
|
from code2llm.core.models import AnalysisResult, ClassInfo
|
|
9
9
|
|
|
10
|
-
from .
|
|
10
|
+
from code2llm.exporters.flow_constants import is_intentional_duplicate_pair
|
|
11
|
+
|
|
12
|
+
from .helpers import _is_excluded, _rel_path, is_intentional_duplicate_copy
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
class DuplicatesMetricsComputer:
|
|
@@ -22,7 +24,9 @@ class DuplicatesMetricsComputer:
|
|
|
22
24
|
dupes: List[Dict[str, Any]] = []
|
|
23
25
|
# Filter out excluded classes first
|
|
24
26
|
class_list = [
|
|
25
|
-
(q, c)
|
|
27
|
+
(q, c)
|
|
28
|
+
for q, c in result.classes.items()
|
|
29
|
+
if not _is_excluded(c.file) and not is_intentional_duplicate_copy(c.file)
|
|
26
30
|
]
|
|
27
31
|
|
|
28
32
|
for i, (qa, ca) in enumerate(class_list):
|
|
@@ -45,6 +49,8 @@ class DuplicatesMetricsComputer:
|
|
|
45
49
|
qb, cb = class_list[j]
|
|
46
50
|
if ca.name != cb.name:
|
|
47
51
|
continue
|
|
52
|
+
if is_intentional_duplicate_pair(ca.file, cb.file):
|
|
53
|
+
continue
|
|
48
54
|
|
|
49
55
|
methods_b = {m.split(".")[-1] for m in cb.methods}
|
|
50
56
|
if len(methods_b) < 3:
|
|
@@ -31,21 +31,23 @@ class HealthMetricsComputer:
|
|
|
31
31
|
return issues[:20] # MAX_HEALTH_ISSUES
|
|
32
32
|
|
|
33
33
|
def _check_duplicates_health(self, ctx, issues):
|
|
34
|
-
"""Check for duplicate classes."""
|
|
35
|
-
|
|
34
|
+
"""Check for duplicate classes (report merged name-groups, not pair count)."""
|
|
35
|
+
dupes = ctx["duplicates"]
|
|
36
|
+
group_names = {d.get("class_name") for d in dupes if d.get("class_name")}
|
|
37
|
+
ndups = len(group_names)
|
|
36
38
|
if ndups > 0:
|
|
37
39
|
dup_lines = sum(
|
|
38
40
|
ctx["files"].get(d.get("fileA_abs", ""), {}).get("lines", 0)
|
|
39
|
-
for d in
|
|
41
|
+
for d in dupes
|
|
40
42
|
)
|
|
41
43
|
issues.append(
|
|
42
44
|
{
|
|
43
45
|
"severity": "red",
|
|
44
46
|
"code": "DUP",
|
|
45
|
-
"message": f"{ndups}
|
|
47
|
+
"message": f"{ndups} duplicate class groups ({dup_lines}L wasted)"
|
|
46
48
|
if dup_lines
|
|
47
|
-
else f"{ndups}
|
|
48
|
-
"impact": f"-{ndups} dup
|
|
49
|
+
else f"{ndups} duplicate class groups",
|
|
50
|
+
"impact": f"-{ndups} dup groups",
|
|
49
51
|
}
|
|
50
52
|
)
|
|
51
53
|
|
|
@@ -41,7 +41,7 @@ class ToonRenderer:
|
|
|
41
41
|
all_cc = [f["cc"] for f in ctx["func_metrics"]]
|
|
42
42
|
avg_cc = round(sum(all_cc) / len(all_cc), 1) if all_cc else 0.0
|
|
43
43
|
critical = len([f for f in ctx["func_metrics"] if f["cc"] >= CC_CRITICAL])
|
|
44
|
-
ndups = len(ctx["duplicates"])
|
|
44
|
+
ndups = len({d["class_name"] for d in ctx["duplicates"]})
|
|
45
45
|
ncycles = len(ctx["cycles"])
|
|
46
46
|
lang_label = _detect_language_label(result)
|
|
47
47
|
return [
|
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import subprocess
|
|
5
5
|
import tempfile
|
|
6
6
|
import json
|
|
7
|
+
import shutil
|
|
7
8
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from typing import List, Optional
|
|
@@ -17,6 +18,38 @@ from .validation import validate_mermaid_file
|
|
|
17
18
|
from .fix import fix_mermaid_file
|
|
18
19
|
|
|
19
20
|
|
|
21
|
+
_BROWSER_ENV_VARS = (
|
|
22
|
+
"PUPPETEER_EXECUTABLE_PATH",
|
|
23
|
+
"CHROME_PATH",
|
|
24
|
+
"GOOGLE_CHROME_BIN",
|
|
25
|
+
)
|
|
26
|
+
_BROWSER_COMMANDS = (
|
|
27
|
+
"google-chrome",
|
|
28
|
+
"google-chrome-stable",
|
|
29
|
+
"chromium",
|
|
30
|
+
"chromium-browser",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _find_browser_executable() -> Optional[str]:
|
|
35
|
+
"""Return an explicit Chrome/Chromium path suitable for Puppeteer.
|
|
36
|
+
|
|
37
|
+
Mermaid CLI bundles puppeteer-core, which does not download Chromium on
|
|
38
|
+
installation. Prefer an explicitly configured browser and otherwise use
|
|
39
|
+
the system browser already available on the PATH.
|
|
40
|
+
"""
|
|
41
|
+
for variable in _BROWSER_ENV_VARS:
|
|
42
|
+
candidate = os.getenv(variable)
|
|
43
|
+
if candidate and Path(candidate).is_file() and os.access(candidate, os.X_OK):
|
|
44
|
+
return candidate
|
|
45
|
+
|
|
46
|
+
for command in _BROWSER_COMMANDS:
|
|
47
|
+
candidate = shutil.which(command)
|
|
48
|
+
if candidate:
|
|
49
|
+
return candidate
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
|
|
20
53
|
def _is_png_fresh(mmd_file: Path, output_dir: Path) -> bool:
|
|
21
54
|
"""Check if PNG exists and is newer than MMD source."""
|
|
22
55
|
png_file = output_dir / f"{mmd_file.stem}.png"
|
|
@@ -115,6 +148,9 @@ def _setup_puppeteer_config() -> tuple[int, int, Optional[str], Optional[str]]:
|
|
|
115
148
|
puppeteer_cfg = {
|
|
116
149
|
"args": ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
117
150
|
}
|
|
151
|
+
browser_executable = _find_browser_executable()
|
|
152
|
+
if browser_executable:
|
|
153
|
+
puppeteer_cfg["executablePath"] = browser_executable
|
|
118
154
|
with tempfile.NamedTemporaryFile(
|
|
119
155
|
mode="w", suffix=".json", delete=False
|
|
120
156
|
) as tmp_pcfg:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2llm
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.175
|
|
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: Tom Sapletta
|
|
@@ -67,13 +67,13 @@ Dynamic: requires-python
|
|
|
67
67
|
|
|
68
68
|
## AI Cost Tracking
|
|
69
69
|
|
|
70
|
-
    
|
|
71
|
+
  
|
|
72
72
|
|
|
73
|
-
- 🤖 **LLM usage:** $
|
|
74
|
-
- 👤 **Human dev:** ~$
|
|
73
|
+
- 🤖 **LLM usage:** $3.8035 (262 commits)
|
|
74
|
+
- 👤 **Human dev:** ~$10435 (104.3h @ $100/h, 30min dedup)
|
|
75
75
|
|
|
76
|
-
Generated on 2026-
|
|
76
|
+
Generated on 2026-08-01 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/deep/deep-v4-pro)
|
|
77
77
|
|
|
78
78
|
---
|
|
79
79
|
|
|
@@ -186,11 +186,14 @@ tests/test_cache_invalidation_e2e.py
|
|
|
186
186
|
tests/test_calls_toon_export.py
|
|
187
187
|
tests/test_declarative_collection.py
|
|
188
188
|
tests/test_deep_analysis.py
|
|
189
|
+
tests/test_dup_groups.py
|
|
189
190
|
tests/test_edge_cases.py
|
|
190
191
|
tests/test_export_cache_flags.py
|
|
192
|
+
tests/test_export_profile_contract.py
|
|
191
193
|
tests/test_file_analyzer_tagging.py
|
|
192
194
|
tests/test_flow_exporter.py
|
|
193
195
|
tests/test_format_quality.py
|
|
196
|
+
tests/test_mermaid_png.py
|
|
194
197
|
tests/test_multilanguage_e2e.py
|
|
195
198
|
tests/test_nlp_pipeline.py
|
|
196
199
|
tests/test_nonpython_cc_calls.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code2llm"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.175"
|
|
8
8
|
description = "High-performance Python code flow analysis with optimized TOON format - CFG, DFG, call graphs, and intelligent code queries"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|