code2llm 0.5.54__tar.gz → 0.5.56__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.
Files changed (120) hide show
  1. {code2llm-0.5.54 → code2llm-0.5.56}/PKG-INFO +14 -19
  2. {code2llm-0.5.54 → code2llm-0.5.56}/README.md +13 -18
  3. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/__init__.py +1 -1
  4. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/cli_commands.py +1 -1
  5. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/cli_exports/orchestrator.py +1 -1
  6. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/cli_exports/prompt.py +18 -15
  7. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/cli_parser.py +6 -6
  8. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/gitignore.py +16 -2
  9. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/__init__.py +1 -1
  10. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/index_generator.py +105 -3
  11. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/map_exporter.py +101 -12
  12. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/mermaid_exporter.py +3 -1
  13. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/project_yaml_exporter.py +1 -1
  14. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/readme_exporter.py +10 -18
  15. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/toon/__init__.py +1 -15
  16. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/generators/mermaid.py +10 -2
  17. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/nlp/__init__.py +1 -1
  18. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm.egg-info/PKG-INFO +14 -19
  19. {code2llm-0.5.54 → code2llm-0.5.56}/pyproject.toml +1 -1
  20. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_format_quality.py +12 -10
  21. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_prompt_txt.py +3 -2
  22. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_toon_v2.py +22 -16
  23. {code2llm-0.5.54 → code2llm-0.5.56}/LICENSE +0 -0
  24. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/__main__.py +0 -0
  25. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/analysis/__init__.py +0 -0
  26. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/analysis/call_graph.py +0 -0
  27. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/analysis/cfg.py +0 -0
  28. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/analysis/coupling.py +0 -0
  29. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/analysis/data_analysis.py +0 -0
  30. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/analysis/dfg.py +0 -0
  31. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/analysis/pipeline_detector.py +0 -0
  32. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/analysis/side_effects.py +0 -0
  33. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/analysis/smells.py +0 -0
  34. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/analysis/type_inference.py +0 -0
  35. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/api.py +0 -0
  36. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/cli.py +0 -0
  37. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/cli_analysis.py +0 -0
  38. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/cli_exports/__init__.py +0 -0
  39. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/cli_exports/code2logic.py +0 -0
  40. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/cli_exports/formats.py +0 -0
  41. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/__init__.py +0 -0
  42. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/analyzer.py +0 -0
  43. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/config.py +0 -0
  44. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/__init__.py +0 -0
  45. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/file_analyzer.py +0 -0
  46. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/file_cache.py +0 -0
  47. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/file_filter.py +0 -0
  48. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/__init__.py +0 -0
  49. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/base.py +0 -0
  50. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/cpp.py +0 -0
  51. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/csharp.py +0 -0
  52. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/generic.py +0 -0
  53. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/go_lang.py +0 -0
  54. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/java.py +0 -0
  55. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/php.py +0 -0
  56. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/ruby.py +0 -0
  57. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/rust.py +0 -0
  58. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/lang/typescript.py +0 -0
  59. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/core/refactoring.py +0 -0
  60. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/large_repo.py +0 -0
  61. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/models.py +0 -0
  62. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/repo_files.py +0 -0
  63. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/streaming/__init__.py +0 -0
  64. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/streaming/cache.py +0 -0
  65. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/streaming/incremental.py +0 -0
  66. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/streaming/prioritizer.py +0 -0
  67. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/streaming/scanner.py +0 -0
  68. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/streaming/strategies.py +0 -0
  69. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/streaming_analyzer.py +0 -0
  70. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/core/toon_size_manager.py +0 -0
  71. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/article_view.py +0 -0
  72. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/base.py +0 -0
  73. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/context_exporter.py +0 -0
  74. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/context_view.py +0 -0
  75. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/evolution_exporter.py +0 -0
  76. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/flow_constants.py +0 -0
  77. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/flow_exporter.py +0 -0
  78. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/flow_renderer.py +0 -0
  79. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/html_dashboard.py +0 -0
  80. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/json_exporter.py +0 -0
  81. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/llm_exporter.py +0 -0
  82. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/report_generators.py +0 -0
  83. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/toon/helpers.py +0 -0
  84. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/toon/metrics.py +0 -0
  85. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/toon/module_detail.py +0 -0
  86. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/toon/renderer.py +0 -0
  87. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/toon.py +0 -0
  88. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/toon_view.py +0 -0
  89. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/validate_project.py +0 -0
  90. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/exporters/yaml_exporter.py +0 -0
  91. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/generators/__init__.py +0 -0
  92. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/generators/llm_flow.py +0 -0
  93. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/generators/llm_task.py +0 -0
  94. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/nlp/config.py +0 -0
  95. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/nlp/entity_resolution.py +0 -0
  96. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/nlp/intent_matching.py +0 -0
  97. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/nlp/normalization.py +0 -0
  98. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/nlp/pipeline.py +0 -0
  99. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/patterns/__init__.py +0 -0
  100. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/patterns/detector.py +0 -0
  101. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/refactor/__init__.py +0 -0
  102. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm/refactor/prompt_engine.py +0 -0
  103. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm.egg-info/SOURCES.txt +0 -0
  104. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm.egg-info/dependency_links.txt +0 -0
  105. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm.egg-info/entry_points.txt +0 -0
  106. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm.egg-info/requires.txt +0 -0
  107. {code2llm-0.5.54 → code2llm-0.5.56}/code2llm.egg-info/top_level.txt +0 -0
  108. {code2llm-0.5.54 → code2llm-0.5.56}/setup.cfg +0 -0
  109. {code2llm-0.5.54 → code2llm-0.5.56}/setup.py +0 -0
  110. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_advanced_analysis.py +0 -0
  111. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_analyzer.py +0 -0
  112. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_deep_analysis.py +0 -0
  113. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_edge_cases.py +0 -0
  114. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_flow_exporter.py +0 -0
  115. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_multilanguage_e2e.py +0 -0
  116. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_nlp_pipeline.py +0 -0
  117. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_nonpython_cc_calls.py +0 -0
  118. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_pipeline_detector.py +0 -0
  119. {code2llm-0.5.54 → code2llm-0.5.56}/tests/test_prompt_engine.py +0 -0
  120. {code2llm-0.5.54 → code2llm-0.5.56}/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.54
3
+ Version: 0.5.56
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,8 +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** - Complexity, god modules, coupling | 66 critical functions, 0 god modules |
64
- | `project.toon` | **TOON** | **🧠 Project logic** - Compact module view from code2logic | Generated via code2logic integration |
63
+ | `analysis.toon` | **TOON** | **🔥 Health diagnostics** - Health, LAYERS, COUPLING | 69 critical functions, 0 god modules |
65
64
 
66
65
  ### 🤖 LLM-Ready Documentation
67
66
 
@@ -145,8 +144,8 @@ cat evolution.toon
145
144
  grep "NEXT" evolution.toon
146
145
  ```
147
146
 
148
- ### `flow.toon` - Data Flow Analysis
149
- **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)
150
149
  **Key sections**:
151
150
  - **PIPELINES**: Data processing chains
152
151
  - **CONTRACTS**: Function input/output contracts
@@ -161,12 +160,13 @@ grep "PIPELINES" flow.toon
161
160
  grep "SIDE_EFFECTS" flow.toon
162
161
  ```
163
162
 
164
- ### `map.toon` - Structural Map
165
- **Purpose**: High-level architecture overview
163
+ ### `map.toon` - Structural Map + Project Header
164
+ **Purpose**: High-level architecture overview plus compact project header
166
165
  **Key sections**:
167
166
  - **MODULES**: All modules with basic stats
168
167
  - **IMPORTS**: Dependency relationships
169
- - **SIGNATURES**: Public API functions
168
+ - **EXPORTS**: Public API surface and signatures
169
+ - **HEADER**: Stats, alerts, hotspots, evolution trend
170
170
 
171
171
  **Example usage**:
172
172
  ```bash
@@ -177,14 +177,9 @@ cat map.toon | head -50
177
177
  grep "SIGNATURES" map.toon
178
178
  ```
179
179
 
180
- ### `project.toon` - Project Logic (Code2Logic)
180
+ ### `project.toon` - Legacy Project Logic (Deprecated)
181
181
  **Purpose**: Compact module view generated by code2logic integration
182
- **Key sections**:
183
- - **Modules list**: All project modules with file sizes
184
- - **Imports**: Dependency information
185
- - **Classes/Functions**: Summary counts
186
-
187
- **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
188
183
 
189
184
  **Example usage**:
190
185
  ```bash
@@ -374,10 +369,10 @@ code2llm ./ -f yaml --separate-orphans
374
369
  ---
375
370
 
376
371
  **Generated by**: `code2llm ./ -f all --readme`
377
- **Analysis Date**: 2026-03-09
378
- **Total Functions**: 861
379
- **Total Classes**: 104
380
- **Modules**: 105
372
+ **Analysis Date**: 2026-03-25
373
+ **Total Functions**: 891
374
+ **Total Classes**: 106
375
+ **Modules**: 121
381
376
 
382
377
  For more information about code2llm, visit: https://github.com/tom-sapletta/code2llm
383
378
 
@@ -10,8 +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** - Complexity, god modules, coupling | 66 critical functions, 0 god modules |
14
- | `project.toon` | **TOON** | **🧠 Project logic** - Compact module view from code2logic | Generated via code2logic integration |
13
+ | `analysis.toon` | **TOON** | **🔥 Health diagnostics** - Health, LAYERS, COUPLING | 69 critical functions, 0 god modules |
15
14
 
16
15
  ### 🤖 LLM-Ready Documentation
17
16
 
@@ -95,8 +94,8 @@ cat evolution.toon
95
94
  grep "NEXT" evolution.toon
96
95
  ```
97
96
 
98
- ### `flow.toon` - Data Flow Analysis
99
- **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)
100
99
  **Key sections**:
101
100
  - **PIPELINES**: Data processing chains
102
101
  - **CONTRACTS**: Function input/output contracts
@@ -111,12 +110,13 @@ grep "PIPELINES" flow.toon
111
110
  grep "SIDE_EFFECTS" flow.toon
112
111
  ```
113
112
 
114
- ### `map.toon` - Structural Map
115
- **Purpose**: High-level architecture overview
113
+ ### `map.toon` - Structural Map + Project Header
114
+ **Purpose**: High-level architecture overview plus compact project header
116
115
  **Key sections**:
117
116
  - **MODULES**: All modules with basic stats
118
117
  - **IMPORTS**: Dependency relationships
119
- - **SIGNATURES**: Public API functions
118
+ - **EXPORTS**: Public API surface and signatures
119
+ - **HEADER**: Stats, alerts, hotspots, evolution trend
120
120
 
121
121
  **Example usage**:
122
122
  ```bash
@@ -127,14 +127,9 @@ cat map.toon | head -50
127
127
  grep "SIGNATURES" map.toon
128
128
  ```
129
129
 
130
- ### `project.toon` - Project Logic (Code2Logic)
130
+ ### `project.toon` - Legacy Project Logic (Deprecated)
131
131
  **Purpose**: Compact module view generated by code2logic integration
132
- **Key sections**:
133
- - **Modules list**: All project modules with file sizes
134
- - **Imports**: Dependency information
135
- - **Classes/Functions**: Summary counts
136
-
137
- **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
138
133
 
139
134
  **Example usage**:
140
135
  ```bash
@@ -324,10 +319,10 @@ code2llm ./ -f yaml --separate-orphans
324
319
  ---
325
320
 
326
321
  **Generated by**: `code2llm ./ -f all --readme`
327
- **Analysis Date**: 2026-03-09
328
- **Total Functions**: 861
329
- **Total Classes**: 104
330
- **Modules**: 105
322
+ **Analysis Date**: 2026-03-25
323
+ **Total Functions**: 891
324
+ **Total Classes**: 106
325
+ **Modules**: 121
331
326
 
332
327
  For more information about code2llm, visit: https://github.com/tom-sapletta/code2llm
333
328
 
@@ -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.54"
11
+ __version__ = "0.5.56"
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
@@ -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', 'flow', 'context', 'code2logic', 'yaml', 'json', 'mermaid', 'evolution', 'project-yaml']
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 name != 'project.toon' and not (output_dir / name).exists()]
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("2. **Refactoring Priorities** - Examine ranked refactoring actions and risk assessment from evolution.toon")
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("3. **Architecture Overview** - Understand main flows, entry points, and public API from context.md")
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 main flows.",
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 god modules from analysis.toon.")
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['has_evolution_toon']:
271
- lines.append("- Start with analysis.toon for health metrics, then evolution.toon for action priorities")
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")
@@ -15,7 +15,7 @@ def create_parser() -> argparse.ArgumentParser:
15
15
  Examples:
16
16
  code2llm ./ # Default: TOON diagnostics + README
17
17
  code2llm ./ -f all -o ./docs # All formats to ./docs/
18
- code2llm ./ -f toon,map,flow # Diagnostics + structure + data-flow
18
+ code2llm ./ -f toon,map,evolution # Consolidated diagnostics + structure + roadmap
19
19
  code2llm ./ -f context # LLM narrative (context.md)
20
20
  code2llm ./ --streaming --strategy deep -f all # Deep streaming analysis, all outputs
21
21
  code2llm ./ --strategy quick -f toon # Fast overview
@@ -34,16 +34,16 @@ Examples:
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
- flow Data-flow analysis (flow.toon) — pipelines, contracts, types
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
- evolution Refactoring queue (evolution.toon)
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 all formats (including project-yaml)
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
@@ -120,6 +120,20 @@ class GitIgnoreParser:
120
120
 
121
121
 
122
122
  def load_gitignore_patterns(project_path: Path) -> GitIgnoreParser:
123
- """Load gitignore patterns from project directory."""
124
- gitignore_path = project_path / '.gitignore'
123
+ """Load gitignore patterns from project directory.
124
+
125
+ Searches up the directory tree from project_path until it finds a .gitignore file
126
+ or reaches the filesystem root. This ensures that gitignore rules are properly applied
127
+ even when analyzing subdirectories of a larger project.
128
+ """
129
+ current_path = project_path.resolve()
130
+
131
+ while current_path != current_path.parent: # Stop at filesystem root
132
+ gitignore_path = current_path / '.gitignore'
133
+ if gitignore_path.exists():
134
+ return GitIgnoreParser(gitignore_path)
135
+ current_path = current_path.parent
136
+
137
+ # Check filesystem root as last resort
138
+ gitignore_path = current_path / '.gitignore'
125
139
  return GitIgnoreParser(gitignore_path)
@@ -2,7 +2,7 @@
2
2
 
3
3
  Available exporters:
4
4
  - ToonExporter → analysis.toon (health diagnostics)
5
- - MapExporter → project.map (structural map)
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' || file.type === 'html') {{
572
- // For markdown, show formatted but also offer raw view
573
- body.innerHTML = `<pre>${{file.content}}</pre>`;
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(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&'));
@@ -1,14 +1,16 @@
1
1
  """Map Exporter — generates map.toon (structural map).
2
2
 
3
- Produces a compact key:value format showing modules, imports, signatures,
4
- and type information. Formerly the project.toon format.
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, e: exports, signatures
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 modules, imports, signatures.
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, m=methods
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
- nfiles = len(result.modules)
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"# {Path(result.project_path).name if result.project_path else 'project'}"
55
- f" | {nfiles}f {total_lines}L | {lang_str}",
56
- "# Keys: M=modules, D=details, i=imports, c=classes, f=functions, m=methods",
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
@@ -212,7 +212,9 @@ class MermaidExporter(Exporter):
212
212
  safe = safe.replace(' ', '_')
213
213
  if len(safe) > 50:
214
214
  # Keep module prefix + function name
215
- parts = name.split('.')
215
+ # Use sanitized parts (replace dashes first)
216
+ sanitized = name.replace('-', '_').replace(':', '_')
217
+ parts = sanitized.split('.')
216
218
  if len(parts) >= 2:
217
219
  safe = f"{parts[0]}__{parts[-1]}"
218
220
  safe = safe[:50]
@@ -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, project.toon, context.md, and evolution.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