readmenator 1.3.2__tar.gz → 1.3.3__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 (148) hide show
  1. {readmenator-1.3.2 → readmenator-1.3.3}/PKG-INFO +64 -7
  2. {readmenator-1.3.2 → readmenator-1.3.3}/README.md +63 -6
  3. {readmenator-1.3.2 → readmenator-1.3.3}/pyproject.toml +1 -1
  4. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/__init__.py +3 -0
  5. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/__main__.py +11 -0
  6. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_app.py +239 -30
  7. readmenator-1.3.3/readmenator/_bundlegraph.py +316 -0
  8. readmenator-1.3.3/readmenator/_bundlegraph_page.py +753 -0
  9. readmenator-1.3.3/readmenator/_components.py +1168 -0
  10. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_config.py +133 -0
  11. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_diagrams.py +1 -1
  12. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_explorer.py +34 -2
  13. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_forcegraph.py +24 -0
  14. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_forcegraph_page.py +142 -2
  15. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_graphlayout.py +289 -69
  16. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_linter.py +66 -5
  17. readmenator-1.3.3/readmenator/_ollama.py +128 -0
  18. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_pipeline.py +45 -0
  19. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_scanner.py +1 -0
  20. readmenator-1.3.3/readmenator/_sourceview.py +122 -0
  21. readmenator-1.3.3/readmenator/_symindex.py +438 -0
  22. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_video.py +641 -27
  23. readmenator-1.3.3/tests/test_bundlegraph.py +233 -0
  24. readmenator-1.3.3/tests/test_components.py +361 -0
  25. readmenator-1.3.3/tests/test_graphlayout.py +236 -0
  26. readmenator-1.3.3/tests/test_ollama.py +39 -0
  27. readmenator-1.3.3/tests/test_sourceview.py +129 -0
  28. readmenator-1.3.3/tests/test_symindex.py +94 -0
  29. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_video.py +65 -3
  30. readmenator-1.3.2/tests/test_graphlayout.py +0 -122
  31. {readmenator-1.3.2 → readmenator-1.3.3}/.gitignore +0 -0
  32. {readmenator-1.3.2 → readmenator-1.3.3}/LICENSE +0 -0
  33. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_agent_injector.py +0 -0
  34. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_agent_output.py +0 -0
  35. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_analytics.py +0 -0
  36. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_analyzer.py +0 -0
  37. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_cache.py +0 -0
  38. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_category.py +0 -0
  39. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_concepts.py +0 -0
  40. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_cpg.py +0 -0
  41. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_cursorrules_generator.py +0 -0
  42. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_dataflow.py +0 -0
  43. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_dead_code.py +0 -0
  44. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_documentation.py +0 -0
  45. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_embed.py +0 -0
  46. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_exclusions.py +0 -0
  47. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_explain.py +0 -0
  48. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_exporter.py +0 -0
  49. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_gh_wiki.py +0 -0
  50. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_gitmeta.py +0 -0
  51. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_graphrag.py +0 -0
  52. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_hotspots.py +0 -0
  53. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_layer_rules.py +0 -0
  54. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_layers.py +0 -0
  55. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_mcp_server.py +0 -0
  56. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_memory.py +0 -0
  57. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_mermaid.py +0 -0
  58. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_models.py +0 -0
  59. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_projections.py +0 -0
  60. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_provenance.py +0 -0
  61. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_purpose.py +0 -0
  62. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_query.py +0 -0
  63. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_rank.py +0 -0
  64. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_readme_injector.py +0 -0
  65. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_refactorizer.py +0 -0
  66. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_resolver.py +0 -0
  67. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_rule_gen.py +0 -0
  68. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_sarif.py +0 -0
  69. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_scantext.py +0 -0
  70. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_security.py +0 -0
  71. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_skill_installer.py +0 -0
  72. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_skills/readmenator-ask/SKILL.md +0 -0
  73. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_skills/readmenator-change/SKILL.md +0 -0
  74. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_skills/readmenator-memory/SKILL.md +0 -0
  75. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_skills/readmenator-orient/SKILL.md +0 -0
  76. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_taint.py +0 -0
  77. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_uml.py +0 -0
  78. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_vendor/README.md +0 -0
  79. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_vendor/force-graph.min.js +0 -0
  80. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_watcher.py +0 -0
  81. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_wiki.py +0 -0
  82. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/_yaralite.py +0 -0
  83. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/__init__.py +0 -0
  84. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_assembly.py +0 -0
  85. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_base.py +0 -0
  86. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_c.py +0 -0
  87. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_csharp.py +0 -0
  88. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_dart.py +0 -0
  89. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_elixir.py +0 -0
  90. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_gdscript.py +0 -0
  91. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_go.py +0 -0
  92. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_java.py +0 -0
  93. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_javascript.py +0 -0
  94. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_kotlin.py +0 -0
  95. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_lua.py +0 -0
  96. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_nim.py +0 -0
  97. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_php.py +0 -0
  98. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_python.py +0 -0
  99. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_ruby.py +0 -0
  100. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_rust.py +0 -0
  101. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_scala.py +0 -0
  102. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_shell.py +0 -0
  103. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator/parsers/_swift.py +0 -0
  104. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator.py +0 -0
  105. {readmenator-1.3.2 → readmenator-1.3.3}/readmenator_orchestrator.py +0 -0
  106. {readmenator-1.3.2 → readmenator-1.3.3}/tests/__init__.py +0 -0
  107. {readmenator-1.3.2 → readmenator-1.3.3}/tests/features/taint_propagation.feature +0 -0
  108. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_agent_friendliness.py +0 -0
  109. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_agent_injector.py +0 -0
  110. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_agent_output.py +0 -0
  111. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_analyzer.py +0 -0
  112. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_cache.py +0 -0
  113. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_concepts.py +0 -0
  114. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_config.py +0 -0
  115. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_cpg.py +0 -0
  116. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_cursorrules.py +0 -0
  117. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_dataflow.py +0 -0
  118. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_dead_code.py +0 -0
  119. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_diagrams.py +0 -0
  120. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_documentation.py +0 -0
  121. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_exporter.py +0 -0
  122. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_gh_wiki.py +0 -0
  123. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_graphrag.py +0 -0
  124. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_hotspots.py +0 -0
  125. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_integration.py +0 -0
  126. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_interactive_graph.py +0 -0
  127. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_layer_rules.py +0 -0
  128. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_linter.py +0 -0
  129. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_mcp_server.py +0 -0
  130. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_memory.py +0 -0
  131. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_mermaid.py +0 -0
  132. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_models.py +0 -0
  133. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_parsers.py +0 -0
  134. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_parsers_new.py +0 -0
  135. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_parsers_property.py +0 -0
  136. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_query.py +0 -0
  137. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_ranking.py +0 -0
  138. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_readme_injector.py +0 -0
  139. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_refactorizer.py +0 -0
  140. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_resolver.py +0 -0
  141. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_rule_gen.py +0 -0
  142. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_sarif.py +0 -0
  143. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_scanner.py +0 -0
  144. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_security.py +0 -0
  145. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_taint.py +0 -0
  146. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_taint_bdd.py +0 -0
  147. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_uml.py +0 -0
  148. {readmenator-1.3.2 → readmenator-1.3.3}/tests/test_wiki.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: readmenator
3
- Version: 1.3.2
3
+ Version: 1.3.3
4
4
  Summary: Zero-token polyglot codebase knowledge graph generator
5
5
  Project-URL: Homepage, https://github.com/grisuno/ReadMenator
6
6
  Project-URL: Repository, https://github.com/grisuno/ReadMenator
@@ -95,6 +95,7 @@ python -m readmenator /path/to/project --svg # graph.svg (
95
95
  python -m readmenator /path/to/project --graphml # graph.graphml (Gephi/yEd)
96
96
  python -m readmenator /path/to/project obsidian # Obsidian vault (wikilinks)
97
97
  python -m readmenator /path/to/project wiki # Agent wiki (index + community pages)
98
+ python -m readmenator /path/to/project components # Component diagrams (analysis.json + graph LR markdown + index.html)
98
99
  python -m readmenator /path/to/project lint-wiki # Wiki health check
99
100
  python -m readmenator /path/to/project lint # Architecture violations (exit 1 on errors)
100
101
  python -m readmenator /path/to/project strip-dead-code # Orphaned symbol report
@@ -203,6 +204,49 @@ external in a 2D map or a 3D space:
203
204
  `#path=<a>~<b>`, `#lens=cycles`, `#edge=<key>`. The page also exposes
204
205
  `window.ReadmenatorExplorer` for console scripting.
205
206
 
207
+ The **Edge Bundle Explorer** (`readmenator-maps/graph-bundle.html`, its own gallery
208
+ card next to the force graph, `readmenator . bundles` to export it alone) is the
209
+ hierarchical edge bundling view from the video, live. It needs no network: one
210
+ canvas, no CDN.
211
+
212
+ - **Circle (2D).** Files sit on a ring grouped into community arcs (hubs first);
213
+ every resolved import is a B-spline routed through the community tree, so thick
214
+ bundles are the real seams between subsystems.
215
+ - **Sphere (3D).** The same hierarchy on a globe: each community owns a contiguous
216
+ cap sized by its file count, wires dive through the core between caps. Drag to
217
+ rotate, wheel to zoom, optional auto-rotate; selecting a file or community flies
218
+ the camera to face it.
219
+ - **Reading it.** Hover a file: cyan wires are what it imports, pink what imports it.
220
+ Click to pin it (imports and importers listed, one click to open it in the force
221
+ graph in 2D or 3D). Click an arc, cap label or legend row to focus a community
222
+ (inside/out/in counts, cohesion, top flows to other communities).
223
+ - **Controls.** Beta slider (0 straight chords, 1 fully bundled, recomputed live),
224
+ crossing-only filter, direction (both, imports, imported by), color by community,
225
+ layer or language, search, PNG export, light/dark theme. Deep links:
226
+ `#view=3d&node=<id>&group=<key>&beta=0.7&color=layer&dir=out&cross=1`; console API
227
+ `window.ReadmenatorBundles`.
228
+
229
+ ### Component Diagrams
230
+
231
+ `readmenator-diagrams/` holds a component architecture map built with zero
232
+ tokens: `analysis.json` (components with key entities and file/line spans,
233
+ relations with method-level call evidence), `overview.md` with the `graph LR`
234
+ diagram, one page per expandable component, and `index.html` — the diagram
235
+ drawn as an offline interactive page in the readmenator dark theme (layered
236
+ left-to-right boxes enriched with key symbols, layer colors and PageRank hubs,
237
+ labeled arrows weighted by call/import evidence, hover descriptions,
238
+ click-to-component, pan/zoom, PNG export). The maps gallery links it with a
239
+ **Component Diagrams** card that opens a self-contained copy living inside the
240
+ maps directory itself, so the link never leaves the site (safe on GitHub Pages
241
+ project subpaths, where `../..` hrefs would escape the project). The docs site
242
+ ships the markdown in its reader. No external service needed: structure and
243
+ call evidence are pure static analysis; a local Ollama daemon only ever
244
+ enriches prose descriptions, and only when `OLLAMA_ENABLED` is set.
245
+
246
+ ```bash
247
+ python -m readmenator /path/to/project components # rebuild only the diagrams
248
+ ```
249
+
206
250
  Serve the `docs/` directory directly with GitHub Pages (Settings -> Pages ->
207
251
  Deploy from branch -> folder `docs/`). The gallery `index.html` links every map
208
252
  with relative paths, works fully offline, and needs no build step.
@@ -213,13 +257,20 @@ gallery, every `--rebuild` refreshes it (video and docs included).
213
257
 
214
258
  ### Overview Video
215
259
 
216
- `readmenator . video` renders a synthwave mp4 from real scan data in seven acts:
260
+ `readmenator . video` renders a synthwave mp4 from real scan data in nine acts:
217
261
  layers, god nodes, blast-radius tree, communities, **Emergence** (ForceAtlas2
218
262
  LinLog with adaptive speed, animated from seeded chaos to convergence, nodes
219
- sized by PageRank with random-surfer particles on the hottest edges), **The Wiring**
220
- (Holten hierarchical edge bundling: files on a circle by community, imports routed
221
- as B-splines through the community tree, a spotlight sweeping each community and a
222
- live flow ranking), and code DNA.
263
+ sized by PageRank with random-surfer particles on the hottest edges), **Orbit**
264
+ (the force graph laid out by ForceAtlas2 in 3D and flown by a camera: color by
265
+ community, layer and language in turn, a tour that zooms into the largest
266
+ communities with their cohesion and seams, then the 1-hop reach of the top hub),
267
+ **The Wiring** (Holten hierarchical edge bundling: files on a circle by community,
268
+ imports routed as B-splines through the community tree, a spotlight sweeping each
269
+ community and a live flow ranking), **The Sphere** (the 3D layout folds onto a globe
270
+ of community caps and every import bundles through its core), and code DNA. A
271
+ closing invitation shows both explorers spinning with their paths, so viewers know
272
+ where to go next. Set an act's duration (`VIDEO_ORBIT_S`, `VIDEO_SPHERE_S`,
273
+ `VIDEO_INVITE_S`, ...) to 0 to drop it with its card.
223
274
 
224
275
  ### GraphRAG for agents (zero tokens to build, cheap to query)
225
276
 
@@ -331,9 +382,15 @@ Supported target languages (12): C++, Java, C#, Python, Go, Rust, PHP, Kotlin, S
331
382
  | Watcher | `_watcher.py` | Filesystem polling watcher for auto-rebuild |
332
383
  | README Injector | `_readme_injector.py` | Auto-injects KB link into project README |
333
384
  | GraphRAG | `_graphrag.py` | Entities, relationships, text units, community report hierarchy, local/global search |
334
- | Graph layouts | `_graphlayout.py` | ForceAtlas2 snapshots and hierarchical edge bundling |
385
+ | Graph layouts | `_graphlayout.py` | ForceAtlas2 (2D/3D) snapshots, circular and spherical hierarchical edge bundling |
386
+ | Edge bundles | `_bundlegraph.py` | Circle + sphere bundle payload, settings, thumbnail |
387
+ | Bundle page | `_bundlegraph_page.py` | Self-contained canvas page: 2D circle, 3D sphere, live beta, focus panels |
335
388
  | Force graph | `_forcegraph.py` | Heterogeneous explorer payload, settings, thumbnail |
336
389
  | Explorer page | `_forcegraph_page.py` | 2D/3D explorer HTML: hit-testing, overlay glyphs, node and edge actions |
390
+ | Source viewer | `_sourceview.py` | Bounded per-file source texts for the explorer View drawer |
391
+ | Symbol index | `_symindex.py` | Definition spans, call sites with lines, BUILTIN/SAME_FILE/IMPORTED/UNIQUE/AMBIGUOUS/UNRESOLVED resolver |
392
+ | Component diagrams | `_components.py` | analysis.json, graph LR markdown, offline interactive index.html, gallery card |
393
+ | Local Ollama | `_ollama.py` | Optional localhost LLM client for prose only (bounded, never fatal) |
337
394
  | Memory | `_memory.py` | MEMORY.md: declared rules, measured baselines, preserved session log |
338
395
  | Skills | `_skill_installer.py` | Installs packaged agent skills from `_skills/` |
339
396
  | Application | `_app.py` | Application orchestrator |
@@ -71,6 +71,7 @@ python -m readmenator /path/to/project --svg # graph.svg (
71
71
  python -m readmenator /path/to/project --graphml # graph.graphml (Gephi/yEd)
72
72
  python -m readmenator /path/to/project obsidian # Obsidian vault (wikilinks)
73
73
  python -m readmenator /path/to/project wiki # Agent wiki (index + community pages)
74
+ python -m readmenator /path/to/project components # Component diagrams (analysis.json + graph LR markdown + index.html)
74
75
  python -m readmenator /path/to/project lint-wiki # Wiki health check
75
76
  python -m readmenator /path/to/project lint # Architecture violations (exit 1 on errors)
76
77
  python -m readmenator /path/to/project strip-dead-code # Orphaned symbol report
@@ -179,6 +180,49 @@ external in a 2D map or a 3D space:
179
180
  `#path=<a>~<b>`, `#lens=cycles`, `#edge=<key>`. The page also exposes
180
181
  `window.ReadmenatorExplorer` for console scripting.
181
182
 
183
+ The **Edge Bundle Explorer** (`readmenator-maps/graph-bundle.html`, its own gallery
184
+ card next to the force graph, `readmenator . bundles` to export it alone) is the
185
+ hierarchical edge bundling view from the video, live. It needs no network: one
186
+ canvas, no CDN.
187
+
188
+ - **Circle (2D).** Files sit on a ring grouped into community arcs (hubs first);
189
+ every resolved import is a B-spline routed through the community tree, so thick
190
+ bundles are the real seams between subsystems.
191
+ - **Sphere (3D).** The same hierarchy on a globe: each community owns a contiguous
192
+ cap sized by its file count, wires dive through the core between caps. Drag to
193
+ rotate, wheel to zoom, optional auto-rotate; selecting a file or community flies
194
+ the camera to face it.
195
+ - **Reading it.** Hover a file: cyan wires are what it imports, pink what imports it.
196
+ Click to pin it (imports and importers listed, one click to open it in the force
197
+ graph in 2D or 3D). Click an arc, cap label or legend row to focus a community
198
+ (inside/out/in counts, cohesion, top flows to other communities).
199
+ - **Controls.** Beta slider (0 straight chords, 1 fully bundled, recomputed live),
200
+ crossing-only filter, direction (both, imports, imported by), color by community,
201
+ layer or language, search, PNG export, light/dark theme. Deep links:
202
+ `#view=3d&node=<id>&group=<key>&beta=0.7&color=layer&dir=out&cross=1`; console API
203
+ `window.ReadmenatorBundles`.
204
+
205
+ ### Component Diagrams
206
+
207
+ `readmenator-diagrams/` holds a component architecture map built with zero
208
+ tokens: `analysis.json` (components with key entities and file/line spans,
209
+ relations with method-level call evidence), `overview.md` with the `graph LR`
210
+ diagram, one page per expandable component, and `index.html` — the diagram
211
+ drawn as an offline interactive page in the readmenator dark theme (layered
212
+ left-to-right boxes enriched with key symbols, layer colors and PageRank hubs,
213
+ labeled arrows weighted by call/import evidence, hover descriptions,
214
+ click-to-component, pan/zoom, PNG export). The maps gallery links it with a
215
+ **Component Diagrams** card that opens a self-contained copy living inside the
216
+ maps directory itself, so the link never leaves the site (safe on GitHub Pages
217
+ project subpaths, where `../..` hrefs would escape the project). The docs site
218
+ ships the markdown in its reader. No external service needed: structure and
219
+ call evidence are pure static analysis; a local Ollama daemon only ever
220
+ enriches prose descriptions, and only when `OLLAMA_ENABLED` is set.
221
+
222
+ ```bash
223
+ python -m readmenator /path/to/project components # rebuild only the diagrams
224
+ ```
225
+
182
226
  Serve the `docs/` directory directly with GitHub Pages (Settings -> Pages ->
183
227
  Deploy from branch -> folder `docs/`). The gallery `index.html` links every map
184
228
  with relative paths, works fully offline, and needs no build step.
@@ -189,13 +233,20 @@ gallery, every `--rebuild` refreshes it (video and docs included).
189
233
 
190
234
  ### Overview Video
191
235
 
192
- `readmenator . video` renders a synthwave mp4 from real scan data in seven acts:
236
+ `readmenator . video` renders a synthwave mp4 from real scan data in nine acts:
193
237
  layers, god nodes, blast-radius tree, communities, **Emergence** (ForceAtlas2
194
238
  LinLog with adaptive speed, animated from seeded chaos to convergence, nodes
195
- sized by PageRank with random-surfer particles on the hottest edges), **The Wiring**
196
- (Holten hierarchical edge bundling: files on a circle by community, imports routed
197
- as B-splines through the community tree, a spotlight sweeping each community and a
198
- live flow ranking), and code DNA.
239
+ sized by PageRank with random-surfer particles on the hottest edges), **Orbit**
240
+ (the force graph laid out by ForceAtlas2 in 3D and flown by a camera: color by
241
+ community, layer and language in turn, a tour that zooms into the largest
242
+ communities with their cohesion and seams, then the 1-hop reach of the top hub),
243
+ **The Wiring** (Holten hierarchical edge bundling: files on a circle by community,
244
+ imports routed as B-splines through the community tree, a spotlight sweeping each
245
+ community and a live flow ranking), **The Sphere** (the 3D layout folds onto a globe
246
+ of community caps and every import bundles through its core), and code DNA. A
247
+ closing invitation shows both explorers spinning with their paths, so viewers know
248
+ where to go next. Set an act's duration (`VIDEO_ORBIT_S`, `VIDEO_SPHERE_S`,
249
+ `VIDEO_INVITE_S`, ...) to 0 to drop it with its card.
199
250
 
200
251
  ### GraphRAG for agents (zero tokens to build, cheap to query)
201
252
 
@@ -307,9 +358,15 @@ Supported target languages (12): C++, Java, C#, Python, Go, Rust, PHP, Kotlin, S
307
358
  | Watcher | `_watcher.py` | Filesystem polling watcher for auto-rebuild |
308
359
  | README Injector | `_readme_injector.py` | Auto-injects KB link into project README |
309
360
  | GraphRAG | `_graphrag.py` | Entities, relationships, text units, community report hierarchy, local/global search |
310
- | Graph layouts | `_graphlayout.py` | ForceAtlas2 snapshots and hierarchical edge bundling |
361
+ | Graph layouts | `_graphlayout.py` | ForceAtlas2 (2D/3D) snapshots, circular and spherical hierarchical edge bundling |
362
+ | Edge bundles | `_bundlegraph.py` | Circle + sphere bundle payload, settings, thumbnail |
363
+ | Bundle page | `_bundlegraph_page.py` | Self-contained canvas page: 2D circle, 3D sphere, live beta, focus panels |
311
364
  | Force graph | `_forcegraph.py` | Heterogeneous explorer payload, settings, thumbnail |
312
365
  | Explorer page | `_forcegraph_page.py` | 2D/3D explorer HTML: hit-testing, overlay glyphs, node and edge actions |
366
+ | Source viewer | `_sourceview.py` | Bounded per-file source texts for the explorer View drawer |
367
+ | Symbol index | `_symindex.py` | Definition spans, call sites with lines, BUILTIN/SAME_FILE/IMPORTED/UNIQUE/AMBIGUOUS/UNRESOLVED resolver |
368
+ | Component diagrams | `_components.py` | analysis.json, graph LR markdown, offline interactive index.html, gallery card |
369
+ | Local Ollama | `_ollama.py` | Optional localhost LLM client for prose only (bounded, never fatal) |
313
370
  | Memory | `_memory.py` | MEMORY.md: declared rules, measured baselines, preserved session log |
314
371
  | Skills | `_skill_installer.py` | Installs packaged agent skills from `_skills/` |
315
372
  | Application | `_app.py` | Application orchestrator |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "readmenator"
7
- version = "1.3.2"
7
+ version = "1.3.3"
8
8
  description = "Zero-token polyglot codebase knowledge graph generator"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -29,6 +29,9 @@ from readmenator._diagrams import ( # noqa: F401
29
29
  VisNetworkRenderer,
30
30
  )
31
31
  from readmenator._mcp_server import MCPServer # noqa: F401
32
+ from readmenator._components import ComponentDiagramBuilder, sanitize # noqa: F401
33
+ from readmenator._ollama import OllamaClient # noqa: F401
34
+ from readmenator._symindex import SymbolIndex # noqa: F401
32
35
  from readmenator._concepts import ConceptExtractor, verb_for_relation # noqa: F401
33
36
  from readmenator._models import ( # noqa: F401
34
37
  AnalysisResult,
@@ -54,6 +54,8 @@ def build_parser() -> argparse.ArgumentParser:
54
54
  " gh-wiki --dry-run Render GitHub wiki pages locally, no git calls\n"
55
55
  " explorer Serve force-graph explorer locally\n"
56
56
  " forcegraph Export force-graph explorer HTML (readmenator-maps/graph-force.html)\n"
57
+ " bundles Export edge bundle explorer HTML, circle + sphere (readmenator-maps/graph-bundle.html)\n"
58
+ " components Export component diagrams (analysis.json + graph LR markdown + index.html)\n"
57
59
  " analytics Print corpus analytics JSON (funnel, layers, hotspots)\n"
58
60
  " near <file|text> Nearest files by scan-text similarity (offline Jaccard)\n"
59
61
  " scan-text Print synthesized scan-text blobs per file\n"
@@ -327,6 +329,15 @@ def main() -> None:
327
329
  out = app.export_forcegraph(target)
328
330
  print(out)
329
331
  return
332
+ elif command == "bundles":
333
+ out = app.export_bundlegraph(target)
334
+ print(out)
335
+ return
336
+ elif command == "components":
337
+ written = app.export_components(target)
338
+ for kind, path in sorted(written.items()):
339
+ print(f"{kind}: {path}")
340
+ return
330
341
  elif command == "analytics":
331
342
  import json as _json
332
343