diff --git a/crates/domain/tests/boundary_rule_tests.rs b/crates/domain/tests/boundary_rule_tests.rs
index 6dae49a..f51f621 100644
--- a/crates/domain/tests/boundary_rule_tests.rs
+++ b/crates/domain/tests/boundary_rule_tests.rs
@@ -1,6 +1,6 @@
use archlens_domain::{
BoundaryRule, CodeElement, CodeElementKind, CodeGraph, FilePath, ModuleName, Relationship,
- RelationshipKind, RuleViolation, check_boundary_rules,
+ RelationshipKind, check_boundary_rules,
};
fn make_element(name: &str, module: &str) -> CodeElement {
diff --git a/crates/domain/tests/code_graph_tests.rs b/crates/domain/tests/code_graph_tests.rs
index 5480264..9c5a891 100644
--- a/crates/domain/tests/code_graph_tests.rs
+++ b/crates/domain/tests/code_graph_tests.rs
@@ -181,10 +181,7 @@ fn qualify_disambiguates_target_by_source_module() {
rel = rel.with_source_file(
archlens_domain::FilePath::new("src/commons/global_audience.rs").unwrap(),
);
- // Make GlobalAudienceDefinition's element file match
- let mut gad = make_element("GlobalAudienceDefinition", Some("Commons"));
- // rebuild with matching file_path
- gad = CodeElement::new(
+ let gad = CodeElement::new(
"GlobalAudienceDefinition",
archlens_domain::CodeElementKind::Class,
archlens_domain::FilePath::new("src/commons/global_audience.rs").unwrap(),
diff --git a/docs/arch/ascii/module.txt b/docs/arch/ascii/module.txt
new file mode 100644
index 0000000..39ac5c6
--- /dev/null
+++ b/docs/arch/ascii/module.txt
@@ -0,0 +1,144 @@
+╔══════════════════════════════════════╗
+║ Architecture Overview ║
+╠══════════════════════════════════════╣
+║ Elements: 61 Modules: 4 ║
+║ Relationships: 59 ║
+╚══════════════════════════════════════╝
+
+┌─ Adapters (30 types)
+│
+│ ├── [str] AsciiRenderer
+│ ├── [str] D2Renderer
+│ ├── [str] CargoWorkspaceAnalyzer
+│ ├── [str] WorkspaceToml
+│ ├── [str] WorkspaceSection
+│ ├── [str] MemberToml
+│ ├── [str] PackageSection
+│ ├── [str] PythonProjectAnalyzer
+│ ├── [str] ProjectSection
+│ ├── [str] PoetrySection
+│ ├── [str] ToolSection
+│ ├── [str] PyprojectToml
+│ ├── [str] StdoutOutputWriter
+│ ├── [str] FileOutputWriter
+│ ├── [enm] OutputPath
+│ ├── [str] MermaidRenderer
+│ ├── [trt] LanguageExtractor
+│ ├── [str] TreeSitterAnalyzer
+│ ├── [str] RustExtractor
+│ ├── [str] PythonExtractor
+│ ├── [str] WalkdirDiscovery
+│ ├── [str] HtmlRenderer
+│ ├── [str] GraphData
+│ ├── [str] NodeData
+│ ├── [str] EdgeData
+│ ├── [str] RawRules
+│ ├── [str] RawConfig
+│ ├── [str] RawAnalysis
+│ ├── [str] RawOutput
+│ └── [str] TomlConfigLoader
+└───
+
+┌─ Application (2 types)
+│
+│ ├── [str] AnalyzeCodebase
+│ └── [str] AnalyzeCodebaseResult
+└───
+
+┌─ Domain (27 types)
+│
+│ ├── [str] Relationship
+│ ├── [str] CodeElement
+│ ├── [enm] DomainError
+│ ├── [trt] DiagramRenderer
+│ ├── [trt] SourceAnalyzer
+│ ├── [trt] ConfigLoader
+│ ├── [trt] FileDiscovery
+│ ├── [trt] ProjectAnalyzer
+│ ├── [trt] OutputWriter
+│ ├── [str] AnalysisResult
+│ ├── [str] AnalysisConfig
+│ ├── [str] AnalysisWarning
+│ ├── [enm] CodeElementKind
+│ ├── [enm] RelationshipKind
+│ ├── [enm] Visibility
+│ ├── [enm] DiagramLevel
+│ ├── [str] OutputConfig
+│ ├── [str] RenderedFile
+│ ├── [str] RenderOutput
+│ ├── [str] ModuleName
+│ ├── [enm] Language
+│ ├── [str] SourceFile
+│ ├── [str] FilePath
+│ ├── [enm] RuleKind
+│ ├── [str] RuleViolation
+│ ├── [str] BoundaryRule
+│ └── [str] CodeGraph
+└───
+
+┌─ Presentation (2 types)
+│
+│ ├── [str] Cli
+│ └── [enm] Command
+└───
+
+── Relationships ──
+ Adapters::AsciiRenderer ─[extends]─> Domain::DiagramRenderer
+ Adapters::D2Renderer ─[has]─> Domain::DiagramLevel
+ Adapters::D2Renderer ─[extends]─> Domain::DiagramRenderer
+ Adapters::CargoWorkspaceAnalyzer ─[extends]─> Domain::ProjectAnalyzer
+ Adapters::ToolSection ─[has]─> Adapters::PoetrySection
+ Adapters::PyprojectToml ─[has]─> Adapters::ToolSection
+ Adapters::PythonProjectAnalyzer ─[extends]─> Domain::ProjectAnalyzer
+ Adapters::StdoutOutputWriter ─[extends]─> Domain::OutputWriter
+ Adapters::FileOutputWriter ─[has]─> Adapters::OutputPath
+ Adapters::FileOutputWriter ─[extends]─> Domain::OutputWriter
+ Adapters::MermaidRenderer ─[has]─> Domain::DiagramLevel
+ Adapters::MermaidRenderer ─[extends]─> Domain::DiagramRenderer
+ Adapters::TreeSitterAnalyzer ─[has]─> Adapters::RustExtractor
+ Adapters::TreeSitterAnalyzer ─[has]─> Adapters::PythonExtractor
+ Adapters::TreeSitterAnalyzer ─[extends]─> Domain::SourceAnalyzer
+ Adapters::RustExtractor ─[extends]─> Adapters::LanguageExtractor
+ Adapters::PythonExtractor ─[extends]─> Adapters::LanguageExtractor
+ Adapters::WalkdirDiscovery ─[extends]─> Domain::FileDiscovery
+ Adapters::HtmlRenderer ─[extends]─> Domain::DiagramRenderer
+ Adapters::RawConfig ─[has]─> Adapters::RawAnalysis
+ Adapters::RawConfig ─[has]─> Adapters::RawOutput
+ Adapters::RawConfig ─[has]─> Adapters::RawRules
+ Adapters::TomlConfigLoader ─[has]─> Adapters::RawConfig
+ Adapters::TomlConfigLoader ─[extends]─> Domain::ConfigLoader
+ Application::AnalyzeCodebaseResult ─[has]─> Domain::CodeGraph
+ Domain::Relationship ─[has]─> Domain::RelationshipKind
+ Domain::CodeElement ─[has]─> Domain::CodeElementKind
+ Domain::CodeElement ─[has]─> Domain::FilePath
+ Domain::CodeElement ─[has]─> Domain::Visibility
+ Domain::AnalysisConfig ─[has]─> Domain::DiagramLevel
+ Domain::AnalysisWarning ─[has]─> Domain::FilePath
+ Domain::SourceFile ─[has]─> Domain::FilePath
+ Domain::SourceFile ─[has]─> Domain::Language
+ Domain::RuleViolation ─[has]─> Domain::RuleKind
+ Application ─[has]─> Domain
+ Presentation ─[has]─> Adapters
+ Presentation ─[has]─> Adapters
+ Presentation ─[has]─> Adapters
+ Presentation ─[has]─> Adapters
+ Presentation ─[has]─> Domain
+ Presentation ─[has]─> Adapters
+ Presentation ─[has]─> Adapters
+ Presentation ─[has]─> Adapters
+ Presentation ─[has]─> Adapters
+ Presentation ─[has]─> Adapters
+ Presentation ─[has]─> Adapters
+ Presentation ─[has]─> Application
+ Presentation ─[has]─> Adapters
+ Adapters ─[has]─> Domain
+ Adapters ─[has]─> Domain
+ Adapters ─[has]─> Domain
+ Adapters ─[has]─> Domain
+ Adapters ─[has]─> Domain
+ Adapters ─[has]─> Domain
+ Adapters ─[has]─> Domain
+ Adapters ─[has]─> Domain
+ Adapters ─[has]─> Domain
+ Adapters ─[has]─> Domain
+ Adapters ─[has]─> Domain
\ No newline at end of file
diff --git a/docs/arch/ascii/project.txt b/docs/arch/ascii/project.txt
new file mode 100644
index 0000000..95782ba
--- /dev/null
+++ b/docs/arch/ascii/project.txt
@@ -0,0 +1,54 @@
+╔══════════════════════════════════════╗
+║ Architecture Overview ║
+╠══════════════════════════════════════╣
+║ Elements: 14 Modules: 1 ║
+║ Relationships: 25 ║
+╚══════════════════════════════════════╝
+
+┌─ (ungrouped)
+│ [prj] archlens-domain
+│ [prj] archlens-application
+│ [prj] archlens
+└───
+
+┌─ Adapters (11 types)
+│
+│ ├── [prj] archlens-tree-sitter
+│ ├── [prj] archlens-walkdir
+│ ├── [prj] archlens-mermaid
+│ ├── [prj] archlens-ascii
+│ ├── [prj] archlens-file-writer
+│ ├── [prj] archlens-stdout-writer
+│ ├── [prj] archlens-toml-config
+│ ├── [prj] archlens-cargo-workspace
+│ ├── [prj] archlens-python-project
+│ ├── [prj] archlens-d2
+│ └── [prj] archlens-html
+└───
+
+── Relationships ──
+ archlens-application ─[has]─> archlens-domain
+ archlens ─[has]─> archlens-tree-sitter
+ archlens ─[has]─> archlens-ascii
+ archlens ─[has]─> archlens-stdout-writer
+ archlens ─[has]─> archlens-application
+ archlens ─[has]─> archlens-walkdir
+ archlens ─[has]─> archlens-d2
+ archlens ─[has]─> archlens-html
+ archlens ─[has]─> archlens-mermaid
+ archlens ─[has]─> archlens-file-writer
+ archlens ─[has]─> archlens-domain
+ archlens ─[has]─> archlens-cargo-workspace
+ archlens ─[has]─> archlens-toml-config
+ archlens ─[has]─> archlens-python-project
+ archlens-tree-sitter ─[has]─> archlens-domain
+ archlens-walkdir ─[has]─> archlens-domain
+ archlens-mermaid ─[has]─> archlens-domain
+ archlens-ascii ─[has]─> archlens-domain
+ archlens-file-writer ─[has]─> archlens-domain
+ archlens-stdout-writer ─[has]─> archlens-domain
+ archlens-toml-config ─[has]─> archlens-domain
+ archlens-cargo-workspace ─[has]─> archlens-domain
+ archlens-python-project ─[has]─> archlens-domain
+ archlens-d2 ─[has]─> archlens-domain
+ archlens-html ─[has]─> archlens-domain
\ No newline at end of file
diff --git a/docs/arch/d2/module.d2 b/docs/arch/d2/module.d2
new file mode 100644
index 0000000..a594a87
--- /dev/null
+++ b/docs/arch/d2/module.d2
@@ -0,0 +1,6 @@
+Adapters: Adapters
+Domain: Domain
+Application: Application
+Presentation: Presentation
+Application -> Domain
+Adapters -> Domain
\ No newline at end of file
diff --git a/docs/arch/d2/project.d2 b/docs/arch/d2/project.d2
new file mode 100644
index 0000000..c80e659
--- /dev/null
+++ b/docs/arch/d2/project.d2
@@ -0,0 +1,41 @@
+Adapters: {
+ archlens_tree_sitter: archlens-tree-sitter
+ archlens_walkdir: archlens-walkdir
+ archlens_mermaid: archlens-mermaid
+ archlens_ascii: archlens-ascii
+ archlens_file_writer: archlens-file-writer
+ archlens_stdout_writer: archlens-stdout-writer
+ archlens_toml_config: archlens-toml-config
+ archlens_cargo_workspace: archlens-cargo-workspace
+ archlens_python_project: archlens-python-project
+ archlens_d2: archlens-d2
+ archlens_html: archlens-html
+}
+archlens_domain: archlens-domain
+archlens_application: archlens-application
+archlens: archlens
+archlens_application -> archlens_domain
+archlens -> archlens_domain
+archlens -> archlens_file_writer
+archlens -> archlens_mermaid
+archlens -> archlens_html
+archlens -> archlens_python_project
+archlens -> archlens_walkdir
+archlens -> archlens_ascii
+archlens -> archlens_toml_config
+archlens -> archlens_stdout_writer
+archlens -> archlens_application
+archlens -> archlens_d2
+archlens -> archlens_tree_sitter
+archlens -> archlens_cargo_workspace
+archlens_tree_sitter -> archlens_domain
+archlens_walkdir -> archlens_domain
+archlens_mermaid -> archlens_domain
+archlens_ascii -> archlens_domain
+archlens_file_writer -> archlens_domain
+archlens_stdout_writer -> archlens_domain
+archlens_toml_config -> archlens_domain
+archlens_cargo_workspace -> archlens_domain
+archlens_python_project -> archlens_domain
+archlens_d2 -> archlens_domain
+archlens_html -> archlens_domain
\ No newline at end of file
diff --git a/docs/arch/d2/type.d2 b/docs/arch/d2/type.d2
new file mode 100644
index 0000000..574a0de
--- /dev/null
+++ b/docs/arch/d2/type.d2
@@ -0,0 +1,448 @@
+Domain: {
+ Relationship: {
+ shape: class
+ source: String
+ target: String
+ kind: RelationshipKind
+ source_file: Option
+ new()
+ with_source_file()
+ source()
+ target()
+ kind()
+ source_file()
+ }
+ CodeElement: {
+ shape: class
+ name: String
+ qualified_name: Option
+ kind: CodeElementKind
+ file_path: FilePath
+ line: usize
+ visibility: Visibility
+ module: Option
+ generics: Vec
+ attributes: Vec
+ fields: Vec
+ methods: Vec
+ new()
+ with_visibility()
+ with_module()
+ with_generics()
+ with_attributes()
+ with_qualified_name()
+ name()
+ qualified_name()
+ kind()
+ file_path()
+ line()
+ visibility()
+ module()
+ generics()
+ attributes()
+ with_fields()
+ with_methods()
+ fields()
+ methods()
+ }
+ DomainError: {
+ shape: class
+ }
+ DiagramRenderer: {
+ shape: class
+ }
+ SourceAnalyzer: {
+ shape: class
+ }
+ ConfigLoader: {
+ shape: class
+ }
+ FileDiscovery: {
+ shape: class
+ }
+ ProjectAnalyzer: {
+ shape: class
+ }
+ OutputWriter: {
+ shape: class
+ }
+ AnalysisResult: {
+ shape: class
+ elements: Vec
+ relationships: Vec
+ warnings: Vec
+ new()
+ empty()
+ elements()
+ relationships()
+ warnings()
+ }
+ AnalysisConfig: {
+ shape: class
+ excludes: Vec
+ level: DiagramLevel
+ module_mappings: HashMap
+ scope: Option
+ include_tests: bool
+ changed_files: Option
+ with_excludes()
+ with_level()
+ with_module_mappings()
+ excludes()
+ level()
+ with_scope()
+ module_mappings()
+ scope()
+ with_include_tests()
+ include_tests()
+ with_changed_files()
+ changed_files()
+ }
+ AnalysisWarning: {
+ shape: class
+ file_path: FilePath
+ line: usize
+ message: String
+ new()
+ file_path()
+ line()
+ message()
+ }
+ CodeElementKind: {
+ shape: class
+ }
+ RelationshipKind: {
+ shape: class
+ }
+ Visibility: {
+ shape: class
+ }
+ DiagramLevel: {
+ shape: class
+ }
+ OutputConfig: {
+ shape: class
+ split_by_module: bool
+ output_path: Option
+ with_split_by_module()
+ with_output_path()
+ split_by_module()
+ output_path()
+ }
+ RenderedFile: {
+ shape: class
+ name: String
+ content: String
+ new()
+ name()
+ content()
+ }
+ RenderOutput: {
+ shape: class
+ files: Vec
+ new()
+ single()
+ files()
+ }
+ ModuleName: {
+ shape: class
+ new()
+ from_path()
+ from_directory_group()
+ capitalize()
+ as_str()
+ }
+ Language: {
+ shape: class
+ name()
+ }
+ SourceFile: {
+ shape: class
+ path: FilePath
+ language: Language
+ new()
+ path()
+ language()
+ }
+ FilePath: {
+ shape: class
+ new()
+ as_str()
+ }
+ RuleKind: {
+ shape: class
+ }
+ RuleViolation: {
+ shape: class
+ source_module: String
+ target_module: String
+ kind: RuleKind
+ new()
+ source_module()
+ target_module()
+ kind()
+ message()
+ }
+ BoundaryRule: {
+ shape: class
+ source: String
+ target: String
+ parse()
+ source()
+ target()
+ matches()
+ }
+ CodeGraph: {
+ shape: class
+ elements: Vec
+ relationships: Vec
+ new()
+ add_element()
+ add_relationship()
+ elements()
+ relationships()
+ modules()
+ elements_by_module()
+ resolve_relationships()
+ filter_external_imports()
+ qualify()
+ cross_module_deps_for()
+ subgraph_by_module()
+ }
+}
+Adapters: {
+ AsciiRenderer: {
+ shape: class
+ new()
+ format_kind()
+ }
+ D2Renderer: {
+ shape: class
+ level: DiagramLevel
+ new()
+ with_level()
+ }
+ CargoWorkspaceAnalyzer: {
+ shape: class
+ new()
+ }
+ WorkspaceToml: {
+ shape: class
+ workspace: Option
+ }
+ WorkspaceSection: {
+ shape: class
+ members: Vec
+ }
+ MemberToml: {
+ shape: class
+ package: Option
+ dependencies: HashMap
+ }
+ PackageSection: {
+ shape: class
+ name: String
+ }
+ PythonProjectAnalyzer: {
+ shape: class
+ new()
+ }
+ ProjectSection: {
+ shape: class
+ name: Option
+ dependencies: Vec
+ }
+ PoetrySection: {
+ shape: class
+ name: Option
+ dependencies: HashMap
+ }
+ ToolSection: {
+ shape: class
+ poetry: PoetrySection
+ }
+ PyprojectToml: {
+ shape: class
+ project: Option
+ tool: ToolSection
+ }
+ StdoutOutputWriter: {
+ shape: class
+ new()
+ }
+ FileOutputWriter: {
+ shape: class
+ output_path: OutputPath
+ new()
+ single_file()
+ }
+ OutputPath: {
+ shape: class
+ }
+ MermaidRenderer: {
+ shape: class
+ level: DiagramLevel
+ show_weights: bool
+ new()
+ with_level()
+ with_weights()
+ display_name()
+ format_element_name()
+ format_visibility()
+ render_class_diagram()
+ push_class_lines()
+ render_module_flowchart()
+ render_project_flowchart()
+ sanitize_id()
+ }
+ LanguageExtractor: {
+ shape: class
+ }
+ TreeSitterAnalyzer: {
+ shape: class
+ rust: RustExtractor
+ python: PythonExtractor
+ new()
+ extractor_for()
+ }
+ RustExtractor: {
+ shape: class
+ }
+ PythonExtractor: {
+ shape: class
+ }
+ WalkdirDiscovery: {
+ shape: class
+ new()
+ detect_language()
+ is_test_file()
+ is_excluded()
+ }
+ HtmlRenderer: {
+ shape: class
+ new()
+ }
+ GraphData: {
+ shape: class
+ nodes: Vec
+ edges: Vec
+ }
+ NodeData: {
+ shape: class
+ id: String
+ label: String
+ module: String
+ kind: String
+ fields: Vec
+ methods: Vec
+ }
+ EdgeData: {
+ shape: class
+ source: String
+ target: String
+ kind: String
+ }
+ RawRules: {
+ shape: class
+ allow: Vec
+ deny: Vec
+ }
+ RawConfig: {
+ shape: class
+ analysis: RawAnalysis
+ output: RawOutput
+ modules: HashMap
+ rules: RawRules
+ }
+ RawAnalysis: {
+ shape: class
+ exclude: Vec
+ level: Option
+ }
+ RawOutput: {
+ shape: class
+ format: Option
+ path: Option
+ split_by_module: bool
+ }
+ TomlConfigLoader: {
+ shape: class
+ raw: RawConfig
+ from_path()
+ parse_level()
+ }
+}
+Application: {
+ AnalyzeCodebase: {
+ shape: class
+ file_discovery: F
+ source_analyzer: S
+ new()
+ execute()
+ }
+ AnalyzeCodebaseResult: {
+ shape: class
+ graph: CodeGraph
+ warnings: Vec
+ graph()
+ warnings()
+ }
+}
+Presentation: {
+ Cli: {
+ shape: class
+ command: Option
+ path: PathBuf
+ level: String
+ format: String
+ output: Option
+ config: Option
+ scope: Option
+ exclude: Vec
+ include_tests: bool
+ no_weights: bool
+ watch: bool
+ since: Option
+ split_by_module: bool
+ strict: bool
+ check: bool
+ verbose: u8
+ }
+ Command: {
+ shape: class
+ }
+}
+Adapters_AsciiRenderer -> Domain_DiagramRenderer: {style.stroke-dash: 0}
+Adapters_D2Renderer -> Domain_DiagramLevel
+Adapters_D2Renderer -> Domain_DiagramRenderer: {style.stroke-dash: 0}
+Adapters_CargoWorkspaceAnalyzer -> Domain_ProjectAnalyzer: {style.stroke-dash: 0}
+Adapters_ToolSection -> Adapters_PoetrySection
+Adapters_PyprojectToml -> Adapters_ToolSection
+Adapters_PythonProjectAnalyzer -> Domain_ProjectAnalyzer: {style.stroke-dash: 0}
+Adapters_StdoutOutputWriter -> Domain_OutputWriter: {style.stroke-dash: 0}
+Adapters_FileOutputWriter -> Adapters_OutputPath
+Adapters_FileOutputWriter -> Domain_OutputWriter: {style.stroke-dash: 0}
+Adapters_MermaidRenderer -> Domain_DiagramLevel
+Adapters_MermaidRenderer -> Domain_DiagramRenderer: {style.stroke-dash: 0}
+Adapters_TreeSitterAnalyzer -> Adapters_RustExtractor
+Adapters_TreeSitterAnalyzer -> Adapters_PythonExtractor
+Adapters_TreeSitterAnalyzer -> Domain_SourceAnalyzer: {style.stroke-dash: 0}
+Adapters_RustExtractor -> Adapters_LanguageExtractor: {style.stroke-dash: 0}
+Adapters_PythonExtractor -> Adapters_LanguageExtractor: {style.stroke-dash: 0}
+Adapters_WalkdirDiscovery -> Domain_FileDiscovery: {style.stroke-dash: 0}
+Adapters_HtmlRenderer -> Domain_DiagramRenderer: {style.stroke-dash: 0}
+Adapters_RawConfig -> Adapters_RawAnalysis
+Adapters_RawConfig -> Adapters_RawOutput
+Adapters_RawConfig -> Adapters_RawRules
+Adapters_TomlConfigLoader -> Adapters_RawConfig
+Adapters_TomlConfigLoader -> Domain_ConfigLoader: {style.stroke-dash: 0}
+Application_AnalyzeCodebaseResult -> Domain_CodeGraph
+Domain_Relationship -> Domain_RelationshipKind
+Domain_CodeElement -> Domain_CodeElementKind
+Domain_CodeElement -> Domain_FilePath
+Domain_CodeElement -> Domain_Visibility
+Domain_AnalysisConfig -> Domain_DiagramLevel
+Domain_AnalysisWarning -> Domain_FilePath
+Domain_SourceFile -> Domain_FilePath
+Domain_SourceFile -> Domain_Language
+Domain_RuleViolation -> Domain_RuleKind
\ No newline at end of file
diff --git a/docs/arch/html/archlens.html b/docs/arch/html/archlens.html
new file mode 100644
index 0000000..bd53287
--- /dev/null
+++ b/docs/arch/html/archlens.html
@@ -0,0 +1,142 @@
+
+
+
+
+
+Architecture Diagram
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/arch/lucy/lucy.html b/docs/arch/lucy/lucy.html
new file mode 100644
index 0000000..e702ea2
--- /dev/null
+++ b/docs/arch/lucy/lucy.html
@@ -0,0 +1,142 @@
+
+
+
+
+
+Architecture Diagram
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/arch/lucy/module/aiss_worker.mmd b/docs/arch/lucy/module/aiss_worker.mmd
new file mode 100644
index 0000000..2f18ff2
--- /dev/null
+++ b/docs/arch/lucy/module/aiss_worker.mmd
@@ -0,0 +1,9 @@
+graph TD
+ Aiss_worker[Aiss_worker]
+ class aiss_worker_module["Aiss_worker"] {
+ <>
+ }
+ class commons_module["Commons"] {
+ <>
+ }
+ aiss_worker_module --> commons_module : 1 dep
\ No newline at end of file
diff --git a/docs/arch/lucy/module/api.mmd b/docs/arch/lucy/module/api.mmd
new file mode 100644
index 0000000..fa42809
--- /dev/null
+++ b/docs/arch/lucy/module/api.mmd
@@ -0,0 +1,9 @@
+graph TD
+ Api[Api]
+ class api_module["Api"] {
+ <>
+ }
+ class commons_module["Commons"] {
+ <>
+ }
+ api_module --> commons_module : 3 deps
\ No newline at end of file
diff --git a/docs/arch/lucy/module/commons.mmd b/docs/arch/lucy/module/commons.mmd
new file mode 100644
index 0000000..caf93f1
--- /dev/null
+++ b/docs/arch/lucy/module/commons.mmd
@@ -0,0 +1,2 @@
+graph TD
+ Commons[Commons]
\ No newline at end of file
diff --git a/docs/arch/lucy/module/overview.mmd b/docs/arch/lucy/module/overview.mmd
new file mode 100644
index 0000000..4bd40ab
--- /dev/null
+++ b/docs/arch/lucy/module/overview.mmd
@@ -0,0 +1,10 @@
+graph TD
+ Aiss_worker[Aiss_worker]
+ Api[Api]
+ Worker[Worker]
+ Commons[Commons]
+ Worker -->|1 dep| Api
+ Aiss_worker -->|7 deps| Commons
+ Aiss_worker -->|1 dep| Api
+ Api -->|23 deps| Commons
+ Worker -->|12 deps| Commons
\ No newline at end of file
diff --git a/docs/arch/lucy/module/worker.mmd b/docs/arch/lucy/module/worker.mmd
new file mode 100644
index 0000000..6baf981
--- /dev/null
+++ b/docs/arch/lucy/module/worker.mmd
@@ -0,0 +1,9 @@
+graph TD
+ Worker[Worker]
+ class worker_module["Worker"] {
+ <>
+ }
+ class commons_module["Commons"] {
+ <>
+ }
+ worker_module --> commons_module : 2 deps
\ No newline at end of file
diff --git a/docs/arch/lucy/project.mmd b/docs/arch/lucy/project.mmd
new file mode 100644
index 0000000..e7321ee
--- /dev/null
+++ b/docs/arch/lucy/project.mmd
@@ -0,0 +1,8 @@
+graph TD
+ aiss_worker[aiss-worker]
+ commons[commons]
+ worker[worker]
+ api[api]
+ aiss_worker --> commons
+ worker --> commons
+ api --> commons
\ No newline at end of file
diff --git a/docs/arch/mermaid/module.mmd b/docs/arch/mermaid/module.mmd
new file mode 100644
index 0000000..b8d67cd
--- /dev/null
+++ b/docs/arch/mermaid/module.mmd
@@ -0,0 +1,10 @@
+graph TD
+ Adapters[Adapters]
+ Presentation[Presentation]
+ Application[Application]
+ Domain[Domain]
+ Presentation -->|1 dep| Application
+ Application -->|2 deps| Domain
+ Presentation -->|11 deps| Adapters
+ Presentation -->|1 dep| Domain
+ Adapters -->|24 deps| Domain
\ No newline at end of file
diff --git a/docs/arch/mermaid/project.mmd b/docs/arch/mermaid/project.mmd
new file mode 100644
index 0000000..33def04
--- /dev/null
+++ b/docs/arch/mermaid/project.mmd
@@ -0,0 +1,42 @@
+graph TD
+ archlens_domain[archlens-domain]
+ archlens_application[archlens-application]
+ archlens[archlens]
+ subgraph Adapters
+ archlens_tree_sitter[archlens-tree-sitter]
+ archlens_walkdir[archlens-walkdir]
+ archlens_mermaid[archlens-mermaid]
+ archlens_ascii[archlens-ascii]
+ archlens_file_writer[archlens-file-writer]
+ archlens_stdout_writer[archlens-stdout-writer]
+ archlens_toml_config[archlens-toml-config]
+ archlens_cargo_workspace[archlens-cargo-workspace]
+ archlens_python_project[archlens-python-project]
+ archlens_d2[archlens-d2]
+ archlens_html[archlens-html]
+ end
+ archlens_application --> archlens_domain
+ archlens --> archlens_file_writer
+ archlens --> archlens_domain
+ archlens --> archlens_cargo_workspace
+ archlens --> archlens_d2
+ archlens --> archlens_html
+ archlens --> archlens_mermaid
+ archlens --> archlens_toml_config
+ archlens --> archlens_python_project
+ archlens --> archlens_ascii
+ archlens --> archlens_tree_sitter
+ archlens --> archlens_application
+ archlens --> archlens_walkdir
+ archlens --> archlens_stdout_writer
+ archlens_tree_sitter --> archlens_domain
+ archlens_walkdir --> archlens_domain
+ archlens_mermaid --> archlens_domain
+ archlens_ascii --> archlens_domain
+ archlens_file_writer --> archlens_domain
+ archlens_stdout_writer --> archlens_domain
+ archlens_toml_config --> archlens_domain
+ archlens_cargo_workspace --> archlens_domain
+ archlens_python_project --> archlens_domain
+ archlens_d2 --> archlens_domain
+ archlens_html --> archlens_domain
\ No newline at end of file
diff --git a/docs/arch/mermaid/type/adapters.mmd b/docs/arch/mermaid/type/adapters.mmd
new file mode 100644
index 0000000..d52d978
--- /dev/null
+++ b/docs/arch/mermaid/type/adapters.mmd
@@ -0,0 +1,137 @@
+classDiagram
+ namespace Adapters {
+ class AsciiRenderer
+ class D2Renderer
+ class CargoWorkspaceAnalyzer
+ class WorkspaceToml
+ class WorkspaceSection
+ class MemberToml
+ class PackageSection
+ class PythonProjectAnalyzer
+ class ProjectSection
+ class PoetrySection
+ class ToolSection
+ class PyprojectToml
+ class StdoutOutputWriter
+ class FileOutputWriter
+ class OutputPath
+ class MermaidRenderer
+ class LanguageExtractor
+ class TreeSitterAnalyzer
+ class RustExtractor
+ class PythonExtractor
+ class WalkdirDiscovery
+ class HtmlRenderer
+ class GraphData
+ class NodeData
+ class EdgeData
+ class RawRules
+ class RawConfig
+ class RawAnalysis
+ class RawOutput
+ class TomlConfigLoader
+ }
+ AsciiRenderer : +new() -] Self
+ AsciiRenderer : -format_kind(element CodeElement) -] static str
+ D2Renderer : level DiagramLevel
+ D2Renderer : +new() -] Self
+ D2Renderer : +with_level(level DiagramLevel) -] Self
+ CargoWorkspaceAnalyzer : +new() -] Self
+ <> WorkspaceToml
+ WorkspaceToml : workspace Option
+ <> WorkspaceSection
+ WorkspaceSection : members Vec
+ <> MemberToml
+ MemberToml : package Option
+ MemberToml : dependencies HashMap
+ <> PackageSection
+ PackageSection : name String
+ PythonProjectAnalyzer : +new() -] Self
+ <> ProjectSection
+ ProjectSection : name Option
+ ProjectSection : dependencies Vec
+ <> PoetrySection
+ PoetrySection : name Option
+ PoetrySection : dependencies HashMap
+ <> ToolSection
+ ToolSection : poetry PoetrySection
+ <> PyprojectToml
+ PyprojectToml : project Option
+ PyprojectToml : tool ToolSection
+ StdoutOutputWriter : +new() -] Self
+ FileOutputWriter : output_path OutputPath
+ FileOutputWriter : +new(output_dir PathBuf) -] Self
+ FileOutputWriter : +single_file(path PathBuf) -] Self
+ <> OutputPath
+ MermaidRenderer : level DiagramLevel
+ MermaidRenderer : show_weights bool
+ MermaidRenderer : +new() -] Self
+ MermaidRenderer : +with_level(level DiagramLevel) -] Self
+ MermaidRenderer : +with_weights(show bool) -] Self
+ MermaidRenderer : -display_name(qualified str) -] str
+ MermaidRenderer : -format_element_name(element CodeElement) -] String
+ MermaidRenderer : -format_visibility(visibility Visibility) -] static str
+ MermaidRenderer : -render_class_diagram(graph CodeGraph) -] String
+ MermaidRenderer : -push_class_lines(lines mut Vec[String], deferred mut Vec[String], element CodeElement, indent str, in_namespace bool)
+ MermaidRenderer : -render_module_flowchart(graph CodeGraph) -] String
+ MermaidRenderer : -render_project_flowchart(graph CodeGraph) -] String
+ MermaidRenderer : -sanitize_id(name str) -] String
+ TreeSitterAnalyzer : rust RustExtractor
+ TreeSitterAnalyzer : python PythonExtractor
+ TreeSitterAnalyzer : +new() -] Self
+ TreeSitterAnalyzer : -extractor_for(language Language) -] Option[dyn LanguageExtractor]
+ WalkdirDiscovery : +new() -] Self
+ WalkdirDiscovery : -detect_language(path Path) -] Option[Language]
+ WalkdirDiscovery : -is_test_file(path Path, language Language) -] bool
+ WalkdirDiscovery : -is_excluded(path Path, root Path, excludes [String]) -] bool
+ HtmlRenderer : +new() -] Self
+ <> GraphData
+ GraphData : nodes Vec
+ GraphData : edges Vec
+ <> NodeData
+ NodeData : id String
+ NodeData : label String
+ NodeData : module String
+ NodeData : kind String
+ NodeData : fields Vec
+ NodeData : methods Vec
+ <> EdgeData
+ EdgeData : source String
+ EdgeData : target String
+ EdgeData : kind String
+ <> RawRules
+ RawRules : allow Vec
+ RawRules : deny Vec
+ <> RawConfig
+ RawConfig : analysis RawAnalysis
+ RawConfig : output RawOutput
+ RawConfig : modules HashMap
+ RawConfig : rules RawRules
+ <> RawAnalysis
+ RawAnalysis : exclude Vec
+ RawAnalysis : level Option
+ <> RawOutput
+ RawOutput : format Option
+ RawOutput : path Option
+ RawOutput : split_by_module bool
+ TomlConfigLoader : raw RawConfig
+ TomlConfigLoader : +from_path(path Path) -] Result[Self, DomainError]
+ TomlConfigLoader : -parse_level(level Option[String]) -] DiagramLevel
+ ToolSection --> PoetrySection
+ PyprojectToml --> ToolSection
+ FileOutputWriter --> OutputPath
+ TreeSitterAnalyzer --> RustExtractor
+ TreeSitterAnalyzer --> PythonExtractor
+ RustExtractor <|-- LanguageExtractor
+ PythonExtractor <|-- LanguageExtractor
+ RawConfig --> RawAnalysis
+ RawConfig --> RawOutput
+ RawConfig --> RawRules
+ TomlConfigLoader --> RawConfig
+ class adapters_module["Adapters"] {
+ <>
+ }
+ class domain_module["Domain"] {
+ <>
+ }
+ adapters_module --> domain_module : 13 deps
\ No newline at end of file
diff --git a/docs/arch/mermaid/type/application.mmd b/docs/arch/mermaid/type/application.mmd
new file mode 100644
index 0000000..cb503f6
--- /dev/null
+++ b/docs/arch/mermaid/type/application.mmd
@@ -0,0 +1,20 @@
+classDiagram
+ namespace Application {
+ class AnalyzeCodebase
+ class AnalyzeCodebaseResult
+ }
+ AnalyzeCodebase : file_discovery F
+ AnalyzeCodebase : source_analyzer S
+ AnalyzeCodebase : +new(file_discovery F, source_analyzer S) -] Self
+ AnalyzeCodebase : +execute(root Path, config AnalysisConfig) -] Result[AnalyzeCodebaseResult, DomainError]
+ AnalyzeCodebaseResult : graph CodeGraph
+ AnalyzeCodebaseResult : warnings Vec
+ AnalyzeCodebaseResult : +graph() -] CodeGraph
+ AnalyzeCodebaseResult : +warnings() -] [AnalysisWarning]
+ class application_module["Application"] {
+ <>
+ }
+ class domain_module["Domain"] {
+ <>
+ }
+ application_module --> domain_module : 1 dep
\ No newline at end of file
diff --git a/docs/arch/mermaid/type/domain.mmd b/docs/arch/mermaid/type/domain.mmd
new file mode 100644
index 0000000..aa61177
--- /dev/null
+++ b/docs/arch/mermaid/type/domain.mmd
@@ -0,0 +1,168 @@
+classDiagram
+ namespace Domain {
+ class Relationship
+ class CodeElement
+ class DomainError
+ class DiagramRenderer
+ class SourceAnalyzer
+ class ConfigLoader
+ class FileDiscovery
+ class ProjectAnalyzer
+ class OutputWriter
+ class AnalysisResult
+ class AnalysisConfig
+ class AnalysisWarning
+ class CodeElementKind
+ class RelationshipKind
+ class Visibility
+ class DiagramLevel
+ class OutputConfig
+ class RenderedFile
+ class RenderOutput
+ class ModuleName
+ class Language
+ class SourceFile
+ class FilePath
+ class RuleKind
+ class RuleViolation
+ class BoundaryRule
+ class CodeGraph
+ }
+ Relationship : source String
+ Relationship : target String
+ Relationship : kind RelationshipKind
+ Relationship : source_file Option
+ Relationship : +new(source str, target str, kind RelationshipKind) -] Result[Self, DomainError]
+ Relationship : +with_source_file(file FilePath) -] Self
+ Relationship : +source() -] str
+ Relationship : +target() -] str
+ Relationship : +kind() -] RelationshipKind
+ Relationship : +source_file() -] Option[FilePath]
+ CodeElement : name String
+ CodeElement : qualified_name Option
+ CodeElement : kind CodeElementKind
+ CodeElement : file_path FilePath
+ CodeElement : line usize
+ CodeElement : visibility Visibility
+ CodeElement : module Option
+ CodeElement : generics Vec
+ CodeElement : attributes Vec
+ CodeElement : fields Vec
+ CodeElement : methods Vec
+ CodeElement : +new(name str, kind CodeElementKind, file_path FilePath, line usize) -] Result[Self, DomainError]
+ CodeElement : +with_visibility(visibility Visibility) -] Self
+ CodeElement : +with_module(module ModuleName) -] Self
+ CodeElement : +with_generics(generics Vec[String]) -] Self
+ CodeElement : +with_attributes(attributes Vec[String]) -] Self
+ CodeElement : +with_qualified_name(qn String) -] Self
+ CodeElement : +name() -] str
+ CodeElement : +qualified_name() -] str
+ CodeElement : +kind() -] CodeElementKind
+ CodeElement : +file_path() -] FilePath
+ CodeElement : +line() -] usize
+ CodeElement : +visibility() -] Visibility
+ CodeElement : +module() -] Option[ModuleName]
+ CodeElement : +generics() -] [String]
+ CodeElement : +attributes() -] [String]
+ CodeElement : +with_fields(fields Vec[String]) -] Self
+ CodeElement : +with_methods(methods Vec[String]) -] Self
+ CodeElement : +fields() -] [String]
+ CodeElement : +methods() -] [String]
+ AnalysisResult : elements Vec
+ AnalysisResult : relationships Vec
+ AnalysisResult : warnings Vec
+ AnalysisResult : +new(elements Vec[CodeElement], relationships Vec[Relationship], warnings Vec[AnalysisWarning]) -] Self
+ AnalysisResult : +empty() -] Self
+ AnalysisResult : +elements() -] [CodeElement]
+ AnalysisResult : +relationships() -] [Relationship]
+ AnalysisResult : +warnings() -] [AnalysisWarning]
+ AnalysisConfig : excludes Vec
+ AnalysisConfig : level DiagramLevel
+ AnalysisConfig : module_mappings HashMap
+ AnalysisConfig : scope Option
+ AnalysisConfig : include_tests bool
+ AnalysisConfig : changed_files Option
+ AnalysisConfig : +with_excludes(excludes Vec[String]) -] Self
+ AnalysisConfig : +with_level(level DiagramLevel) -] Self
+ AnalysisConfig : +with_module_mappings(mappings HashMap[String, String]) -] Self
+ AnalysisConfig : +excludes() -] [String]
+ AnalysisConfig : +level() -] DiagramLevel
+ AnalysisConfig : +with_scope(scope String) -] Self
+ AnalysisConfig : +module_mappings() -] HashMap[String, String]
+ AnalysisConfig : +scope() -] Option[str]
+ AnalysisConfig : +with_include_tests(include bool) -] Self
+ AnalysisConfig : +include_tests() -] bool
+ AnalysisConfig : +with_changed_files(files HashSet[String]) -] Self
+ AnalysisConfig : +changed_files() -] Option[HashSet[String]]
+ AnalysisWarning : file_path FilePath
+ AnalysisWarning : line usize
+ AnalysisWarning : message String
+ AnalysisWarning : +new(file_path FilePath, line usize, message str) -] Result[Self, DomainError]
+ AnalysisWarning : +file_path() -] FilePath
+ AnalysisWarning : +line() -] usize
+ AnalysisWarning : +message() -] str
+ OutputConfig : split_by_module bool
+ OutputConfig : output_path Option
+ OutputConfig : +with_split_by_module(split bool) -] Self
+ OutputConfig : +with_output_path(path String) -] Self
+ OutputConfig : +split_by_module() -] bool
+ OutputConfig : +output_path() -] Option[str]
+ RenderedFile : name String
+ RenderedFile : content String
+ RenderedFile : +new(name str, content str) -] Result[Self, DomainError]
+ RenderedFile : +name() -] str
+ RenderedFile : +content() -] str
+ RenderOutput : files Vec
+ RenderOutput : +new(files Vec[RenderedFile]) -] Self
+ RenderOutput : +single(file RenderedFile) -] Self
+ RenderOutput : +files() -] [RenderedFile]
+ ModuleName : +new(value str) -] Result[Self, DomainError]
+ ModuleName : +from_path(file_path str, root Path, module_mappings HashMap[String, String]) -] Option[Self]
+ ModuleName : +from_directory_group(member_path str) -] Option[Self]
+ ModuleName : +capitalize(s str) -] String
+ ModuleName : +as_str() -] str
+ Language : +name() -] static str
+ SourceFile : path FilePath
+ SourceFile : language Language
+ SourceFile : +new(path FilePath, language Language) -] Self
+ SourceFile : +path() -] FilePath
+ SourceFile : +language() -] Language
+ FilePath : +new(value str) -] Result[Self, DomainError]
+ FilePath : +as_str() -] str
+ RuleViolation : source_module String
+ RuleViolation : target_module String
+ RuleViolation : kind RuleKind
+ RuleViolation : +new(source_module str, target_module str, kind RuleKind) -] Self
+ RuleViolation : +source_module() -] str
+ RuleViolation : +target_module() -] str
+ RuleViolation : +kind() -] RuleKind
+ RuleViolation : +message() -] String
+ BoundaryRule : source String
+ BoundaryRule : target String
+ BoundaryRule : +parse(s str) -] Option[Self]
+ BoundaryRule : +source() -] str
+ BoundaryRule : +target() -] str
+ BoundaryRule : +matches(src_module str, tgt_module str) -] bool
+ CodeGraph : elements Vec
+ CodeGraph : relationships Vec
+ CodeGraph : +new() -] Self
+ CodeGraph : +add_element(element CodeElement)
+ CodeGraph : +add_relationship(relationship Relationship)
+ CodeGraph : +elements() -] [CodeElement]
+ CodeGraph : +relationships() -] [Relationship]
+ CodeGraph : +modules() -] Vec[ModuleName]
+ CodeGraph : +elements_by_module() -] (HashMap[String, Vec[CodeElement]], Vec[CodeElement])
+ CodeGraph : +resolve_relationships() -] CodeGraph
+ CodeGraph : +filter_external_imports(known_modules HashSet[String]) -] CodeGraph
+ CodeGraph : +qualify() -] CodeGraph
+ CodeGraph : +cross_module_deps_for(module ModuleName) -] Vec[(ModuleName, usize)]
+ CodeGraph : +subgraph_by_module(module ModuleName) -] CodeGraph
+ Relationship --> RelationshipKind
+ CodeElement --> CodeElementKind
+ CodeElement --> FilePath
+ CodeElement --> Visibility
+ AnalysisConfig --> DiagramLevel
+ AnalysisWarning --> FilePath
+ SourceFile --> FilePath
+ SourceFile --> Language
+ RuleViolation --> RuleKind
\ No newline at end of file
diff --git a/docs/arch/mermaid/type/overview.mmd b/docs/arch/mermaid/type/overview.mmd
new file mode 100644
index 0000000..33525d8
--- /dev/null
+++ b/docs/arch/mermaid/type/overview.mmd
@@ -0,0 +1,343 @@
+classDiagram
+ namespace Presentation {
+ class Cli
+ class Command
+ }
+ namespace Application {
+ class AnalyzeCodebase
+ class AnalyzeCodebaseResult
+ }
+ namespace Adapters {
+ class AsciiRenderer
+ class D2Renderer
+ class CargoWorkspaceAnalyzer
+ class WorkspaceToml
+ class WorkspaceSection
+ class MemberToml
+ class PackageSection
+ class PythonProjectAnalyzer
+ class ProjectSection
+ class PoetrySection
+ class ToolSection
+ class PyprojectToml
+ class StdoutOutputWriter
+ class FileOutputWriter
+ class OutputPath
+ class MermaidRenderer
+ class LanguageExtractor
+ class TreeSitterAnalyzer
+ class RustExtractor
+ class PythonExtractor
+ class WalkdirDiscovery
+ class HtmlRenderer
+ class GraphData
+ class NodeData
+ class EdgeData
+ class RawRules
+ class RawConfig
+ class RawAnalysis
+ class RawOutput
+ class TomlConfigLoader
+ }
+ namespace Domain {
+ class Relationship
+ class CodeElement
+ class DomainError
+ class DiagramRenderer
+ class SourceAnalyzer
+ class ConfigLoader
+ class FileDiscovery
+ class ProjectAnalyzer
+ class OutputWriter
+ class AnalysisResult
+ class AnalysisConfig
+ class AnalysisWarning
+ class CodeElementKind
+ class RelationshipKind
+ class Visibility
+ class DiagramLevel
+ class OutputConfig
+ class RenderedFile
+ class RenderOutput
+ class ModuleName
+ class Language
+ class SourceFile
+ class FilePath
+ class RuleKind
+ class RuleViolation
+ class BoundaryRule
+ class CodeGraph
+ }
+ Cli : command Option
+ Cli : path PathBuf
+ Cli : level String
+ Cli : format String
+ Cli : output Option
+ Cli : config Option
+ Cli : scope Option
+ Cli : exclude Vec
+ Cli : include_tests bool
+ Cli : no_weights bool
+ Cli : watch bool
+ Cli : since Option
+ Cli : split_by_module bool
+ Cli : strict bool
+ Cli : check bool
+ Cli : verbose u8
+ AnalyzeCodebase : file_discovery F
+ AnalyzeCodebase : source_analyzer S
+ AnalyzeCodebase : +new(file_discovery F, source_analyzer S) -] Self
+ AnalyzeCodebase : +execute(root Path, config AnalysisConfig) -] Result[AnalyzeCodebaseResult, DomainError]
+ AnalyzeCodebaseResult : graph CodeGraph
+ AnalyzeCodebaseResult : warnings Vec
+ AnalyzeCodebaseResult : +graph() -] CodeGraph
+ AnalyzeCodebaseResult : +warnings() -] [AnalysisWarning]
+ AsciiRenderer : +new() -] Self
+ AsciiRenderer : -format_kind(element CodeElement) -] static str
+ D2Renderer : level DiagramLevel
+ D2Renderer : +new() -] Self
+ D2Renderer : +with_level(level DiagramLevel) -] Self
+ CargoWorkspaceAnalyzer : +new() -] Self
+ <> WorkspaceToml
+ WorkspaceToml : workspace Option
+ <> WorkspaceSection
+ WorkspaceSection : members Vec
+ <> MemberToml
+ MemberToml : package Option
+ MemberToml : dependencies HashMap
+ <> PackageSection
+ PackageSection : name String
+ PythonProjectAnalyzer : +new() -] Self
+ <> ProjectSection
+ ProjectSection : name Option
+ ProjectSection : dependencies Vec
+ <> PoetrySection
+ PoetrySection : name Option
+ PoetrySection : dependencies HashMap
+ <> ToolSection
+ ToolSection : poetry PoetrySection
+ <> PyprojectToml
+ PyprojectToml : project Option
+ PyprojectToml : tool ToolSection
+ StdoutOutputWriter : +new() -] Self
+ FileOutputWriter : output_path OutputPath
+ FileOutputWriter : +new(output_dir PathBuf) -] Self
+ FileOutputWriter : +single_file(path PathBuf) -] Self
+ <> OutputPath
+ MermaidRenderer : level DiagramLevel
+ MermaidRenderer : show_weights bool
+ MermaidRenderer : +new() -] Self
+ MermaidRenderer : +with_level(level DiagramLevel) -] Self
+ MermaidRenderer : +with_weights(show bool) -] Self
+ MermaidRenderer : -display_name(qualified str) -] str
+ MermaidRenderer : -format_element_name(element CodeElement) -] String
+ MermaidRenderer : -format_visibility(visibility Visibility) -] static str
+ MermaidRenderer : -render_class_diagram(graph CodeGraph) -] String
+ MermaidRenderer : -push_class_lines(lines mut Vec[String], deferred mut Vec[String], element CodeElement, indent str, in_namespace bool)
+ MermaidRenderer : -render_module_flowchart(graph CodeGraph) -] String
+ MermaidRenderer : -render_project_flowchart(graph CodeGraph) -] String
+ MermaidRenderer : -sanitize_id(name str) -] String
+ TreeSitterAnalyzer : rust RustExtractor
+ TreeSitterAnalyzer : python PythonExtractor
+ TreeSitterAnalyzer : +new() -] Self
+ TreeSitterAnalyzer : -extractor_for(language Language) -] Option[dyn LanguageExtractor]
+ WalkdirDiscovery : +new() -] Self
+ WalkdirDiscovery : -detect_language(path Path) -] Option[Language]
+ WalkdirDiscovery : -is_test_file(path Path, language Language) -] bool
+ WalkdirDiscovery : -is_excluded(path Path, root Path, excludes [String]) -] bool
+ HtmlRenderer : +new() -] Self
+ <> GraphData
+ GraphData : nodes Vec
+ GraphData : edges Vec
+ <> NodeData
+ NodeData : id String
+ NodeData : label String
+ NodeData : module String
+ NodeData : kind String
+ NodeData : fields Vec
+ NodeData : methods Vec
+ <> EdgeData
+ EdgeData : source String
+ EdgeData : target String
+ EdgeData : kind String
+ <> RawRules
+ RawRules : allow Vec
+ RawRules : deny Vec
+ <> RawConfig
+ RawConfig : analysis RawAnalysis
+ RawConfig : output RawOutput
+ RawConfig : modules HashMap
+ RawConfig : rules RawRules
+ <> RawAnalysis
+ RawAnalysis : exclude Vec
+ RawAnalysis : level Option
+ <> RawOutput
+ RawOutput : format Option
+ RawOutput : path Option
+ RawOutput : split_by_module bool
+ TomlConfigLoader : raw RawConfig
+ TomlConfigLoader : +from_path(path Path) -] Result[Self, DomainError]
+ TomlConfigLoader : -parse_level(level Option[String]) -] DiagramLevel
+ Relationship : source String
+ Relationship : target String
+ Relationship : kind RelationshipKind
+ Relationship : source_file Option
+ Relationship : +new(source str, target str, kind RelationshipKind) -] Result[Self, DomainError]
+ Relationship : +with_source_file(file FilePath) -] Self
+ Relationship : +source() -] str
+ Relationship : +target() -] str
+ Relationship : +kind() -] RelationshipKind
+ Relationship : +source_file() -] Option[FilePath]
+ CodeElement : name String
+ CodeElement : qualified_name Option
+ CodeElement : kind CodeElementKind
+ CodeElement : file_path FilePath
+ CodeElement : line usize
+ CodeElement : visibility Visibility
+ CodeElement : module Option
+ CodeElement : generics Vec
+ CodeElement : attributes Vec
+ CodeElement : fields Vec
+ CodeElement : methods Vec
+ CodeElement : +new(name str, kind CodeElementKind, file_path FilePath, line usize) -] Result[Self, DomainError]
+ CodeElement : +with_visibility(visibility Visibility) -] Self
+ CodeElement : +with_module(module ModuleName) -] Self
+ CodeElement : +with_generics(generics Vec[String]) -] Self
+ CodeElement : +with_attributes(attributes Vec[String]) -] Self
+ CodeElement : +with_qualified_name(qn String) -] Self
+ CodeElement : +name() -] str
+ CodeElement : +qualified_name() -] str
+ CodeElement : +kind() -] CodeElementKind
+ CodeElement : +file_path() -] FilePath
+ CodeElement : +line() -] usize
+ CodeElement : +visibility() -] Visibility
+ CodeElement : +module() -] Option[ModuleName]
+ CodeElement : +generics() -] [String]
+ CodeElement : +attributes() -] [String]
+ CodeElement : +with_fields(fields Vec[String]) -] Self
+ CodeElement : +with_methods(methods Vec[String]) -] Self
+ CodeElement : +fields() -] [String]
+ CodeElement : +methods() -] [String]
+ AnalysisResult : elements Vec
+ AnalysisResult : relationships Vec
+ AnalysisResult : warnings Vec
+ AnalysisResult : +new(elements Vec[CodeElement], relationships Vec[Relationship], warnings Vec[AnalysisWarning]) -] Self
+ AnalysisResult : +empty() -] Self
+ AnalysisResult : +elements() -] [CodeElement]
+ AnalysisResult : +relationships() -] [Relationship]
+ AnalysisResult : +warnings() -] [AnalysisWarning]
+ AnalysisConfig : excludes Vec
+ AnalysisConfig : level DiagramLevel
+ AnalysisConfig : module_mappings HashMap
+ AnalysisConfig : scope Option
+ AnalysisConfig : include_tests bool
+ AnalysisConfig : changed_files Option
+ AnalysisConfig : +with_excludes(excludes Vec[String]) -] Self
+ AnalysisConfig : +with_level(level DiagramLevel) -] Self
+ AnalysisConfig : +with_module_mappings(mappings HashMap[String, String]) -] Self
+ AnalysisConfig : +excludes() -] [String]
+ AnalysisConfig : +level() -] DiagramLevel
+ AnalysisConfig : +with_scope(scope String) -] Self
+ AnalysisConfig : +module_mappings() -] HashMap[String, String]
+ AnalysisConfig : +scope() -] Option[str]
+ AnalysisConfig : +with_include_tests(include bool) -] Self
+ AnalysisConfig : +include_tests() -] bool
+ AnalysisConfig : +with_changed_files(files HashSet[String]) -] Self
+ AnalysisConfig : +changed_files() -] Option[HashSet[String]]
+ AnalysisWarning : file_path FilePath
+ AnalysisWarning : line usize
+ AnalysisWarning : message String
+ AnalysisWarning : +new(file_path FilePath, line usize, message str) -] Result[Self, DomainError]
+ AnalysisWarning : +file_path() -] FilePath
+ AnalysisWarning : +line() -] usize
+ AnalysisWarning : +message() -] str
+ OutputConfig : split_by_module bool
+ OutputConfig : output_path Option
+ OutputConfig : +with_split_by_module(split bool) -] Self
+ OutputConfig : +with_output_path(path String) -] Self
+ OutputConfig : +split_by_module() -] bool
+ OutputConfig : +output_path() -] Option[str]
+ RenderedFile : name String
+ RenderedFile : content String
+ RenderedFile : +new(name str, content str) -] Result[Self, DomainError]
+ RenderedFile : +name() -] str
+ RenderedFile : +content() -] str
+ RenderOutput : files Vec
+ RenderOutput : +new(files Vec[RenderedFile]) -] Self
+ RenderOutput : +single(file RenderedFile) -] Self
+ RenderOutput : +files() -] [RenderedFile]
+ ModuleName : +new(value str) -] Result[Self, DomainError]
+ ModuleName : +from_path(file_path str, root Path, module_mappings HashMap[String, String]) -] Option[Self]
+ ModuleName : +from_directory_group(member_path str) -] Option[Self]
+ ModuleName : +capitalize(s str) -] String
+ ModuleName : +as_str() -] str
+ Language : +name() -] static str
+ SourceFile : path FilePath
+ SourceFile : language Language
+ SourceFile : +new(path FilePath, language Language) -] Self
+ SourceFile : +path() -] FilePath
+ SourceFile : +language() -] Language
+ FilePath : +new(value str) -] Result[Self, DomainError]
+ FilePath : +as_str() -] str
+ RuleViolation : source_module String
+ RuleViolation : target_module String
+ RuleViolation : kind RuleKind
+ RuleViolation : +new(source_module str, target_module str, kind RuleKind) -] Self
+ RuleViolation : +source_module() -] str
+ RuleViolation : +target_module() -] str
+ RuleViolation : +kind() -] RuleKind
+ RuleViolation : +message() -] String
+ BoundaryRule : source String
+ BoundaryRule : target String
+ BoundaryRule : +parse(s str) -] Option[Self]
+ BoundaryRule : +source() -] str
+ BoundaryRule : +target() -] str
+ BoundaryRule : +matches(src_module str, tgt_module str) -] bool
+ CodeGraph : elements Vec
+ CodeGraph : relationships Vec
+ CodeGraph : +new() -] Self
+ CodeGraph : +add_element(element CodeElement)
+ CodeGraph : +add_relationship(relationship Relationship)
+ CodeGraph : +elements() -] [CodeElement]
+ CodeGraph : +relationships() -] [Relationship]
+ CodeGraph : +modules() -] Vec[ModuleName]
+ CodeGraph : +elements_by_module() -] (HashMap[String, Vec[CodeElement]], Vec[CodeElement])
+ CodeGraph : +resolve_relationships() -] CodeGraph
+ CodeGraph : +filter_external_imports(known_modules HashSet[String]) -] CodeGraph
+ CodeGraph : +qualify() -] CodeGraph
+ CodeGraph : +cross_module_deps_for(module ModuleName) -] Vec[(ModuleName, usize)]
+ CodeGraph : +subgraph_by_module(module ModuleName) -] CodeGraph
+ AsciiRenderer <|-- DiagramRenderer
+ D2Renderer --> DiagramLevel
+ D2Renderer <|-- DiagramRenderer
+ CargoWorkspaceAnalyzer <|-- ProjectAnalyzer
+ ToolSection --> PoetrySection
+ PyprojectToml --> ToolSection
+ PythonProjectAnalyzer <|-- ProjectAnalyzer
+ StdoutOutputWriter <|-- OutputWriter
+ FileOutputWriter --> OutputPath
+ FileOutputWriter <|-- OutputWriter
+ MermaidRenderer --> DiagramLevel
+ MermaidRenderer <|-- DiagramRenderer
+ TreeSitterAnalyzer --> RustExtractor
+ TreeSitterAnalyzer --> PythonExtractor
+ TreeSitterAnalyzer <|-- SourceAnalyzer
+ RustExtractor <|-- LanguageExtractor
+ PythonExtractor <|-- LanguageExtractor
+ WalkdirDiscovery <|-- FileDiscovery
+ HtmlRenderer <|-- DiagramRenderer
+ RawConfig --> RawAnalysis
+ RawConfig --> RawOutput
+ RawConfig --> RawRules
+ TomlConfigLoader --> RawConfig
+ TomlConfigLoader <|-- ConfigLoader
+ AnalyzeCodebaseResult --> CodeGraph
+ Relationship --> RelationshipKind
+ CodeElement --> CodeElementKind
+ CodeElement --> FilePath
+ CodeElement --> Visibility
+ AnalysisConfig --> DiagramLevel
+ AnalysisWarning --> FilePath
+ SourceFile --> FilePath
+ SourceFile --> Language
+ RuleViolation --> RuleKind
\ No newline at end of file
diff --git a/docs/arch/mermaid/type/presentation.mmd b/docs/arch/mermaid/type/presentation.mmd
new file mode 100644
index 0000000..567b924
--- /dev/null
+++ b/docs/arch/mermaid/type/presentation.mmd
@@ -0,0 +1,21 @@
+classDiagram
+ namespace Presentation {
+ class Cli
+ class Command
+ }
+ Cli : command Option
+ Cli : path PathBuf
+ Cli : level String
+ Cli : format String
+ Cli : output Option
+ Cli : config Option
+ Cli : scope Option
+ Cli : exclude Vec
+ Cli : include_tests bool
+ Cli : no_weights bool
+ Cli : watch bool
+ Cli : since Option
+ Cli : split_by_module bool
+ Cli : strict bool
+ Cli : check bool
+ Cli : verbose u8
\ No newline at end of file