code2llm 0.5.173__tar.gz → 0.5.174__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.174}/PKG-INFO +6 -6
- {code2llm-0.5.173 → code2llm-0.5.174}/README.md +5 -5
- code2llm-0.5.174/VERSION +1 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/__init__.py +1 -1
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/flow_constants.py +18 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/planfile_tickets.py +46 -19
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/_render_section_helpers.py +2 -1
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/helpers.py +1 -1
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/metrics_duplicates.py +4 -2
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/metrics_health.py +8 -6
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/renderer.py +1 -1
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/nlp/__init__.py +1 -1
- {code2llm-0.5.173 → code2llm-0.5.174/code2llm.egg-info}/PKG-INFO +6 -6
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm.egg-info/SOURCES.txt +1 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/pyproject.toml +1 -1
- code2llm-0.5.174/tests/test_dup_groups.py +80 -0
- code2llm-0.5.173/VERSION +0 -1
- {code2llm-0.5.173 → code2llm-0.5.174}/LICENSE +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/MANIFEST.in +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/__main__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/_data_impl.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/call_graph.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/cfg.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/coupling.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/data_analysis.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/dfg.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/pipeline_classifier.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/pipeline_detector.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/pipeline_resolver.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/side_effects.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/smells.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/type_inference.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/utils/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/analysis/utils/ast_helpers.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/api.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_analysis.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_commands.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_exports/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_exports/code2logic.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_exports/formats.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_exports/orchestrator.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_exports/orchestrator_chunked.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_exports/orchestrator_constants.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_exports/orchestrator_handlers.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_exports/prompt.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/cli_parser.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/analyzer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/ast_registry.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/config.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/export_pipeline.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/file_analyzer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/file_cache.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/file_filter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/gitignore.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/incremental.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/_c_parser.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/_calls.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/_complexity.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/base.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/cpp.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/csharp.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/generic.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/go_lang.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/java.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/php.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/ruby.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/rust.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/ts_extractors.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/ts_parser.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/lang/typescript.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/large_repo.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/models.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/persistent_cache.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/refactoring.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/repo_files.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/source_classifier.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/streaming/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/streaming/cache.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/streaming/incremental.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/streaming/prioritizer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/streaming/scanner.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/streaming/strategies.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/streaming_analyzer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/core/toon_size_manager.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/article_view.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/base.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/context_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/context_view.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/dashboard_data.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/dashboard_renderer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/evolution/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/evolution/computation.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/evolution/constants.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/evolution/exclusion.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/evolution/render.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/evolution/yaml_export.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/evolution_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/flow_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/flow_renderer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/html_dashboard.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/index_generator/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/index_generator/renderer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/index_generator/scanner.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/index_generator.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/json_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/llm_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/map/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/map/alerts.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/map/details.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/map/header.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/map/module_list.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/map/utils.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/map/yaml_export.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/map_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/mermaid/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/mermaid/calls.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/mermaid/classic.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/mermaid/compact.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/mermaid/flow_compact.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/mermaid/flow_detailed.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/mermaid/flow_full.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/mermaid/utils.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/mermaid_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/mermaid_flow_helpers.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/project_yaml/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/project_yaml/constants.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/project_yaml/core.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/project_yaml/evolution.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/project_yaml/health.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/project_yaml/hotspots.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/project_yaml/modules.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/project_yaml_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/readme/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/readme/content.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/readme/files.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/readme/insights.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/readme/sections.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/readme_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/report_generators.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/_render_coupling_helpers.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/constants.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/metrics.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/metrics_core.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon/module_detail.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/toon_view.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/validate_project.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/exporters/yaml_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/_utils.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/llm_flow/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/llm_flow/analysis.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/llm_flow/cli.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/llm_flow/generator.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/llm_flow/nodes.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/llm_flow/parsing.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/llm_flow/utils.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/llm_flow.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/llm_task.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/mermaid/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/mermaid/fix.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/mermaid/png.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/mermaid/validation.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/generators/mermaid.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/nlp/config.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/nlp/entity_resolution.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/nlp/intent_matching.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/nlp/normalization.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/nlp/pipeline.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/parsers/toon_parser.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/patterns/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/patterns/detector.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/refactor/__init__.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm/refactor/prompt_engine.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm.egg-info/dependency_links.txt +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm.egg-info/entry_points.txt +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm.egg-info/requires.txt +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/code2llm.egg-info/top_level.txt +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/setup.cfg +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/setup.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_advanced_analysis.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_analyzer.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_cache_invalidation_e2e.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_calls_toon_export.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_declarative_collection.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_deep_analysis.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_edge_cases.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_export_cache_flags.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_file_analyzer_tagging.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_flow_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_format_quality.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_multilanguage_e2e.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_nlp_pipeline.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_nonpython_cc_calls.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_orchestrator_cache_mtime.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_persistent_cache.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_pipeline_detector.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_planfile_tickets_exporter.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_project_toon_export.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_prompt_engine.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_prompt_txt.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_refactoring_engine.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_smells_data_clumps.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/tests/test_smells_shotgun_surgery.py +0 -0
- {code2llm-0.5.173 → code2llm-0.5.174}/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.174
|
|
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.8031 (260 commits)
|
|
74
|
+
- 👤 **Human dev:** ~$10235 (102.3h @ $100/h, 30min dedup)
|
|
75
75
|
|
|
76
|
-
Generated on 2026-07-
|
|
76
|
+
Generated on 2026-07-13 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.8031 (260 commits)
|
|
9
|
+
- 👤 **Human dev:** ~$10235 (102.3h @ $100/h, 30min dedup)
|
|
10
10
|
|
|
11
|
-
Generated on 2026-07-
|
|
11
|
+
Generated on 2026-07-13 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/deep/deep-v4-pro)
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
code2llm-0.5.174/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.5.174
|
|
@@ -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.174"
|
|
12
12
|
__author__ = "STTS Project"
|
|
13
13
|
|
|
14
14
|
# Core analysis components (lightweight, always needed)
|
|
@@ -39,6 +39,24 @@ EXCLUDE_PATTERNS = {
|
|
|
39
39
|
".envs",
|
|
40
40
|
}
|
|
41
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
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@lru_cache(maxsize=4096)
|
|
53
|
+
def is_intentional_duplicate_copy(path: str) -> bool:
|
|
54
|
+
"""True when *path* is an intentional parallel copy (not actionable duplication)."""
|
|
55
|
+
if not path:
|
|
56
|
+
return False
|
|
57
|
+
norm = path.replace("\\", "/").lower()
|
|
58
|
+
return any(marker in norm for marker in INTENTIONAL_DUP_COPY_MARKERS)
|
|
59
|
+
|
|
42
60
|
|
|
43
61
|
@lru_cache(maxsize=4096)
|
|
44
62
|
def is_excluded_path(path: str) -> bool:
|
|
@@ -256,9 +256,51 @@ 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 is_intentional_duplicate_copy
|
|
297
|
+
|
|
298
|
+
pairs: list[tuple[str, str, str]] = []
|
|
299
|
+
classes = [
|
|
300
|
+
c
|
|
301
|
+
for c in result.classes.values()
|
|
302
|
+
if not is_intentional_duplicate_copy(c.file)
|
|
303
|
+
]
|
|
262
304
|
for index, left in enumerate(classes):
|
|
263
305
|
left_methods = _method_names(left)
|
|
264
306
|
if len(left_methods) < 3:
|
|
@@ -275,23 +317,8 @@ def _duplicate_class_tickets(result: AnalysisResult) -> list[PlanfileTicketSugge
|
|
|
275
317
|
continue
|
|
276
318
|
left_file = _rel_path(left.file, result.project_path)
|
|
277
319
|
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
|
|
320
|
+
pairs.append((left.name, left_file, right_file))
|
|
321
|
+
return pairs
|
|
295
322
|
|
|
296
323
|
|
|
297
324
|
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,7 @@ from typing import Any, Dict, List, Optional, Set
|
|
|
7
7
|
|
|
8
8
|
from code2llm.core.models import AnalysisResult, ClassInfo
|
|
9
9
|
|
|
10
|
-
from .helpers import _is_excluded, _rel_path
|
|
10
|
+
from .helpers import _is_excluded, _rel_path, is_intentional_duplicate_copy
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class DuplicatesMetricsComputer:
|
|
@@ -22,7 +22,9 @@ class DuplicatesMetricsComputer:
|
|
|
22
22
|
dupes: List[Dict[str, Any]] = []
|
|
23
23
|
# Filter out excluded classes first
|
|
24
24
|
class_list = [
|
|
25
|
-
(q, c)
|
|
25
|
+
(q, c)
|
|
26
|
+
for q, c in result.classes.items()
|
|
27
|
+
if not _is_excluded(c.file) and not is_intentional_duplicate_copy(c.file)
|
|
26
28
|
]
|
|
27
29
|
|
|
28
30
|
for i, (qa, ca) in enumerate(class_list):
|
|
@@ -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 [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2llm
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.174
|
|
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.8031 (260 commits)
|
|
74
|
+
- 👤 **Human dev:** ~$10235 (102.3h @ $100/h, 30min dedup)
|
|
75
75
|
|
|
76
|
-
Generated on 2026-07-
|
|
76
|
+
Generated on 2026-07-13 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/deep/deep-v4-pro)
|
|
77
77
|
|
|
78
78
|
---
|
|
79
79
|
|
|
@@ -186,6 +186,7 @@ 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
|
|
191
192
|
tests/test_file_analyzer_tagging.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.174"
|
|
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"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Regression: duplicate class groups vs pairwise pairs (IFURI-245)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from code2llm.core.models import AnalysisResult, ClassInfo
|
|
8
|
+
from code2llm.exporters.flow_constants import is_intentional_duplicate_copy
|
|
9
|
+
from code2llm.exporters.planfile_tickets import collect_planfile_tickets
|
|
10
|
+
from code2llm.exporters.toon.metrics_duplicates import DuplicatesMetricsComputer
|
|
11
|
+
from code2llm.exporters.toon.metrics_health import HealthMetricsComputer
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _worker(file: Path, pkg: str) -> ClassInfo:
|
|
15
|
+
methods = [f"{pkg}.Worker.load", f"{pkg}.Worker.save", f"{pkg}.Worker.run"]
|
|
16
|
+
return ClassInfo(
|
|
17
|
+
name="Worker",
|
|
18
|
+
qualified_name=f"{pkg}.Worker",
|
|
19
|
+
file=str(file),
|
|
20
|
+
line=1,
|
|
21
|
+
methods=methods,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_intentional_copy_paths_are_detected() -> None:
|
|
26
|
+
assert is_intentional_duplicate_copy("/repo/pc1/net-user-pl/handler.py")
|
|
27
|
+
assert is_intentional_duplicate_copy("/repo/examples/demo/foo.py")
|
|
28
|
+
assert is_intentional_duplicate_copy("/repo/urirun-contract-windowpair/x.py")
|
|
29
|
+
assert not is_intentional_duplicate_copy("/repo/app/src/handler.py")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_duplicate_groups_not_pair_count(tmp_path: Path) -> None:
|
|
33
|
+
project = tmp_path
|
|
34
|
+
result = AnalysisResult(project_path=str(project))
|
|
35
|
+
for index in range(4):
|
|
36
|
+
pkg = f"pkg{index}"
|
|
37
|
+
path = project / f"{pkg}.py"
|
|
38
|
+
path.write_text("# stub\n", encoding="utf-8")
|
|
39
|
+
result.classes[f"{pkg}.Worker"] = _worker(path, pkg)
|
|
40
|
+
|
|
41
|
+
dupes = DuplicatesMetricsComputer(str(project)).detect_duplicates(result)
|
|
42
|
+
assert len(dupes) == 6 # C(4,2) pairs for same class name
|
|
43
|
+
|
|
44
|
+
ctx = {
|
|
45
|
+
"duplicates": dupes,
|
|
46
|
+
"files": {str(project / f"pkg{i}.py"): {"lines": 10} for i in range(4)},
|
|
47
|
+
"result": result,
|
|
48
|
+
"health": [],
|
|
49
|
+
"func_metrics": [],
|
|
50
|
+
}
|
|
51
|
+
issues = HealthMetricsComputer().compute_health(ctx)
|
|
52
|
+
dup_issue = next(i for i in issues if i["code"] == "DUP")
|
|
53
|
+
assert "1 duplicate class groups" in dup_issue["message"]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_planfile_dup_ticket_uses_stable_group_dedupe_key(tmp_path: Path) -> None:
|
|
57
|
+
project = tmp_path
|
|
58
|
+
result = AnalysisResult(project_path=str(project))
|
|
59
|
+
for pkg in ("one", "two", "three"):
|
|
60
|
+
path = project / f"{pkg}.py"
|
|
61
|
+
path.write_text("# stub\n", encoding="utf-8")
|
|
62
|
+
result.classes[f"pkg.{pkg}.Worker"] = _worker(path, f"pkg.{pkg}")
|
|
63
|
+
|
|
64
|
+
dup_tickets = [t for t in collect_planfile_tickets(result) if t.signal == "code2llm_dup"]
|
|
65
|
+
assert len(dup_tickets) == 1
|
|
66
|
+
assert dup_tickets[0].dedupe_key == "code2llm:dup:Worker"
|
|
67
|
+
assert len(dup_tickets[0].files) == 3
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_examples_dir_excluded_from_duplicate_pairs(tmp_path: Path) -> None:
|
|
71
|
+
project = tmp_path
|
|
72
|
+
result = AnalysisResult(project_path=str(project))
|
|
73
|
+
for pkg in ("app/main", "examples/demo"):
|
|
74
|
+
path = project / f"{pkg}.py"
|
|
75
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
76
|
+
path.write_text("# stub\n", encoding="utf-8")
|
|
77
|
+
result.classes[f"{pkg}.Worker"] = _worker(path, pkg.replace("/", "."))
|
|
78
|
+
|
|
79
|
+
dupes = DuplicatesMetricsComputer(str(project)).detect_duplicates(result)
|
|
80
|
+
assert dupes == []
|
code2llm-0.5.173/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.5.173
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|