code2llm 0.5.123__tar.gz → 0.5.125__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.123 → code2llm-0.5.125}/PKG-INFO +2 -2
- {code2llm-0.5.123 → code2llm-0.5.125}/README.md +1 -1
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/__init__.py +1 -1
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/cli_analysis.py +4 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/cli_exports/orchestrator.py +53 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/analyzer.py +10 -0
- code2llm-0.5.125/code2llm/exporters/report_generators.py +76 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/generators/llm_flow.py +35 -4
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/generators/llm_task.py +35 -3
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/nlp/__init__.py +1 -1
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm.egg-info/PKG-INFO +2 -2
- {code2llm-0.5.123 → code2llm-0.5.125}/pyproject.toml +1 -1
- {code2llm-0.5.123 → code2llm-0.5.125}/setup.py +6 -1
- code2llm-0.5.123/code2llm/exporters/report_generators.py +0 -34
- {code2llm-0.5.123 → code2llm-0.5.125}/LICENSE +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/__main__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/call_graph.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/cfg.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/coupling.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/data_analysis.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/dfg.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/pipeline_classifier.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/pipeline_detector.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/pipeline_resolver.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/side_effects.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/smells.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/type_inference.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/utils/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/analysis/utils/ast_helpers.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/api.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/cli.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/cli_commands.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/cli_exports/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/cli_exports/code2logic.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/cli_exports/formats.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/cli_exports/prompt.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/cli_parser.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/ast_registry.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/config.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/export_pipeline.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/file_analyzer.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/file_cache.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/file_filter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/gitignore.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/incremental.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/base.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/cpp.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/csharp.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/generic.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/go_lang.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/java.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/php.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/ruby.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/rust.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/ts_extractors.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/ts_parser.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/lang/typescript.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/large_repo.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/models.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/persistent_cache.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/refactoring.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/repo_files.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/streaming/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/streaming/cache.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/streaming/incremental.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/streaming/prioritizer.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/streaming/scanner.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/streaming/strategies.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/streaming_analyzer.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/core/toon_size_manager.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/article_view.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/base.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/context_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/context_view.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/dashboard_data.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/dashboard_renderer.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/evolution_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/flow_constants.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/flow_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/flow_renderer.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/html_dashboard.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/index_generator/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/index_generator/renderer.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/index_generator/scanner.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/index_generator.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/json_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/llm_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/map_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/mermaid_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/mermaid_flow_helpers.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/project_yaml/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/project_yaml/constants.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/project_yaml/core.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/project_yaml/evolution.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/project_yaml/health.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/project_yaml/hotspots.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/project_yaml/modules.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/project_yaml_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/readme_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/toon/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/toon/helpers.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/toon/metrics.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/toon/metrics_core.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/toon/metrics_duplicates.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/toon/metrics_health.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/toon/module_detail.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/toon/renderer.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/toon.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/toon_view.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/validate_project.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/exporters/yaml_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/generators/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/generators/_utils.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/generators/mermaid.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/nlp/config.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/nlp/entity_resolution.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/nlp/intent_matching.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/nlp/normalization.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/nlp/pipeline.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/patterns/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/patterns/detector.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/refactor/__init__.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm/refactor/prompt_engine.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm.egg-info/SOURCES.txt +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm.egg-info/dependency_links.txt +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm.egg-info/entry_points.txt +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm.egg-info/requires.txt +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/code2llm.egg-info/top_level.txt +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/setup.cfg +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_advanced_analysis.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_analyzer.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_calls_toon_export.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_deep_analysis.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_edge_cases.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_flow_exporter.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_format_quality.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_multilanguage_e2e.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_nlp_pipeline.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_nonpython_cc_calls.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_persistent_cache.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_pipeline_detector.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_project_toon_export.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_prompt_engine.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_prompt_txt.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/tests/test_refactoring_engine.py +0 -0
- {code2llm-0.5.123 → code2llm-0.5.125}/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.125
|
|
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
|
|
@@ -67,7 +67,7 @@ Dynamic: requires-python
|
|
|
67
67
|
|
|
68
68
|
## AI Cost Tracking
|
|
69
69
|
|
|
70
|
-
    
|
|
71
71
|
  
|
|
72
72
|
|
|
73
73
|
- 🤖 **LLM usage:** $7.5000 (166 commits)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
## AI Cost Tracking
|
|
5
5
|
|
|
6
|
-
    
|
|
7
7
|
  
|
|
8
8
|
|
|
9
9
|
- 🤖 **LLM usage:** $7.5000 (166 commits)
|
|
@@ -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.125"
|
|
12
12
|
__author__ = "STTS Project"
|
|
13
13
|
|
|
14
14
|
# Core analysis components (lightweight, always needed)
|
|
@@ -84,6 +84,10 @@ def _build_config(args, output_dir: Path):
|
|
|
84
84
|
# Persistent cache flags (read via getattr with defaults in analyzer.py)
|
|
85
85
|
no_cache = getattr(args, 'no_cache', False) or getattr(args, 'force', False)
|
|
86
86
|
config.no_cache = no_cache
|
|
87
|
+
# Watch mode for auto-detecting changed files
|
|
88
|
+
config.watch = getattr(args, 'watch', False)
|
|
89
|
+
# Dry-run mode (handled in orchestrator, but stored for reference)
|
|
90
|
+
config.dry_run = getattr(args, 'dry_run', False)
|
|
87
91
|
return config
|
|
88
92
|
|
|
89
93
|
|
|
@@ -42,6 +42,18 @@ FORMAT_FILENAMES: Dict[str, str] = {
|
|
|
42
42
|
'project-yaml': 'project.yaml',
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
# Files produced per format in dry-run preview
|
|
46
|
+
FORMAT_DRY_RUN_FILES: Dict[str, List[str]] = {
|
|
47
|
+
'toon': ['analysis.toon'],
|
|
48
|
+
'map': ['map.toon.yaml'],
|
|
49
|
+
'evolution': ['evolution.toon.yaml'],
|
|
50
|
+
'context': ['context.md'],
|
|
51
|
+
'mermaid': ['calls.mmd', 'calls.png'],
|
|
52
|
+
'yaml': ['analysis.yaml'],
|
|
53
|
+
'json': ['analysis.json'],
|
|
54
|
+
'readme': ['README.md'],
|
|
55
|
+
}
|
|
56
|
+
|
|
45
57
|
# Human-readable labels
|
|
46
58
|
FORMAT_LABELS: Dict[str, str] = {
|
|
47
59
|
'toon': 'TOON (diagnostics)',
|
|
@@ -69,6 +81,41 @@ def _build_export_config(args, formats: List[str]) -> Dict[str, Any]:
|
|
|
69
81
|
}
|
|
70
82
|
|
|
71
83
|
|
|
84
|
+
def _collect_dry_run_files(formats: List[str], output_dir: Path) -> List[Path]:
|
|
85
|
+
"""Return the list of files that would be written for the given formats."""
|
|
86
|
+
output_files: List[Path] = []
|
|
87
|
+
for fmt in formats:
|
|
88
|
+
for name in FORMAT_DRY_RUN_FILES.get(fmt, []):
|
|
89
|
+
output_files.append(output_dir / name)
|
|
90
|
+
output_files.append(output_dir / 'project.toon.yaml')
|
|
91
|
+
output_files.append(output_dir / 'prompt.txt')
|
|
92
|
+
return output_files
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _show_dry_run_plan(formats: List[str], output_dir: Path, is_chunked: bool, result) -> None:
|
|
96
|
+
"""Display what would be exported in dry-run mode."""
|
|
97
|
+
print("\n📋 DRY-RUN: Would export the following:\n")
|
|
98
|
+
|
|
99
|
+
output_files = _collect_dry_run_files(formats, output_dir)
|
|
100
|
+
|
|
101
|
+
size_hint = ""
|
|
102
|
+
func_count = len(getattr(result, 'functions', []))
|
|
103
|
+
if func_count > 0:
|
|
104
|
+
size_hint = f" (~{func_count * 50 // 1024}KB est.)"
|
|
105
|
+
|
|
106
|
+
for f in sorted(set(output_files)):
|
|
107
|
+
print(f" 📄 {f}{size_hint}")
|
|
108
|
+
|
|
109
|
+
stats = getattr(result, 'stats', {})
|
|
110
|
+
if stats:
|
|
111
|
+
print(f"\n📊 Based on analysis:")
|
|
112
|
+
print(f" - Functions: {stats.get('functions_found', 'N/A')}")
|
|
113
|
+
print(f" - Classes: {stats.get('classes_found', 'N/A')}")
|
|
114
|
+
print(f" - Files: {stats.get('files_processed', 'N/A')}")
|
|
115
|
+
|
|
116
|
+
print(f"\n✅ Dry-run complete. Use without --dry-run to export.\n")
|
|
117
|
+
|
|
118
|
+
|
|
72
119
|
def _run_exports(args, result, output_dir: Path, source_path: Optional[Path] = None):
|
|
73
120
|
"""Export analysis results in requested formats.
|
|
74
121
|
|
|
@@ -79,6 +126,12 @@ def _run_exports(args, result, output_dir: Path, source_path: Optional[Path] = N
|
|
|
79
126
|
requested_formats = [f.strip() for f in args.format.split(',')]
|
|
80
127
|
formats = _expand_all_formats(requested_formats, getattr(args, 'png', False))
|
|
81
128
|
is_chunked = getattr(args, 'chunk', False)
|
|
129
|
+
dry_run = getattr(args, 'dry_run', False)
|
|
130
|
+
|
|
131
|
+
# Dry-run: show what would be exported without writing
|
|
132
|
+
if dry_run:
|
|
133
|
+
_show_dry_run_plan(formats, output_dir, is_chunked, result)
|
|
134
|
+
return
|
|
82
135
|
|
|
83
136
|
# Skip cache for chunked or when explicitly disabled
|
|
84
137
|
skip_cache = is_chunked or getattr(args, 'no_cache', False)
|
|
@@ -52,6 +52,16 @@ class ProjectAnalyzer:
|
|
|
52
52
|
print(f" - Parallel: {self.config.performance.parallel_enabled}, Workers: {workers}")
|
|
53
53
|
|
|
54
54
|
pcache, cached_results, files_to_analyze = self._load_from_persistent_cache(files, project_path)
|
|
55
|
+
|
|
56
|
+
# Watch mode: show what changed
|
|
57
|
+
if getattr(self.config, 'watch', False) and files_to_analyze:
|
|
58
|
+
print(f"\n👁️ Watch mode: {len(files_to_analyze)} files changed since last run:")
|
|
59
|
+
for fp, _ in files_to_analyze[:10]:
|
|
60
|
+
print(f" • {Path(fp).name}")
|
|
61
|
+
if len(files_to_analyze) > 10:
|
|
62
|
+
print(f" ... and {len(files_to_analyze) - 10} more")
|
|
63
|
+
print()
|
|
64
|
+
|
|
55
65
|
fresh_results = self._run_analysis(files_to_analyze)
|
|
56
66
|
self._store_to_persistent_cache(pcache, files_to_analyze, fresh_results)
|
|
57
67
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Report generators — produce views from project.yaml (single source of truth).
|
|
2
|
+
|
|
3
|
+
Thin re-export module. Actual generators live in separate files:
|
|
4
|
+
toon_view.py → ToonViewGenerator → project.toon.yaml
|
|
5
|
+
context_view.py → ContextViewGenerator → context.md
|
|
6
|
+
article_view.py → ArticleViewGenerator → status.md
|
|
7
|
+
html_dashboard.py → HTMLDashboardGenerator → dashboard.html
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import yaml
|
|
11
|
+
from typing import Any, Dict
|
|
12
|
+
|
|
13
|
+
from .toon_view import ToonViewGenerator
|
|
14
|
+
from .context_view import ContextViewGenerator
|
|
15
|
+
from .article_view import ArticleViewGenerator
|
|
16
|
+
from .html_dashboard import HTMLDashboardGenerator
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def load_project_yaml(path: str) -> Dict[str, Any]:
|
|
20
|
+
"""Load and validate project.yaml with detailed error reporting."""
|
|
21
|
+
import yaml
|
|
22
|
+
from yaml.scanner import ScannerError
|
|
23
|
+
from yaml.parser import ParserError
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
27
|
+
content = f.read()
|
|
28
|
+
except FileNotFoundError:
|
|
29
|
+
raise ValueError(f"project.yaml not found: {path}")
|
|
30
|
+
except Exception as e:
|
|
31
|
+
raise ValueError(f"Cannot read project.yaml ({path}): {e}")
|
|
32
|
+
|
|
33
|
+
# Check for empty file
|
|
34
|
+
if not content.strip():
|
|
35
|
+
raise ValueError(f"project.yaml is empty: {path}")
|
|
36
|
+
|
|
37
|
+
# Try to parse YAML with detailed error reporting
|
|
38
|
+
try:
|
|
39
|
+
data = yaml.safe_load(content)
|
|
40
|
+
except ScannerError as e:
|
|
41
|
+
line = e.problem_mark.line + 1 if e.problem_mark else "?"
|
|
42
|
+
col = e.problem_mark.column if e.problem_mark else "?"
|
|
43
|
+
raise ValueError(
|
|
44
|
+
f"YAML syntax error in {path} at line {line}, column {col}: {e.problem}\n"
|
|
45
|
+
f"Hint: Check indentation and special characters (:, -, #)")
|
|
46
|
+
except ParserError as e:
|
|
47
|
+
line = e.problem_mark.line + 1 if e.problem_mark else "?"
|
|
48
|
+
raise ValueError(
|
|
49
|
+
f"YAML parse error in {path} at line {line}: {e.problem}\n"
|
|
50
|
+
f"Hint: Verify YAML structure (mapping vs list)")
|
|
51
|
+
except Exception as e:
|
|
52
|
+
raise ValueError(f"YAML error in {path}: {e}")
|
|
53
|
+
|
|
54
|
+
# Validate structure
|
|
55
|
+
if data is None:
|
|
56
|
+
raise ValueError(f"project.yaml is null/empty: {path}")
|
|
57
|
+
if not isinstance(data, dict):
|
|
58
|
+
raise ValueError(
|
|
59
|
+
f"Invalid project.yaml: expected dict/object, got {type(data).__name__} in {path}\n"
|
|
60
|
+
f"Hint: YAML must start with key-value pairs, not a list")
|
|
61
|
+
if "version" not in data:
|
|
62
|
+
raise ValueError(
|
|
63
|
+
f"Invalid project.yaml: missing required 'version' key in {path}\n"
|
|
64
|
+
f"Required keys: version, project, analysis\n"
|
|
65
|
+
f"Found keys: {list(data.keys())[:10]}")
|
|
66
|
+
|
|
67
|
+
return data
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
__all__ = [
|
|
71
|
+
"load_project_yaml",
|
|
72
|
+
"ToonViewGenerator",
|
|
73
|
+
"ContextViewGenerator",
|
|
74
|
+
"ArticleViewGenerator",
|
|
75
|
+
"HTMLDashboardGenerator",
|
|
76
|
+
]
|
|
@@ -21,11 +21,42 @@ def _strip_bom(text: str) -> str:
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def _safe_read_yaml(path: Path) -> Dict[str, Any]:
|
|
24
|
-
"""Read YAML file safely, handling BOM and type validation."""
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
"""Read YAML file safely, handling BOM and type validation with detailed errors."""
|
|
25
|
+
from yaml.scanner import ScannerError
|
|
26
|
+
from yaml.parser import ParserError
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
raw = _strip_bom(path.read_text(encoding="utf-8"))
|
|
30
|
+
except FileNotFoundError:
|
|
31
|
+
raise ValueError(f"File not found: {path}")
|
|
32
|
+
except Exception as e:
|
|
33
|
+
raise ValueError(f"Cannot read file {path}: {e}")
|
|
34
|
+
|
|
35
|
+
if not raw.strip():
|
|
36
|
+
raise ValueError(f"File is empty: {path}")
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
loaded = yaml.safe_load(raw)
|
|
40
|
+
except ScannerError as e:
|
|
41
|
+
line = e.problem_mark.line + 1 if e.problem_mark else "?"
|
|
42
|
+
col = e.problem_mark.column if e.problem_mark else "?"
|
|
43
|
+
raise ValueError(
|
|
44
|
+
f"YAML syntax error in {path} at line {line}, column {col}: {e.problem}\n"
|
|
45
|
+
f"Hint: Check indentation, avoid tabs, watch special characters (:, -, #)")
|
|
46
|
+
except ParserError as e:
|
|
47
|
+
line = e.problem_mark.line + 1 if e.problem_mark else "?"
|
|
48
|
+
raise ValueError(
|
|
49
|
+
f"YAML parse error in {path} at line {line}: {e.problem}\n"
|
|
50
|
+
f"Hint: Verify structure - are you using list where dict expected?")
|
|
51
|
+
except Exception as e:
|
|
52
|
+
raise ValueError(f"YAML error in {path}: {e}")
|
|
53
|
+
|
|
54
|
+
if loaded is None:
|
|
55
|
+
raise ValueError(f"File is null/empty YAML: {path}")
|
|
27
56
|
if not isinstance(loaded, dict):
|
|
28
|
-
raise ValueError(
|
|
57
|
+
raise ValueError(
|
|
58
|
+
f"Expected YAML mapping (dict), got {type(loaded).__name__} in {path}\n"
|
|
59
|
+
f"Hint: File must start with 'key: value' pairs, not a list")
|
|
29
60
|
return loaded
|
|
30
61
|
|
|
31
62
|
|
|
@@ -212,13 +212,45 @@ def parse_llm_task_text(text: str) -> Dict[str, Any]:
|
|
|
212
212
|
|
|
213
213
|
|
|
214
214
|
def load_input(path: Path) -> Dict[str, Any]:
|
|
215
|
-
|
|
215
|
+
"""Load input file with detailed YAML/JSON error reporting."""
|
|
216
|
+
from yaml.scanner import ScannerError
|
|
217
|
+
from yaml.parser import ParserError
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
raw = path.read_text(encoding="utf-8")
|
|
221
|
+
except FileNotFoundError:
|
|
222
|
+
raise ValueError(f"Input file not found: {path}")
|
|
223
|
+
except Exception as e:
|
|
224
|
+
raise ValueError(f"Cannot read input file {path}: {e}")
|
|
225
|
+
|
|
216
226
|
raw = _strip_bom(raw)
|
|
217
227
|
|
|
228
|
+
if not raw.strip():
|
|
229
|
+
raise ValueError(f"Input file is empty: {path}")
|
|
230
|
+
|
|
218
231
|
if path.suffix.lower() in {".yaml", ".yml"}:
|
|
219
|
-
|
|
232
|
+
try:
|
|
233
|
+
loaded = yaml.safe_load(raw)
|
|
234
|
+
except ScannerError as e:
|
|
235
|
+
line = e.problem_mark.line + 1 if e.problem_mark else "?"
|
|
236
|
+
col = e.problem_mark.column if e.problem_mark else "?"
|
|
237
|
+
raise ValueError(
|
|
238
|
+
f"YAML syntax error at line {line}, column {col}: {e.problem}\n"
|
|
239
|
+
f"Hint: Check indentation in {path}")
|
|
240
|
+
except ParserError as e:
|
|
241
|
+
line = e.problem_mark.line + 1 if e.problem_mark else "?"
|
|
242
|
+
raise ValueError(
|
|
243
|
+
f"YAML parse error at line {line}: {e.problem}\n"
|
|
244
|
+
f"Hint: Verify YAML structure in {path}")
|
|
245
|
+
except Exception as e:
|
|
246
|
+
raise ValueError(f"YAML error in {path}: {e}")
|
|
247
|
+
|
|
248
|
+
if loaded is None:
|
|
249
|
+
raise ValueError(f"YAML file is null/empty: {path}")
|
|
220
250
|
if not isinstance(loaded, dict):
|
|
221
|
-
raise ValueError(
|
|
251
|
+
raise ValueError(
|
|
252
|
+
f"YAML must be a mapping/object, got {type(loaded).__name__} in {path}\n"
|
|
253
|
+
f"Hint: File should start with 'key: value' pairs")
|
|
222
254
|
return loaded
|
|
223
255
|
|
|
224
256
|
if path.suffix.lower() == ".json":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2llm
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.125
|
|
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
|
|
@@ -67,7 +67,7 @@ Dynamic: requires-python
|
|
|
67
67
|
|
|
68
68
|
## AI Cost Tracking
|
|
69
69
|
|
|
70
|
-
    
|
|
71
71
|
  
|
|
72
72
|
|
|
73
73
|
- 🤖 **LLM usage:** $7.5000 (166 commits)
|
|
@@ -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.125"
|
|
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.8"
|
|
@@ -4,7 +4,12 @@ from setuptools import setup, find_packages
|
|
|
4
4
|
import os
|
|
5
5
|
|
|
6
6
|
# Read version
|
|
7
|
-
|
|
7
|
+
def read_version():
|
|
8
|
+
version_path = os.path.join(os.path.dirname(__file__), 'VERSION')
|
|
9
|
+
with open(version_path, 'r') as f:
|
|
10
|
+
return f.read().strip()
|
|
11
|
+
|
|
12
|
+
version = read_version()
|
|
8
13
|
|
|
9
14
|
# Read long description
|
|
10
15
|
def read_readme():
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"""Report generators — produce views from project.yaml (single source of truth).
|
|
2
|
-
|
|
3
|
-
Thin re-export module. Actual generators live in separate files:
|
|
4
|
-
toon_view.py → ToonViewGenerator → project.toon.yaml
|
|
5
|
-
context_view.py → ContextViewGenerator → context.md
|
|
6
|
-
article_view.py → ArticleViewGenerator → status.md
|
|
7
|
-
html_dashboard.py → HTMLDashboardGenerator → dashboard.html
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import yaml
|
|
11
|
-
from typing import Any, Dict
|
|
12
|
-
|
|
13
|
-
from .toon_view import ToonViewGenerator
|
|
14
|
-
from .context_view import ContextViewGenerator
|
|
15
|
-
from .article_view import ArticleViewGenerator
|
|
16
|
-
from .html_dashboard import HTMLDashboardGenerator
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def load_project_yaml(path: str) -> Dict[str, Any]:
|
|
20
|
-
"""Load and validate project.yaml."""
|
|
21
|
-
with open(path, "r", encoding="utf-8") as f:
|
|
22
|
-
data = yaml.safe_load(f)
|
|
23
|
-
if not isinstance(data, dict) or "version" not in data:
|
|
24
|
-
raise ValueError(f"Invalid project.yaml: missing 'version' key in {path}")
|
|
25
|
-
return data
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
__all__ = [
|
|
29
|
-
"load_project_yaml",
|
|
30
|
-
"ToonViewGenerator",
|
|
31
|
-
"ContextViewGenerator",
|
|
32
|
-
"ArticleViewGenerator",
|
|
33
|
-
"HTMLDashboardGenerator",
|
|
34
|
-
]
|
|
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
|
|
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
|