code2llm 0.5.55__tar.gz → 0.5.57__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.55 → code2llm-0.5.57}/PKG-INFO +13 -17
- {code2llm-0.5.55 → code2llm-0.5.57}/README.md +12 -16
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/__init__.py +1 -1
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/cli_commands.py +1 -1
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/cli_exports/formats.py +2 -2
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/cli_exports/orchestrator.py +1 -1
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/cli_exports/prompt.py +18 -15
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/cli_parser.py +9 -9
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/__init__.py +1 -1
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/index_generator.py +105 -3
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/map_exporter.py +101 -12
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/project_yaml_exporter.py +1 -1
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/readme_exporter.py +14 -22
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/report_generators.py +1 -1
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/toon/__init__.py +1 -15
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/toon/metrics.py +6 -6
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/nlp/__init__.py +1 -1
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm.egg-info/PKG-INFO +13 -17
- {code2llm-0.5.55 → code2llm-0.5.57}/pyproject.toml +1 -1
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_format_quality.py +12 -10
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_prompt_txt.py +3 -2
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_toon_v2.py +22 -16
- {code2llm-0.5.55 → code2llm-0.5.57}/LICENSE +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/__main__.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/analysis/__init__.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/analysis/call_graph.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/analysis/cfg.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/analysis/coupling.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/analysis/data_analysis.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/analysis/dfg.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/analysis/pipeline_detector.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/analysis/side_effects.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/analysis/smells.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/analysis/type_inference.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/api.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/cli.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/cli_analysis.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/cli_exports/__init__.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/cli_exports/code2logic.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/__init__.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/analyzer.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/config.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/__init__.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/file_analyzer.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/file_cache.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/file_filter.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/__init__.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/base.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/cpp.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/csharp.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/generic.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/go_lang.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/java.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/php.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/ruby.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/rust.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/lang/typescript.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/core/refactoring.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/gitignore.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/large_repo.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/models.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/repo_files.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/streaming/__init__.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/streaming/cache.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/streaming/incremental.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/streaming/prioritizer.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/streaming/scanner.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/streaming/strategies.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/streaming_analyzer.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/core/toon_size_manager.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/article_view.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/base.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/context_exporter.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/context_view.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/evolution_exporter.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/flow_constants.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/flow_exporter.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/flow_renderer.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/html_dashboard.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/json_exporter.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/llm_exporter.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/mermaid_exporter.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/toon/helpers.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/toon/module_detail.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/toon/renderer.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/toon.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/toon_view.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/validate_project.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/exporters/yaml_exporter.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/generators/__init__.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/generators/llm_flow.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/generators/llm_task.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/generators/mermaid.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/nlp/config.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/nlp/entity_resolution.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/nlp/intent_matching.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/nlp/normalization.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/nlp/pipeline.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/patterns/__init__.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/patterns/detector.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/refactor/__init__.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm/refactor/prompt_engine.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm.egg-info/SOURCES.txt +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm.egg-info/dependency_links.txt +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm.egg-info/entry_points.txt +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm.egg-info/requires.txt +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/code2llm.egg-info/top_level.txt +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/setup.cfg +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/setup.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_advanced_analysis.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_analyzer.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_deep_analysis.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_edge_cases.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_flow_exporter.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_multilanguage_e2e.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_nlp_pipeline.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_nonpython_cc_calls.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_pipeline_detector.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_prompt_engine.py +0 -0
- {code2llm-0.5.55 → code2llm-0.5.57}/tests/test_refactoring_engine.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.57
|
|
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
|
|
@@ -60,7 +60,7 @@ When you run `code2llm ./ -f all`, the following files are created:
|
|
|
60
60
|
|
|
61
61
|
| File | Format | Purpose | Key Insights |
|
|
62
62
|
|------|--------|---------|--------------|
|
|
63
|
-
| `analysis.toon` | **TOON** | **🔥 Health diagnostics** -
|
|
63
|
+
| `analysis.toon` | **TOON** | **🔥 Health diagnostics** - Health, LAYERS, COUPLING | 69 critical functions, 0 god modules |
|
|
64
64
|
|
|
65
65
|
### 🤖 LLM-Ready Documentation
|
|
66
66
|
|
|
@@ -144,8 +144,8 @@ cat evolution.toon
|
|
|
144
144
|
grep "NEXT" evolution.toon
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
-
### `flow.toon` - Data Flow Analysis
|
|
148
|
-
**Purpose**: Understand data movement through the system
|
|
147
|
+
### `flow.toon` - Legacy Data Flow Analysis
|
|
148
|
+
**Purpose**: Understand data movement through the system (legacy / explicit opt-in)
|
|
149
149
|
**Key sections**:
|
|
150
150
|
- **PIPELINES**: Data processing chains
|
|
151
151
|
- **CONTRACTS**: Function input/output contracts
|
|
@@ -160,12 +160,13 @@ grep "PIPELINES" flow.toon
|
|
|
160
160
|
grep "SIDE_EFFECTS" flow.toon
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
### `map.toon` - Structural Map
|
|
164
|
-
**Purpose**: High-level architecture overview
|
|
163
|
+
### `map.toon` - Structural Map + Project Header
|
|
164
|
+
**Purpose**: High-level architecture overview plus compact project header
|
|
165
165
|
**Key sections**:
|
|
166
166
|
- **MODULES**: All modules with basic stats
|
|
167
167
|
- **IMPORTS**: Dependency relationships
|
|
168
|
-
- **
|
|
168
|
+
- **e:** Public API exports and signatures
|
|
169
|
+
- **HEADER**: Stats, alerts, hotspots, evolution trend
|
|
169
170
|
|
|
170
171
|
**Example usage**:
|
|
171
172
|
```bash
|
|
@@ -173,17 +174,12 @@ grep "SIDE_EFFECTS" flow.toon
|
|
|
173
174
|
cat map.toon | head -50
|
|
174
175
|
|
|
175
176
|
# Find public APIs
|
|
176
|
-
grep "
|
|
177
|
+
grep "^ e:" map.toon
|
|
177
178
|
```
|
|
178
179
|
|
|
179
|
-
### `project.toon` - Project Logic (
|
|
180
|
+
### `project.toon` - Legacy Project Logic (Deprecated)
|
|
180
181
|
**Purpose**: Compact module view generated by code2logic integration
|
|
181
|
-
**
|
|
182
|
-
- **Modules list**: All project modules with file sizes
|
|
183
|
-
- **Imports**: Dependency information
|
|
184
|
-
- **Classes/Functions**: Summary counts
|
|
185
|
-
|
|
186
|
-
**When to use**: When you need a lightweight project overview combined with code2llm analysis
|
|
182
|
+
**Status**: Deprecated — the lightweight project overview is now merged into `map.toon` header
|
|
187
183
|
|
|
188
184
|
**Example usage**:
|
|
189
185
|
```bash
|
|
@@ -373,8 +369,8 @@ code2llm ./ -f yaml --separate-orphans
|
|
|
373
369
|
---
|
|
374
370
|
|
|
375
371
|
**Generated by**: `code2llm ./ -f all --readme`
|
|
376
|
-
**Analysis Date**: 2026-03-
|
|
377
|
-
**Total Functions**:
|
|
372
|
+
**Analysis Date**: 2026-03-25
|
|
373
|
+
**Total Functions**: 891
|
|
378
374
|
**Total Classes**: 106
|
|
379
375
|
**Modules**: 121
|
|
380
376
|
|
|
@@ -10,7 +10,7 @@ When you run `code2llm ./ -f all`, the following files are created:
|
|
|
10
10
|
|
|
11
11
|
| File | Format | Purpose | Key Insights |
|
|
12
12
|
|------|--------|---------|--------------|
|
|
13
|
-
| `analysis.toon` | **TOON** | **🔥 Health diagnostics** -
|
|
13
|
+
| `analysis.toon` | **TOON** | **🔥 Health diagnostics** - Health, LAYERS, COUPLING | 69 critical functions, 0 god modules |
|
|
14
14
|
|
|
15
15
|
### 🤖 LLM-Ready Documentation
|
|
16
16
|
|
|
@@ -94,8 +94,8 @@ cat evolution.toon
|
|
|
94
94
|
grep "NEXT" evolution.toon
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
### `flow.toon` - Data Flow Analysis
|
|
98
|
-
**Purpose**: Understand data movement through the system
|
|
97
|
+
### `flow.toon` - Legacy Data Flow Analysis
|
|
98
|
+
**Purpose**: Understand data movement through the system (legacy / explicit opt-in)
|
|
99
99
|
**Key sections**:
|
|
100
100
|
- **PIPELINES**: Data processing chains
|
|
101
101
|
- **CONTRACTS**: Function input/output contracts
|
|
@@ -110,12 +110,13 @@ grep "PIPELINES" flow.toon
|
|
|
110
110
|
grep "SIDE_EFFECTS" flow.toon
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
### `map.toon` - Structural Map
|
|
114
|
-
**Purpose**: High-level architecture overview
|
|
113
|
+
### `map.toon` - Structural Map + Project Header
|
|
114
|
+
**Purpose**: High-level architecture overview plus compact project header
|
|
115
115
|
**Key sections**:
|
|
116
116
|
- **MODULES**: All modules with basic stats
|
|
117
117
|
- **IMPORTS**: Dependency relationships
|
|
118
|
-
- **
|
|
118
|
+
- **e:** Public API exports and signatures
|
|
119
|
+
- **HEADER**: Stats, alerts, hotspots, evolution trend
|
|
119
120
|
|
|
120
121
|
**Example usage**:
|
|
121
122
|
```bash
|
|
@@ -123,17 +124,12 @@ grep "SIDE_EFFECTS" flow.toon
|
|
|
123
124
|
cat map.toon | head -50
|
|
124
125
|
|
|
125
126
|
# Find public APIs
|
|
126
|
-
grep "
|
|
127
|
+
grep "^ e:" map.toon
|
|
127
128
|
```
|
|
128
129
|
|
|
129
|
-
### `project.toon` - Project Logic (
|
|
130
|
+
### `project.toon` - Legacy Project Logic (Deprecated)
|
|
130
131
|
**Purpose**: Compact module view generated by code2logic integration
|
|
131
|
-
**
|
|
132
|
-
- **Modules list**: All project modules with file sizes
|
|
133
|
-
- **Imports**: Dependency information
|
|
134
|
-
- **Classes/Functions**: Summary counts
|
|
135
|
-
|
|
136
|
-
**When to use**: When you need a lightweight project overview combined with code2llm analysis
|
|
132
|
+
**Status**: Deprecated — the lightweight project overview is now merged into `map.toon` header
|
|
137
133
|
|
|
138
134
|
**Example usage**:
|
|
139
135
|
```bash
|
|
@@ -323,8 +319,8 @@ code2llm ./ -f yaml --separate-orphans
|
|
|
323
319
|
---
|
|
324
320
|
|
|
325
321
|
**Generated by**: `code2llm ./ -f all --readme`
|
|
326
|
-
**Analysis Date**: 2026-03-
|
|
327
|
-
**Total Functions**:
|
|
322
|
+
**Analysis Date**: 2026-03-25
|
|
323
|
+
**Total Functions**: 891
|
|
328
324
|
**Total Classes**: 106
|
|
329
325
|
**Modules**: 121
|
|
330
326
|
|
|
@@ -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.57"
|
|
12
12
|
__author__ = "STTS Project"
|
|
13
13
|
|
|
14
14
|
# Core analysis components (lightweight, always needed)
|
|
@@ -24,7 +24,7 @@ def handle_report_command(args_list) -> int:
|
|
|
24
24
|
"""Generate views from an existing project.yaml.
|
|
25
25
|
|
|
26
26
|
Usage:
|
|
27
|
-
code2llm report --format toon # → project.toon
|
|
27
|
+
code2llm report --format toon # → project.toon (legacy)
|
|
28
28
|
code2llm report --format context # → context.md
|
|
29
29
|
code2llm report --format article # → status.md
|
|
30
30
|
code2llm report --format html # → dashboard.html
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Format export functions — toon, map,
|
|
1
|
+
"""Format export functions — toon, map, context, yaml, json, mermaid, evolution, and legacy project-yaml/flow exports."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
@@ -101,7 +101,7 @@ def _export_simple_formats(args, result, output_dir: Path, formats):
|
|
|
101
101
|
"""Export toon, map, flow, context, yaml, json, project-yaml formats."""
|
|
102
102
|
format_map = {
|
|
103
103
|
'toon': ('analysis.toon', ToonExporter, 'TOON (diagnostics)'),
|
|
104
|
-
'map': ('map.toon', MapExporter, 'MAP (structure)'),
|
|
104
|
+
'map': ('map.toon', MapExporter, 'MAP (structure + header)'),
|
|
105
105
|
'flow': ('flow.toon', FlowExporter, 'FLOW (data-flow)'),
|
|
106
106
|
'context': ('context.md', ContextExporter, 'CONTEXT (LLM narrative)'),
|
|
107
107
|
}
|
|
@@ -25,7 +25,7 @@ def _run_exports(args, result, output_dir: Path, source_path: Optional[Path] = N
|
|
|
25
25
|
"""
|
|
26
26
|
formats = [f.strip() for f in args.format.split(',')]
|
|
27
27
|
if 'all' in formats:
|
|
28
|
-
formats = ['toon', 'map', '
|
|
28
|
+
formats = ['toon', 'map', 'context', 'yaml', 'json', 'mermaid', 'evolution']
|
|
29
29
|
|
|
30
30
|
is_chunked = args.chunk if hasattr(args, 'chunk') else False
|
|
31
31
|
|
|
@@ -78,9 +78,9 @@ def _get_prompt_paths(source_path: Optional[Path], output_dir: Path) -> Tuple[st
|
|
|
78
78
|
|
|
79
79
|
_MAIN_FILES = [
|
|
80
80
|
('analysis.toon', 'Health diagnostics - complexity metrics, god modules, coupling issues, refactoring priorities'),
|
|
81
|
+
('map.toon', 'Structural map - files, sizes, imports, exports, signatures, project header'),
|
|
81
82
|
('context.md', 'LLM narrative - architecture summary, key entry points, process flows, public API surface'),
|
|
82
83
|
('evolution.toon', 'Refactoring queue - ranked actions by impact/effort, risks, metrics targets, history'),
|
|
83
|
-
('project.toon', 'Project logic - compact module view from code2logic, file sizes, dependencies overview'),
|
|
84
84
|
('README.md', 'Documentation - complete guide to all generated files, usage examples, interpretation'),
|
|
85
85
|
]
|
|
86
86
|
|
|
@@ -121,7 +121,7 @@ def _format_size(size_bytes: int) -> str:
|
|
|
121
121
|
|
|
122
122
|
def _get_missing_files(output_dir: Path) -> List[str]:
|
|
123
123
|
"""Return names of expected main files that are missing."""
|
|
124
|
-
return [name for name, _ in _MAIN_FILES if
|
|
124
|
+
return [name for name, _ in _MAIN_FILES if not (output_dir / name).exists()]
|
|
125
125
|
|
|
126
126
|
|
|
127
127
|
def _build_subprojects_section(subprojects: list, output_dir: Path, output_rel_path: str) -> List[str]:
|
|
@@ -169,9 +169,9 @@ def _analyze_generated_files(output_dir: Path, subprojects: list = None) -> dict
|
|
|
169
169
|
"""Analyze which files were generated and determine appropriate focus areas."""
|
|
170
170
|
analysis = {
|
|
171
171
|
'has_analysis_toon': (output_dir / 'analysis.toon').exists(),
|
|
172
|
+
'has_map_toon': (output_dir / 'map.toon').exists(),
|
|
172
173
|
'has_context_md': (output_dir / 'context.md').exists(),
|
|
173
174
|
'has_evolution_toon': (output_dir / 'evolution.toon').exists(),
|
|
174
|
-
'has_project_toon': (output_dir / 'project.toon').exists(),
|
|
175
175
|
'has_readme': (output_dir / 'README.md').exists(),
|
|
176
176
|
'has_yaml': (output_dir / 'analysis.yaml').exists(),
|
|
177
177
|
'has_json': (output_dir / 'analysis.json').exists(),
|
|
@@ -194,15 +194,15 @@ def _build_dynamic_focus_areas(file_analysis: dict) -> List[str]:
|
|
|
194
194
|
|
|
195
195
|
if file_analysis['has_analysis_toon']:
|
|
196
196
|
focus_areas.append("1. **Code Health Analysis** - Review complexity metrics, god modules, coupling issues from analysis.toon")
|
|
197
|
+
|
|
198
|
+
if file_analysis['has_map_toon']:
|
|
199
|
+
focus_areas.append("2. **Structural Map** - Use map.toon to inspect imports, exports, signatures, and the project header")
|
|
197
200
|
|
|
198
201
|
if file_analysis['has_evolution_toon']:
|
|
199
|
-
focus_areas.append("
|
|
202
|
+
focus_areas.append("3. **Refactoring Priorities** - Examine ranked refactoring actions and risk assessment from evolution.toon")
|
|
200
203
|
|
|
201
204
|
if file_analysis['has_context_md']:
|
|
202
|
-
focus_areas.append("
|
|
203
|
-
|
|
204
|
-
if file_analysis['has_project_toon']:
|
|
205
|
-
focus_areas.append("4. **Project Structure** - Analyze module organization and dependencies from project.toon")
|
|
205
|
+
focus_areas.append("4. **Architecture Overview** - Understand main flows, entry points, and public API from context.md")
|
|
206
206
|
|
|
207
207
|
if file_analysis['has_yaml'] or file_analysis['has_json']:
|
|
208
208
|
focus_areas.append("5. **Structured Data** - Use machine-readable formats for automated analysis and metrics extraction")
|
|
@@ -222,20 +222,23 @@ def _build_dynamic_focus_areas(file_analysis: dict) -> List[str]:
|
|
|
222
222
|
def _build_dynamic_tasks(file_analysis: dict) -> List[str]:
|
|
223
223
|
"""Build tasks based on available files."""
|
|
224
224
|
tasks = [
|
|
225
|
-
"- Summarize the architecture and
|
|
225
|
+
"- Summarize the architecture, main flows, and structural dependencies.",
|
|
226
226
|
"- Identify the highest-risk areas and propose a refactoring plan.",
|
|
227
227
|
"- If you suggest changes, keep behavior backward compatible and provide concrete steps.",
|
|
228
228
|
]
|
|
229
229
|
|
|
230
230
|
if file_analysis['has_analysis_toon']:
|
|
231
|
-
tasks.append("- Highlight critical functions (CC ≥ 10) and
|
|
231
|
+
tasks.append("- Highlight critical functions (CC ≥ 10) and top problem areas from analysis.toon.")
|
|
232
|
+
|
|
233
|
+
if file_analysis['has_map_toon']:
|
|
234
|
+
tasks.append("- Cross-check imports, exports, and signatures against map.toon before proposing splits.")
|
|
232
235
|
|
|
233
236
|
if file_analysis['has_evolution_toon']:
|
|
234
237
|
tasks.append("- Prioritize refactoring actions by impact/effort ratio from evolution.toon.")
|
|
235
238
|
|
|
236
239
|
if file_analysis['has_context_md']:
|
|
237
240
|
tasks.append("- Validate entry points and public API surface match the architecture described.")
|
|
238
|
-
|
|
241
|
+
|
|
239
242
|
if file_analysis['is_chunked']:
|
|
240
243
|
tasks.append("- Analyze cross-chunk dependencies and suggest consolidation strategies.")
|
|
241
244
|
|
|
@@ -267,12 +270,12 @@ def _build_prompt_footer(chunked: bool = False, file_analysis: dict = None) -> L
|
|
|
267
270
|
if file_analysis['file_count'] > 0:
|
|
268
271
|
lines.append("")
|
|
269
272
|
lines.append("Analysis Strategy:")
|
|
270
|
-
if file_analysis['has_analysis_toon'] and file_analysis['
|
|
271
|
-
lines.append("- Start with analysis.toon for health metrics, then
|
|
273
|
+
if file_analysis['has_analysis_toon'] and file_analysis['has_map_toon']:
|
|
274
|
+
lines.append("- Start with analysis.toon for health metrics, then map.toon for structure and signatures")
|
|
275
|
+
if file_analysis['has_evolution_toon']:
|
|
276
|
+
lines.append("- Finish with evolution.toon for action priorities and next steps")
|
|
272
277
|
elif file_analysis['has_context_md']:
|
|
273
278
|
lines.append("- Use context.md as the primary reference for architectural understanding")
|
|
274
|
-
elif file_analysis['has_project_toon']:
|
|
275
|
-
lines.append("- Begin with project.toon for structural overview")
|
|
276
279
|
|
|
277
280
|
if file_analysis['has_yaml']:
|
|
278
281
|
lines.append("- Reference analysis.yaml for precise metrics and programmatic data")
|
|
@@ -14,10 +14,10 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
14
14
|
epilog='''
|
|
15
15
|
Examples:
|
|
16
16
|
code2llm ./ # Default: TOON diagnostics + README
|
|
17
|
-
code2llm ./ -f all -o ./docs #
|
|
18
|
-
code2llm ./ -f toon,map,
|
|
17
|
+
code2llm ./ -f all -o ./docs # Core formats to ./docs/
|
|
18
|
+
code2llm ./ -f toon,map,evolution # Consolidated diagnostics + structure + roadmap
|
|
19
19
|
code2llm ./ -f context # LLM narrative (context.md)
|
|
20
|
-
code2llm ./ --streaming --strategy deep -f all # Deep streaming analysis,
|
|
20
|
+
code2llm ./ --streaming --strategy deep -f all # Deep streaming analysis, core outputs
|
|
21
21
|
code2llm ./ --strategy quick -f toon # Fast overview
|
|
22
22
|
code2llm ./ --refactor # AI refactoring prompts
|
|
23
23
|
code2llm ./ --refactor --smell god_function # Filter by smell type
|
|
@@ -27,23 +27,23 @@ Examples:
|
|
|
27
27
|
code2llm ./ -m static -v -o ./analysis # Static mode, verbose
|
|
28
28
|
code2llm ./ --no-readme # Disable README generation
|
|
29
29
|
code2llm ./ -f project-yaml # Unified project.yaml (single source of truth)
|
|
30
|
-
code2llm report --format toon # Generate
|
|
30
|
+
code2llm report --format toon # Generate legacy project.toon from project.yaml
|
|
31
31
|
code2llm report --format all # All views from project.yaml
|
|
32
32
|
code2llm llm-flow # Generate LLM flow summary
|
|
33
33
|
code2llm llm-context ./ # Generate LLM context only
|
|
34
34
|
|
|
35
35
|
Format Options (-f):
|
|
36
36
|
toon — Health diagnostics (analysis.toon) [default]
|
|
37
|
-
map — Structural map (map.toon) — modules, imports, signatures
|
|
38
|
-
|
|
37
|
+
map — Structural map (map.toon) — modules, imports, exports, signatures, project header
|
|
38
|
+
evolution — Refactoring queue (evolution.toon)
|
|
39
39
|
context — LLM narrative (context.md) — architecture summary
|
|
40
|
-
code2logic — Generate project logic (project.toon) via external code2logic
|
|
41
40
|
yaml — Standard YAML format
|
|
42
41
|
json — Machine-readable JSON
|
|
43
42
|
mermaid — Flowchart diagrams (flow.mmd, calls.mmd, compact_flow.mmd)
|
|
44
|
-
|
|
43
|
+
flow — Data-flow analysis (flow.toon) — legacy, explicit opt-in
|
|
44
|
+
code2logic — Generate project logic (legacy project.toon) via external code2logic
|
|
45
45
|
project-yaml — Unified project.yaml (single source of truth) + generated views
|
|
46
|
-
all — Generate
|
|
46
|
+
all — Generate core formats (analysis.toon, map.toon, evolution.toon, context, yaml, json, mermaid)
|
|
47
47
|
|
|
48
48
|
Strategy Options (--strategy):
|
|
49
49
|
quick — Fast overview, fewer files analyzed
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Available exporters:
|
|
4
4
|
- ToonExporter → analysis.toon (health diagnostics)
|
|
5
|
-
- MapExporter →
|
|
5
|
+
- MapExporter → map.toon (structural map + project header)
|
|
6
6
|
- FlowExporter → flow.toon (data-flow: pipelines, contracts, types)
|
|
7
7
|
- EvolutionExporter → evolution.toon (ranked refactoring queue)
|
|
8
8
|
- ContextExporter → context.md (LLM narrative)
|
|
@@ -84,6 +84,9 @@ class IndexHTMLGenerator:
|
|
|
84
84
|
# Limit size
|
|
85
85
|
if len(content) > 100000:
|
|
86
86
|
content = content[:100000] + '\n\n... [truncated - file too large]'
|
|
87
|
+
# Don't escape markdown - it will be rendered as HTML
|
|
88
|
+
if file_type == 'markdown':
|
|
89
|
+
return content
|
|
87
90
|
return self._escape_html(content)
|
|
88
91
|
return '[Binary file]'
|
|
89
92
|
except Exception as e:
|
|
@@ -116,6 +119,7 @@ class IndexHTMLGenerator:
|
|
|
116
119
|
<meta charset="UTF-8">
|
|
117
120
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
118
121
|
<title>code2llm Analysis Results</title>
|
|
122
|
+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
119
123
|
<style>
|
|
120
124
|
:root {{
|
|
121
125
|
--bg: #0f172a;
|
|
@@ -418,6 +422,101 @@ class IndexHTMLGenerator:
|
|
|
418
422
|
word-break: break-word;
|
|
419
423
|
}}
|
|
420
424
|
|
|
425
|
+
/* Markdown rendered content styles */
|
|
426
|
+
.markdown-content {{
|
|
427
|
+
line-height: 1.6;
|
|
428
|
+
max-width: 100%;
|
|
429
|
+
}}
|
|
430
|
+
|
|
431
|
+
.markdown-content h1, .markdown-content h2, .markdown-content h3,
|
|
432
|
+
.markdown-content h4, .markdown-content h5, .markdown-content h6 {{
|
|
433
|
+
margin-top: 1.5rem;
|
|
434
|
+
margin-bottom: 0.75rem;
|
|
435
|
+
font-weight: 600;
|
|
436
|
+
line-height: 1.3;
|
|
437
|
+
}}
|
|
438
|
+
|
|
439
|
+
.markdown-content h1 {{ font-size: 1.75rem; border-bottom: 2px solid var(--border); padding-bottom: 0.5rem; }}
|
|
440
|
+
.markdown-content h2 {{ font-size: 1.5rem; border-bottom: 1px solid var(--border); padding-bottom: 0.4rem; }}
|
|
441
|
+
.markdown-content h3 {{ font-size: 1.25rem; }}
|
|
442
|
+
.markdown-content h4 {{ font-size: 1.1rem; }}
|
|
443
|
+
|
|
444
|
+
.markdown-content p {{
|
|
445
|
+
margin-bottom: 1rem;
|
|
446
|
+
}}
|
|
447
|
+
|
|
448
|
+
.markdown-content ul, .markdown-content ol {{
|
|
449
|
+
margin-bottom: 1rem;
|
|
450
|
+
padding-left: 1.5rem;
|
|
451
|
+
}}
|
|
452
|
+
|
|
453
|
+
.markdown-content li {{
|
|
454
|
+
margin-bottom: 0.25rem;
|
|
455
|
+
}}
|
|
456
|
+
|
|
457
|
+
.markdown-content code {{
|
|
458
|
+
background: var(--surface);
|
|
459
|
+
padding: 0.2rem 0.4rem;
|
|
460
|
+
border-radius: 0.25rem;
|
|
461
|
+
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
|
|
462
|
+
font-size: 0.875em;
|
|
463
|
+
}}
|
|
464
|
+
|
|
465
|
+
.markdown-content pre code {{
|
|
466
|
+
background: none;
|
|
467
|
+
padding: 0;
|
|
468
|
+
}}
|
|
469
|
+
|
|
470
|
+
.markdown-content blockquote {{
|
|
471
|
+
border-left: 4px solid var(--accent);
|
|
472
|
+
padding-left: 1rem;
|
|
473
|
+
margin-left: 0;
|
|
474
|
+
margin-bottom: 1rem;
|
|
475
|
+
color: var(--text-muted);
|
|
476
|
+
}}
|
|
477
|
+
|
|
478
|
+
.markdown-content table {{
|
|
479
|
+
border-collapse: collapse;
|
|
480
|
+
width: 100%;
|
|
481
|
+
margin-bottom: 1rem;
|
|
482
|
+
}}
|
|
483
|
+
|
|
484
|
+
.markdown-content th, .markdown-content td {{
|
|
485
|
+
border: 1px solid var(--border);
|
|
486
|
+
padding: 0.5rem 0.75rem;
|
|
487
|
+
text-align: left;
|
|
488
|
+
}}
|
|
489
|
+
|
|
490
|
+
.markdown-content th {{
|
|
491
|
+
background: var(--surface);
|
|
492
|
+
font-weight: 600;
|
|
493
|
+
}}
|
|
494
|
+
|
|
495
|
+
.markdown-content tr:nth-child(even) {{
|
|
496
|
+
background: var(--surface-hover);
|
|
497
|
+
}}
|
|
498
|
+
|
|
499
|
+
.markdown-content a {{
|
|
500
|
+
color: var(--accent);
|
|
501
|
+
text-decoration: none;
|
|
502
|
+
}}
|
|
503
|
+
|
|
504
|
+
.markdown-content a:hover {{
|
|
505
|
+
text-decoration: underline;
|
|
506
|
+
}}
|
|
507
|
+
|
|
508
|
+
.markdown-content img {{
|
|
509
|
+
max-width: 100%;
|
|
510
|
+
height: auto;
|
|
511
|
+
border-radius: 0.5rem;
|
|
512
|
+
}}
|
|
513
|
+
|
|
514
|
+
.markdown-content hr {{
|
|
515
|
+
border: none;
|
|
516
|
+
border-top: 1px solid var(--border);
|
|
517
|
+
margin: 1.5rem 0;
|
|
518
|
+
}}
|
|
519
|
+
|
|
421
520
|
/* Mobile responsive */
|
|
422
521
|
@media (max-width: 768px) {{
|
|
423
522
|
.container {{
|
|
@@ -568,9 +667,12 @@ class IndexHTMLGenerator:
|
|
|
568
667
|
|
|
569
668
|
// Content
|
|
570
669
|
const body = document.getElementById('contentBody');
|
|
571
|
-
if (file.type === 'markdown'
|
|
572
|
-
//
|
|
573
|
-
body.innerHTML = `<
|
|
670
|
+
if (file.type === 'markdown') {{
|
|
671
|
+
// Render markdown as HTML using marked.js
|
|
672
|
+
body.innerHTML = `<div class="markdown-content">${{marked.parse(file.content)}}</div>`;
|
|
673
|
+
}} else if (file.type === 'html') {{
|
|
674
|
+
// For HTML files, show in iframe for safety
|
|
675
|
+
body.innerHTML = `<iframe src="${{file.rel_path}}" style="width:100%;height:100%;border:none;border-radius:0.5rem;"></iframe>`;
|
|
574
676
|
}} else if (file.type === 'json') {{
|
|
575
677
|
try {{
|
|
576
678
|
const json = JSON.parse(file.content.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'));
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
"""Map Exporter — generates map.toon (structural map).
|
|
2
2
|
|
|
3
|
-
Produces a compact key:value
|
|
4
|
-
|
|
3
|
+
Produces a compact project header plus a key:value structural map showing
|
|
4
|
+
modules, imports, exports, and signatures.
|
|
5
5
|
|
|
6
6
|
Purpose: "what exists and how it's connected"
|
|
7
|
-
Format: M[] module list, D: details with i: imports,
|
|
7
|
+
Format: header summary + M[] module list, D: details with i: imports,
|
|
8
|
+
e: exports, signatures
|
|
8
9
|
"""
|
|
9
10
|
|
|
10
11
|
from collections import defaultdict
|
|
11
12
|
from datetime import datetime
|
|
13
|
+
import re
|
|
12
14
|
from pathlib import Path
|
|
13
15
|
from typing import Any, Dict, List, Optional, Set, Tuple
|
|
14
16
|
|
|
@@ -25,15 +27,16 @@ EXCLUDE_PATTERNS = {
|
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
class MapExporter(Exporter):
|
|
28
|
-
"""Export to map.toon — structural map with
|
|
30
|
+
"""Export to map.toon — structural map with a compact project header.
|
|
29
31
|
|
|
30
|
-
Keys: M=modules, D=details, i=imports, c=classes, f=functions,
|
|
32
|
+
Keys: M=modules, D=details, i=imports, e=exports, c=classes, f=functions,
|
|
33
|
+
m=methods
|
|
31
34
|
"""
|
|
32
35
|
|
|
33
36
|
def export(self, result: AnalysisResult, output_path: str, **kwargs) -> None:
|
|
34
37
|
"""Export analysis result to .map format."""
|
|
35
38
|
lines: List[str] = []
|
|
36
|
-
lines.extend(self._render_header(result))
|
|
39
|
+
lines.extend(self._render_header(result, output_path))
|
|
37
40
|
lines.extend(self._render_module_list(result))
|
|
38
41
|
lines.extend(self._render_details(result))
|
|
39
42
|
|
|
@@ -44,16 +47,32 @@ class MapExporter(Exporter):
|
|
|
44
47
|
# ------------------------------------------------------------------
|
|
45
48
|
# header
|
|
46
49
|
# ------------------------------------------------------------------
|
|
47
|
-
def _render_header(self, result: AnalysisResult) -> List[str]:
|
|
48
|
-
|
|
50
|
+
def _render_header(self, result: AnalysisResult, output_path: str) -> List[str]:
|
|
51
|
+
project_name = Path(result.project_path).name if result.project_path else "project"
|
|
49
52
|
total_lines = self._count_total_lines(result)
|
|
50
53
|
langs = self._detect_languages(result)
|
|
51
|
-
lang_str = ",".join(f"{lang}:{count}" for lang, count in langs.items())
|
|
54
|
+
lang_str = ",".join(f"{lang}:{count}" for lang, count in langs.items()) or "unknown"
|
|
55
|
+
|
|
56
|
+
included_files = [mi for mi in result.modules.values() if not self._is_excluded(mi.file)]
|
|
57
|
+
included_funcs = [fi for fi in result.functions.values() if not self._is_excluded(fi.file)]
|
|
58
|
+
included_classes = [ci for ci in result.classes.values() if not self._is_excluded(ci.file)]
|
|
59
|
+
|
|
60
|
+
cc_scores = [fi.complexity.get("cyclomatic_complexity", 0) for fi in included_funcs]
|
|
61
|
+
avg_cc = round(sum(cc_scores) / len(cc_scores), 1) if cc_scores else 0.0
|
|
62
|
+
critical_count = len([cc for cc in cc_scores if cc >= 15])
|
|
63
|
+
cycles = len(result.metrics.get("project", {}).get("circular_dependencies", []))
|
|
64
|
+
|
|
65
|
+
alerts = self._build_alerts(included_funcs)
|
|
66
|
+
hotspots = self._build_hotspots(included_funcs)
|
|
67
|
+
trend = self._load_evolution_trend(Path(output_path).with_name("evolution.toon"), avg_cc)
|
|
52
68
|
|
|
53
69
|
lines = [
|
|
54
|
-
f"# {
|
|
55
|
-
f" | {
|
|
56
|
-
"#
|
|
70
|
+
f"# {project_name} | {len(included_files)}f {total_lines}L | {lang_str} | {datetime.now().strftime('%Y-%m-%d')}",
|
|
71
|
+
f"# stats: {len(included_funcs)} func | {len(included_classes)} cls | {len(included_files)} mod | CC̄={avg_cc} | critical:{critical_count} | cycles:{cycles}",
|
|
72
|
+
f"# alerts[{len(alerts)}]: {'; '.join(alerts) if alerts else 'none'}",
|
|
73
|
+
f"# hotspots[{len(hotspots)}]: {'; '.join(hotspots) if hotspots else 'none'}",
|
|
74
|
+
f"# evolution: {trend}",
|
|
75
|
+
"# Keys: M=modules, D=details, i=imports, e=exports, c=classes, f=functions, m=methods",
|
|
57
76
|
]
|
|
58
77
|
return lines
|
|
59
78
|
|
|
@@ -235,3 +254,73 @@ class MapExporter(Exporter):
|
|
|
235
254
|
if ext:
|
|
236
255
|
langs[ext.lstrip('.')] += 1
|
|
237
256
|
return dict(langs)
|
|
257
|
+
|
|
258
|
+
@staticmethod
|
|
259
|
+
def _build_alerts(funcs: List[FunctionInfo]) -> List[str]:
|
|
260
|
+
"""Build a compact list of top alerts for the header."""
|
|
261
|
+
alerts: List[Tuple[int, int, str]] = []
|
|
262
|
+
for fi in funcs:
|
|
263
|
+
display = fi.name if not fi.class_name else f"{fi.class_name}.{fi.name}"
|
|
264
|
+
cc = fi.complexity.get("cyclomatic_complexity", 0)
|
|
265
|
+
if cc >= 15:
|
|
266
|
+
severity = 0 if cc >= 25 else 1
|
|
267
|
+
alerts.append((severity, cc, f"CC {display}={cc}"))
|
|
268
|
+
|
|
269
|
+
fan_out = len(set(fi.calls))
|
|
270
|
+
if fan_out >= 10:
|
|
271
|
+
severity = 0 if fan_out >= 20 else 1
|
|
272
|
+
alerts.append((severity, fan_out, f"fan-out {display}={fan_out}"))
|
|
273
|
+
|
|
274
|
+
alerts.sort(key=lambda item: (item[0], -item[1], item[2]))
|
|
275
|
+
return [label for _, _, label in alerts[:5]]
|
|
276
|
+
|
|
277
|
+
@staticmethod
|
|
278
|
+
def _build_hotspots(funcs: List[FunctionInfo]) -> List[str]:
|
|
279
|
+
"""Build a compact list of top fan-out hotspots for the header."""
|
|
280
|
+
spots: List[Tuple[int, str]] = []
|
|
281
|
+
for fi in funcs:
|
|
282
|
+
fan_out = len(set(fi.calls))
|
|
283
|
+
if fan_out >= 5:
|
|
284
|
+
display = fi.name if not fi.class_name else f"{fi.class_name}.{fi.name}"
|
|
285
|
+
spots.append((fan_out, f"{display} fan={fan_out}"))
|
|
286
|
+
|
|
287
|
+
spots.sort(key=lambda item: item[0], reverse=True)
|
|
288
|
+
return [label for _, label in spots[:5]]
|
|
289
|
+
|
|
290
|
+
@staticmethod
|
|
291
|
+
def _load_evolution_trend(evolution_path: Path, current_cc: float) -> str:
|
|
292
|
+
"""Summarize the latest CC trend from the previous evolution.toon file."""
|
|
293
|
+
previous_cc = MapExporter._read_previous_cc_avg(evolution_path)
|
|
294
|
+
if previous_cc is None:
|
|
295
|
+
return "baseline"
|
|
296
|
+
|
|
297
|
+
delta = round(current_cc - previous_cc, 1)
|
|
298
|
+
if delta < 0:
|
|
299
|
+
direction = "improved"
|
|
300
|
+
elif delta > 0:
|
|
301
|
+
direction = "regressed"
|
|
302
|
+
else:
|
|
303
|
+
direction = "flat"
|
|
304
|
+
|
|
305
|
+
sign = "+" if delta > 0 else ""
|
|
306
|
+
return f"CC̄ {previous_cc:.1f}→{current_cc:.1f} ({direction} {sign}{delta:.1f})"
|
|
307
|
+
|
|
308
|
+
@staticmethod
|
|
309
|
+
def _read_previous_cc_avg(evolution_path: Path) -> Optional[float]:
|
|
310
|
+
"""Read the previous CC average from an existing evolution.toon file."""
|
|
311
|
+
if not evolution_path.exists():
|
|
312
|
+
return None
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
content = evolution_path.read_text(encoding="utf-8")
|
|
316
|
+
except Exception:
|
|
317
|
+
return None
|
|
318
|
+
|
|
319
|
+
for line in content.splitlines():
|
|
320
|
+
match = re.search(r"CC̄:\s*([0-9]+(?:\.[0-9]+)?)\s*→", line)
|
|
321
|
+
if match:
|
|
322
|
+
try:
|
|
323
|
+
return float(match.group(1))
|
|
324
|
+
except ValueError:
|
|
325
|
+
return None
|
|
326
|
+
return None
|
|
@@ -35,7 +35,7 @@ GOD_MODULE_LINES = 500
|
|
|
35
35
|
class ProjectYAMLExporter(Exporter):
|
|
36
36
|
"""Export unified project.yaml — single source of truth for diagnostics.
|
|
37
37
|
|
|
38
|
-
Combines data from analysis.toon,
|
|
38
|
+
Combines data from analysis.toon, map.toon, context.md, and evolution.toon
|
|
39
39
|
into one machine-parseable YAML file.
|
|
40
40
|
"""
|
|
41
41
|
|