codeboarding 0.9.3__tar.gz → 0.9.5__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 (145) hide show
  1. {codeboarding-0.9.3/codeboarding.egg-info → codeboarding-0.9.5}/PKG-INFO +1 -1
  2. codeboarding-0.9.5/README.md +149 -0
  3. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/agent_responses.py +4 -4
  4. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/cluster_methods_mixin.py +5 -2
  5. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/dependency_discovery.py +5 -5
  6. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/planner_agent.py +9 -9
  7. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/prompts/gpt_prompts.py +1 -1
  8. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/read_file_structure.py +6 -6
  9. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/read_source.py +1 -1
  10. {codeboarding-0.9.3 → codeboarding-0.9.5/codeboarding.egg-info}/PKG-INFO +1 -1
  11. {codeboarding-0.9.3 → codeboarding-0.9.5}/codeboarding.egg-info/SOURCES.txt +4 -1
  12. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/diagram_generator.py +4 -4
  13. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/file_coverage.py +2 -2
  14. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/io_utils.py +2 -2
  15. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/models.py +3 -3
  16. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/manifest.py +2 -2
  17. {codeboarding-0.9.3 → codeboarding-0.9.5}/github_action.py +1 -1
  18. {codeboarding-0.9.3 → codeboarding-0.9.5}/install.py +86 -45
  19. {codeboarding-0.9.3 → codeboarding-0.9.5}/logging_config.py +14 -0
  20. {codeboarding-0.9.3 → codeboarding-0.9.5}/main.py +1 -1
  21. {codeboarding-0.9.3 → codeboarding-0.9.5}/monitoring/context.py +4 -4
  22. {codeboarding-0.9.3 → codeboarding-0.9.5}/monitoring/writers.py +2 -2
  23. {codeboarding-0.9.3 → codeboarding-0.9.5}/output_generators/markdown.py +1 -1
  24. {codeboarding-0.9.3 → codeboarding-0.9.5}/output_generators/mdx.py +1 -1
  25. {codeboarding-0.9.3 → codeboarding-0.9.5}/output_generators/sphinx.py +1 -1
  26. {codeboarding-0.9.3 → codeboarding-0.9.5}/pyproject.toml +1 -1
  27. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/cluster_change_analyzer.py +1 -1
  28. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/graph.py +3 -3
  29. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/lsp_client/client.py +29 -11
  30. codeboarding-0.9.5/tests/test_install.py +120 -0
  31. {codeboarding-0.9.3 → codeboarding-0.9.5}/tests/test_logging_config.py +73 -0
  32. codeboarding-0.9.5/tests/test_tool_registry.py +94 -0
  33. codeboarding-0.9.5/tests/test_user_config.py +65 -0
  34. codeboarding-0.9.5/tests/test_windows_encoding.py +49 -0
  35. {codeboarding-0.9.3 → codeboarding-0.9.5}/tool_registry.py +133 -9
  36. {codeboarding-0.9.3 → codeboarding-0.9.5}/user_config.py +1 -1
  37. codeboarding-0.9.3/README.md +0 -281
  38. codeboarding-0.9.3/tests/test_install.py +0 -51
  39. {codeboarding-0.9.3 → codeboarding-0.9.5}/LICENSE +0 -0
  40. {codeboarding-0.9.3 → codeboarding-0.9.5}/PYPI.md +0 -0
  41. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/__init__.py +0 -0
  42. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/abstraction_agent.py +0 -0
  43. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/agent.py +0 -0
  44. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/constants.py +0 -0
  45. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/details_agent.py +0 -0
  46. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/llm_config.py +0 -0
  47. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/meta_agent.py +0 -0
  48. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/prompts/__init__.py +0 -0
  49. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/prompts/abstract_prompt_factory.py +0 -0
  50. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/prompts/claude_prompts.py +0 -0
  51. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/prompts/deepseek_prompts.py +0 -0
  52. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/prompts/gemini_flash_prompts.py +0 -0
  53. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/prompts/glm_prompts.py +0 -0
  54. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/prompts/kimi_prompts.py +0 -0
  55. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/prompts/prompt_factory.py +0 -0
  56. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/__init__.py +0 -0
  57. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/base.py +0 -0
  58. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/get_external_deps.py +0 -0
  59. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/get_method_invocations.py +0 -0
  60. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/read_cfg.py +0 -0
  61. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/read_docs.py +0 -0
  62. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/read_file.py +0 -0
  63. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/read_git_diff.py +0 -0
  64. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/read_packages.py +0 -0
  65. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/read_structure.py +0 -0
  66. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/tools/toolkit.py +0 -0
  67. {codeboarding-0.9.3 → codeboarding-0.9.5}/agents/validation.py +0 -0
  68. {codeboarding-0.9.3 → codeboarding-0.9.5}/caching/__init__.py +0 -0
  69. {codeboarding-0.9.3 → codeboarding-0.9.5}/caching/cache.py +0 -0
  70. {codeboarding-0.9.3 → codeboarding-0.9.5}/caching/meta_cache.py +0 -0
  71. {codeboarding-0.9.3 → codeboarding-0.9.5}/codeboarding.egg-info/dependency_links.txt +0 -0
  72. {codeboarding-0.9.3 → codeboarding-0.9.5}/codeboarding.egg-info/entry_points.txt +0 -0
  73. {codeboarding-0.9.3 → codeboarding-0.9.5}/codeboarding.egg-info/requires.txt +0 -0
  74. {codeboarding-0.9.3 → codeboarding-0.9.5}/codeboarding.egg-info/top_level.txt +0 -0
  75. {codeboarding-0.9.3 → codeboarding-0.9.5}/core/__init__.py +0 -0
  76. {codeboarding-0.9.3 → codeboarding-0.9.5}/core/plugin_loader.py +0 -0
  77. {codeboarding-0.9.3 → codeboarding-0.9.5}/core/protocols.py +0 -0
  78. {codeboarding-0.9.3 → codeboarding-0.9.5}/core/registry.py +0 -0
  79. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/__init__.py +0 -0
  80. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/analysis_json.py +0 -0
  81. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/__init__.py +0 -0
  82. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/component_checker.py +0 -0
  83. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/file_manager.py +0 -0
  84. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/impact_analyzer.py +0 -0
  85. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/path_patching.py +0 -0
  86. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/reexpansion.py +0 -0
  87. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/scoped_analysis.py +0 -0
  88. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/updater.py +0 -0
  89. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/incremental/validation.py +0 -0
  90. {codeboarding-0.9.3 → codeboarding-0.9.5}/diagram_analysis/version.py +0 -0
  91. {codeboarding-0.9.3 → codeboarding-0.9.5}/duckdb_crud.py +0 -0
  92. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/__init__.py +0 -0
  93. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/checks/__init__.py +0 -0
  94. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/checks/circular_deps.py +0 -0
  95. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/checks/cohesion.py +0 -0
  96. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/checks/coupling.py +0 -0
  97. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/checks/function_size.py +0 -0
  98. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/checks/god_class.py +0 -0
  99. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/checks/inheritance.py +0 -0
  100. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/checks/instability.py +0 -0
  101. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/checks/unused_code_diagnostics.py +0 -0
  102. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/config.py +0 -0
  103. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/constants.py +0 -0
  104. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/models.py +0 -0
  105. {codeboarding-0.9.3 → codeboarding-0.9.5}/health/runner.py +0 -0
  106. {codeboarding-0.9.3 → codeboarding-0.9.5}/health_main.py +0 -0
  107. {codeboarding-0.9.3 → codeboarding-0.9.5}/monitoring/__init__.py +0 -0
  108. {codeboarding-0.9.3 → codeboarding-0.9.5}/monitoring/callbacks.py +0 -0
  109. {codeboarding-0.9.3 → codeboarding-0.9.5}/monitoring/mixin.py +0 -0
  110. {codeboarding-0.9.3 → codeboarding-0.9.5}/monitoring/paths.py +0 -0
  111. {codeboarding-0.9.3 → codeboarding-0.9.5}/monitoring/stats.py +0 -0
  112. {codeboarding-0.9.3 → codeboarding-0.9.5}/output_generators/__init__.py +0 -0
  113. {codeboarding-0.9.3 → codeboarding-0.9.5}/output_generators/html.py +0 -0
  114. {codeboarding-0.9.3 → codeboarding-0.9.5}/output_generators/html_template.py +0 -0
  115. {codeboarding-0.9.3 → codeboarding-0.9.5}/repo_utils/__init__.py +0 -0
  116. {codeboarding-0.9.3 → codeboarding-0.9.5}/repo_utils/change_detector.py +0 -0
  117. {codeboarding-0.9.3 → codeboarding-0.9.5}/repo_utils/errors.py +0 -0
  118. {codeboarding-0.9.3 → codeboarding-0.9.5}/repo_utils/git_diff.py +0 -0
  119. {codeboarding-0.9.3 → codeboarding-0.9.5}/repo_utils/ignore.py +0 -0
  120. {codeboarding-0.9.3 → codeboarding-0.9.5}/setup.cfg +0 -0
  121. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/__init__.py +0 -0
  122. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/analysis_cache.py +0 -0
  123. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/analysis_result.py +0 -0
  124. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/cluster_helpers.py +0 -0
  125. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/constants.py +0 -0
  126. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/git_diff_analyzer.py +0 -0
  127. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/incremental_orchestrator.py +0 -0
  128. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/java_config_scanner.py +0 -0
  129. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/java_utils.py +0 -0
  130. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/lsp_client/__init__.py +0 -0
  131. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/lsp_client/diagnostics.py +0 -0
  132. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/lsp_client/java_client.py +0 -0
  133. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/lsp_client/language_settings.py +0 -0
  134. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/lsp_client/typescript_client.py +0 -0
  135. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/programming_language.py +0 -0
  136. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/reference_resolve_mixin.py +0 -0
  137. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/scanner.py +0 -0
  138. {codeboarding-0.9.3 → codeboarding-0.9.5}/static_analyzer/typescript_config_scanner.py +0 -0
  139. {codeboarding-0.9.3 → codeboarding-0.9.5}/tests/test_github_action.py +0 -0
  140. {codeboarding-0.9.3 → codeboarding-0.9.5}/tests/test_incremental_analyzer.py +0 -0
  141. {codeboarding-0.9.3 → codeboarding-0.9.5}/tests/test_main.py +0 -0
  142. {codeboarding-0.9.3 → codeboarding-0.9.5}/tests/test_vscode_constants.py +0 -0
  143. {codeboarding-0.9.3 → codeboarding-0.9.5}/tests/test_windows_compatibility.py +0 -0
  144. {codeboarding-0.9.3 → codeboarding-0.9.5}/utils.py +0 -0
  145. {codeboarding-0.9.3 → codeboarding-0.9.5}/vscode_constants.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeboarding
3
- Version: 0.9.3
3
+ Version: 0.9.5
4
4
  Summary: Interactive Diagrams for Code
5
5
  Author: CodeBoarding Team
6
6
  License: MIT
@@ -0,0 +1,149 @@
1
+ # CodeBoarding
2
+
3
+ See what your AI is building before it breaks.
4
+
5
+ CodeBoarding gives developers and coding agents a visual map of a codebase. It combines static analysis with LLM reasoning to generate architecture diagrams, component-level documentation, and navigable outputs you can use in your IDE, CI, and docs.
6
+
7
+ [Website](https://codeboarding.org) · [Open VSX extension](https://open-vsx.org/extension/CodeBoarding/codeboarding) · [Explore examples](https://codeboarding.org/diagrams) · [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Codeboarding.codeboarding) · [GitHub Action](https://github.com/marketplace/actions/codeboarding-diagram-first-documentation) ·[Discord](https://discord.gg/T5zHTJYFuy)
8
+
9
+ [![CodeBoarding demo](docs/assets/codeboarding-demo.gif)](https://open-vsx.org/extension/CodeBoarding/codeboarding)
10
+
11
+ Install the extension from Open VSX.
12
+
13
+ [![JavaScript](https://img.shields.io/badge/JavaScript-222222?style=flat-square&logo=javascript&logoColor=F7DF1E)](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
14
+ [![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
15
+ [![Java](https://img.shields.io/badge/Java-E76F00?style=flat-square&logo=openjdk&logoColor=white)](https://www.java.com/)
16
+ [![Python](https://img.shields.io/badge/Python-3776AB?style=flat-square&logo=python&logoColor=white)](https://www.python.org/)
17
+ [![Go](https://img.shields.io/badge/Go-00ADD8?style=flat-square&logo=go&logoColor=white)](https://go.dev/)
18
+ [![PHP](https://img.shields.io/badge/PHP-777BB4?style=flat-square&logo=php&logoColor=white)](https://www.php.net/)
19
+
20
+ ## Few use cases:
21
+
22
+ - Keep architecture visible while agents code.
23
+ - Review AI-generated changes with system context before they turn into hidden debt.
24
+ - Understand large repositories faster with layered diagrams and component breakdowns.
25
+ - Share the same visual model across local workflows, IDEs, pull requests, and docs.
26
+
27
+ ## What CodeBoarding generates
28
+
29
+ - High-level system architecture diagrams.
30
+ - Deeper component diagrams for important subsystems.
31
+ - Markdown documentation in `.codeboarding/`.
32
+ - Mermaid output that is easy to embed in docs and PRs.
33
+ - Incremental updates when only part of the codebase changes.
34
+
35
+ ## How it works
36
+
37
+ ```mermaid
38
+ graph LR
39
+ Application_Orchestrator_Repository_Manager["Application Orchestrator & Repository Manager"]
40
+ LLM_Agent_Core["LLM Agent Core"]
41
+ Static_Code_Analyzer["Static Code Analyzer"]
42
+ Agent_Tooling_Interface["Agent Tooling Interface"]
43
+ Incremental_Analysis_Engine["Incremental Analysis Engine"]
44
+ Documentation_Diagram_Generator["Documentation & Diagram Generator"]
45
+ Application_Orchestrator_Repository_Manager -- "Orchestrator initiates analysis workflow, leveraging incremental updates based on detected code changes." --> Incremental_Analysis_Engine
46
+ Application_Orchestrator_Repository_Manager -- "Orchestrator passes project context and triggers the main analysis workflow for the LLM Agent." --> LLM_Agent_Core
47
+ Incremental_Analysis_Engine -- "Incremental engine requests static analysis for specific code segments (new or changed)." --> Static_Code_Analyzer
48
+ Static_Code_Analyzer -- "Static analyzer provides analysis results to the incremental engine for caching." --> Incremental_Analysis_Engine
49
+ LLM_Agent_Core -- "LLM Agent invokes specialized tools to interact with the codebase and analysis data." --> Agent_Tooling_Interface
50
+ Agent_Tooling_Interface -- "Agent tools query the static analysis engine for detailed code insights." --> Static_Code_Analyzer
51
+ Static_Code_Analyzer -- "Static analysis engine provides requested data to the agent tools." --> Agent_Tooling_Interface
52
+ LLM_Agent_Core -- "LLM Agent delivers structured analysis insights for documentation and diagram generation." --> Documentation_Diagram_Generator
53
+ click Application_Orchestrator_Repository_Manager href "https://github.com/CodeBoarding/CodeBoarding/blob/main/.codeboarding/Application_Orchestrator_Repository_Manager.md" "Details"
54
+ click LLM_Agent_Core href "https://github.com/CodeBoarding/CodeBoarding/blob/main/.codeboarding/LLM_Agent_Core.md" "Details"
55
+ click Static_Code_Analyzer href "https://github.com/CodeBoarding/CodeBoarding/blob/main/.codeboarding/Static_Code_Analyzer.md" "Details"
56
+ click Agent_Tooling_Interface href "https://github.com/CodeBoarding/CodeBoarding/blob/main/.codeboarding/Agent_Tooling_Interface.md" "Details"
57
+ click Incremental_Analysis_Engine href "https://github.com/CodeBoarding/CodeBoarding/blob/main/.codeboarding/Incremental_Analysis_Engine.md" "Details"
58
+ click Documentation_Diagram_Generator href "https://github.com/CodeBoarding/CodeBoarding/blob/main/.codeboarding/Documentation_Diagram_Generator.md" "Details"
59
+ ```
60
+
61
+ For a deeper architecture walkthrough, see [`.codeboarding/overview.md`](.codeboarding/overview.md).
62
+
63
+ ## Quick start
64
+
65
+ ### Run from source
66
+
67
+ ```bash
68
+ uv sync --frozen
69
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
70
+ python install.py
71
+ python main.py --local /path/to/repo
72
+ ```
73
+
74
+ ### Use the packaged CLI
75
+
76
+ ```bash
77
+ pip install codeboarding
78
+ codeboarding-setup
79
+ codeboarding --local /path/to/repo
80
+ ```
81
+
82
+ Output is written to `/path/to/repo/.codeboarding/`.
83
+
84
+ `python install.py` and `codeboarding-setup` download language server binaries to `~/.codeboarding/servers/`, shared across projects. `npm` is required for Python, TypeScript, JavaScript, and PHP language servers; if it is missing, setup can install it via `nodeenv`.
85
+
86
+ ## Configuration
87
+
88
+ On first run, CodeBoarding creates `~/.codeboarding/config.toml`. Set one provider there or use environment variables.
89
+
90
+ ```toml
91
+ [provider]
92
+ # openai_api_key = "sk-..."
93
+ # anthropic_api_key = "sk-ant-..."
94
+ # google_api_key = "AIza..."
95
+ # vercel_api_key = "vck_..."
96
+ # aws_bearer_token_bedrock = "..."
97
+ # ollama_base_url = "http://localhost:11434"
98
+ # openrouter_api_key = "sk-..."
99
+
100
+ [llm]
101
+ # agent_model = "gemini-3-flash"
102
+ # parsing_model = "gemini-3-flash"
103
+ ```
104
+
105
+ Shell environment variables such as `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY`, and `OLLAMA_BASE_URL` take precedence over the config file. For private repositories, set `GITHUB_TOKEN` in your environment.
106
+
107
+ ## Common commands
108
+
109
+ ```bash
110
+ # Analyze a local repository
111
+ python main.py --local ./my-project
112
+
113
+ # Increase diagram depth
114
+ python main.py --local ./my-project --depth-level 2
115
+
116
+ # Re-analyze only changed parts when possible
117
+ python main.py --local ./my-project --incremental
118
+
119
+ # Update a single component by ID
120
+ python main.py --local ./my-project --partial-component-id "a3f2b1c4d5e6f789"
121
+
122
+ # Analyze a remote GitHub repository
123
+ python main.py https://github.com/pytorch/pytorch
124
+ ```
125
+
126
+ ## Where to use it
127
+
128
+ - [CLI](https://github.com/CodeBoarding/CodeBoarding) for local analysis, automation, and CI workflows.
129
+ - [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Codeboarding.codeboarding) for in-editor visual architecture.
130
+ - [GitHub Action](https://github.com/marketplace/actions/codeboarding-diagram-first-documentation) to keep diagrams updated in CI.
131
+
132
+ ## Supported stack
133
+
134
+ - Languages: Python, TypeScript, JavaScript, Java, Go, PHP.
135
+ - LLM providers: OpenAI, Anthropic, Google, Vercel AI Gateway, AWS Bedrock, Ollama, OpenRouter, and more.
136
+
137
+ ## Examples
138
+
139
+ - Visualized 800+ open-source repositories.
140
+ - Browse generated examples in [GeneratedOnBoardings](https://github.com/CodeBoarding/GeneratedOnBoardings).
141
+ - Try the hosted explorer at [codeboarding.org/diagrams](https://codeboarding.org/diagrams).
142
+
143
+ ## Contributing
144
+
145
+ If you want to improve CodeBoarding, open an [issue](https://github.com/CodeBoarding/CodeBoarding/issues) or send a pull request. We welcome improvements to analysis quality, output generators, integrations, and developer experience.
146
+
147
+ ## Vision
148
+
149
+ CodeBoarding is building an open standard for code understanding: a visual, accurate, high-level representation of a codebase that both humans and agents can use.
@@ -180,7 +180,7 @@ class AnalysisInsights(LLMBaseModel):
180
180
  def llm_str(self):
181
181
  if not self.components:
182
182
  return "No abstract components found."
183
- title = "# 📦 Abstract Components Overview\n"
183
+ title = "# Abstract Components Overview\n"
184
184
  body = "\n".join(ac.llm_str() for ac in self.components)
185
185
  relations = "\n".join(cr.llm_str() for cr in self.components_relations)
186
186
  return title + body + relations
@@ -251,7 +251,7 @@ class CFGAnalysisInsights(LLMBaseModel):
251
251
  def llm_str(self):
252
252
  if not self.components:
253
253
  return "No abstract components found in the CFG."
254
- title = "# 📦 Abstract Components Overview from CFG\n"
254
+ title = "# Abstract Components Overview from CFG\n"
255
255
  body = "\n".join(ac.llm_str() for ac in self.components)
256
256
  relations = "\n".join(cr.llm_str() for cr in self.components_relations)
257
257
  return title + body + relations
@@ -309,7 +309,7 @@ class MetaAnalysisInsights(LLMBaseModel):
309
309
  )
310
310
 
311
311
  def llm_str(self):
312
- title = "# 🎯 Project Metadata Analysis\n"
312
+ title = "# Project Metadata Analysis\n"
313
313
  content = f"""
314
314
  **Project Type:** {self.project_type}
315
315
  **Domain:** {self.domain}
@@ -341,7 +341,7 @@ class ComponentFiles(LLMBaseModel):
341
341
  def llm_str(self):
342
342
  if not self.file_paths:
343
343
  return "No files classified."
344
- title = "# 📄 Component File Classifications\n"
344
+ title = "# Component File Classifications\n"
345
345
  body = "\n".join(f"- `{fc.file_path}` -> Component: `{fc.component_name}`" for fc in self.file_paths)
346
346
  return title + body
347
347
 
@@ -2,10 +2,13 @@ import logging
2
2
  import os
3
3
  from pathlib import Path
4
4
 
5
- from agents.agent_responses import Component, AnalysisInsights
5
+ from agents.agent_responses import AnalysisInsights, Component
6
6
  from static_analyzer.analysis_result import StaticAnalysisResults
7
+ from static_analyzer.cluster_helpers import (
8
+ get_all_cluster_ids,
9
+ get_files_for_cluster_ids,
10
+ )
7
11
  from static_analyzer.graph import ClusterResult
8
- from static_analyzer.cluster_helpers import get_files_for_cluster_ids, get_all_cluster_ids
9
12
 
10
13
  logger = logging.getLogger(__name__)
11
14
 
@@ -31,7 +31,7 @@ class DependencyFileSpec:
31
31
 
32
32
 
33
33
  DEPENDENCY_REGISTRY: tuple[DependencyFileSpec, ...] = (
34
- # ── Python ──
34
+ # -- Python --
35
35
  DependencyFileSpec("requirements.txt", Ecosystem.PYTHON, FileRole.MANIFEST),
36
36
  DependencyFileSpec("requirements-dev.txt", Ecosystem.PYTHON, FileRole.MANIFEST),
37
37
  DependencyFileSpec("requirements-test.txt", Ecosystem.PYTHON, FileRole.MANIFEST),
@@ -52,7 +52,7 @@ DEPENDENCY_REGISTRY: tuple[DependencyFileSpec, ...] = (
52
52
  DependencyFileSpec("pixi.toml", Ecosystem.PYTHON, FileRole.MANIFEST),
53
53
  DependencyFileSpec("requirements.in", Ecosystem.PYTHON, FileRole.MANIFEST),
54
54
  DependencyFileSpec("pixi.lock", Ecosystem.PYTHON, FileRole.LOCK),
55
- # ── Node / TypeScript / JavaScript ──
55
+ # -- Node / TypeScript / JavaScript --
56
56
  DependencyFileSpec("package.json", Ecosystem.NODE, FileRole.MANIFEST),
57
57
  DependencyFileSpec("package-lock.json", Ecosystem.NODE, FileRole.LOCK),
58
58
  DependencyFileSpec("yarn.lock", Ecosystem.NODE, FileRole.LOCK),
@@ -65,12 +65,12 @@ DEPENDENCY_REGISTRY: tuple[DependencyFileSpec, ...] = (
65
65
  DependencyFileSpec("deno.jsonc", Ecosystem.NODE, FileRole.MANIFEST),
66
66
  DependencyFileSpec("deno.lock", Ecosystem.NODE, FileRole.LOCK),
67
67
  DependencyFileSpec("lerna.json", Ecosystem.NODE, FileRole.CONFIG),
68
- # ── Go ──
68
+ # -- Go --
69
69
  DependencyFileSpec("go.mod", Ecosystem.GO, FileRole.MANIFEST),
70
70
  DependencyFileSpec("go.sum", Ecosystem.GO, FileRole.LOCK),
71
71
  DependencyFileSpec("go.work", Ecosystem.GO, FileRole.CONFIG),
72
72
  DependencyFileSpec("go.work.sum", Ecosystem.GO, FileRole.LOCK),
73
- # ── Java / JVM ──
73
+ # -- Java / JVM --
74
74
  DependencyFileSpec("pom.xml", Ecosystem.JAVA, FileRole.MANIFEST),
75
75
  DependencyFileSpec("pom.properties", Ecosystem.JAVA, FileRole.CONFIG),
76
76
  DependencyFileSpec("build.gradle", Ecosystem.JAVA, FileRole.MANIFEST),
@@ -81,7 +81,7 @@ DEPENDENCY_REGISTRY: tuple[DependencyFileSpec, ...] = (
81
81
  DependencyFileSpec("build.sbt", Ecosystem.JAVA, FileRole.MANIFEST),
82
82
  DependencyFileSpec("gradle.lockfile", Ecosystem.JAVA, FileRole.LOCK),
83
83
  DependencyFileSpec("verification-metadata.xml", Ecosystem.JAVA, FileRole.LOCK),
84
- # ── PHP ──
84
+ # -- PHP --
85
85
  DependencyFileSpec("composer.json", Ecosystem.PHP, FileRole.MANIFEST),
86
86
  DependencyFileSpec("composer.lock", Ecosystem.PHP, FileRole.LOCK),
87
87
  DependencyFileSpec("symfony.lock", Ecosystem.PHP, FileRole.LOCK),
@@ -6,14 +6,14 @@ should be expanded into sub-components. Unlike the previous LLM-based approach,
6
6
  this uses CFG clustering structure as the source of truth.
7
7
 
8
8
  Expansion Rules:
9
- 1. If component has source_cluster_ids expandable (CFG structure exists)
10
- 2. If component has no clusters but has files expandable ONE level (to explain files)
11
- 3. If neither component nor its parent has clusters leaf (stop expanding)
9
+ 1. If component has source_cluster_ids -> expandable (CFG structure exists)
10
+ 2. If component has no clusters but has files -> expandable ONE level (to explain files)
11
+ 3. If neither component nor its parent has clusters -> leaf (stop expanding)
12
12
 
13
13
  Example:
14
- - Component: "Agents" (clusters: [1,2,3]) expand
15
- - Sub-component: "DetailsAgent" (clusters: [], files: [details_agent.py]) expand (parent had clusters)
16
- - Sub-sub-component: "run_method" (clusters: [], files: []) DON'T expand (parent had no clusters)
14
+ - Component: "Agents" (clusters: [1,2,3]) -> expand (yes)
15
+ - Sub-component: "DetailsAgent" (clusters: [], files: [details_agent.py]) -> expand (yes, parent had clusters)
16
+ - Sub-sub-component: "run_method" (clusters: [], files: []) -> DON'T expand (no, parent had no clusters)
17
17
  """
18
18
 
19
19
  import logging
@@ -35,10 +35,10 @@ def should_expand_component(
35
35
  Determine if a component should be expanded into sub-components.
36
36
 
37
37
  Expansion logic:
38
- - If component has clusters expand (there's CFG structure to decompose)
39
- - If component has no clusters but has files expand if parent had clusters
38
+ - If component has clusters -> expand (there's CFG structure to decompose)
39
+ - If component has no clusters but has files -> expand if parent had clusters
40
40
  (allows one more level to explain file internals)
41
- - If neither component nor parent has clusters stop (leaf node)
41
+ - If neither component nor parent has clusters -> stop (leaf node)
42
42
 
43
43
  Args:
44
44
  component: The component to evaluate
@@ -213,7 +213,7 @@ RELATIONSHIPS_VALIDATION = """Validate component relationships for accuracy and
213
213
 
214
214
  1. **Accuracy:**
215
215
  - [ ] Relationship type is correct (dependency, composition, inheritance, etc.)
216
- - [ ] Direction is accurate (source target)
216
+ - [ ] Direction is accurate (source -> target)
217
217
  - [ ] Both components exist in the analysis
218
218
 
219
219
  2. **Completeness:**
@@ -124,19 +124,19 @@ def get_tree_string(
124
124
  entries = sorted([p for p in startpath.iterdir() if not (ignore_manager and ignore_manager.should_ignore(p))])
125
125
  except (PermissionError, FileNotFoundError):
126
126
  # Handle permission errors or non-existent directories
127
- return [indent + "└── [Error reading directory]"]
127
+ return [indent + "`--[Error reading directory]"]
128
128
 
129
129
  for i, entry_path in enumerate(entries):
130
130
  # Check if we've exceeded the maximum number of lines
131
131
  if len(tree_lines) >= max_lines:
132
- tree_lines.append(indent + "└── [Output truncated due to size limits]")
132
+ tree_lines.append(indent + "`-- [Output truncated due to size limits]")
133
133
  return tree_lines
134
134
 
135
- connector = "└── " if i == len(entries) - 1 else "├── "
135
+ connector = "`-- " if i == len(entries) - 1 else "|-- "
136
136
  tree_lines.append(indent + connector + entry_path.name)
137
137
 
138
138
  if entry_path.is_dir():
139
- extension = " " if i == len(entries) - 1 else " "
139
+ extension = " " if i == len(entries) - 1 else "| "
140
140
  subtree = get_tree_string(
141
141
  entry_path,
142
142
  indent + extension,
@@ -149,8 +149,8 @@ def get_tree_string(
149
149
 
150
150
  # Check again after adding subtree
151
151
  if len(tree_lines) >= max_lines:
152
- if tree_lines[-1] != indent + "└── [Output truncated due to size limits]":
153
- tree_lines.append(indent + "└── [Output truncated due to size limits]")
152
+ if tree_lines[-1] != indent + "`-- [Output truncated due to size limits]":
153
+ tree_lines.append(indent + "`-- [Output truncated due to size limits]")
154
154
  return tree_lines
155
155
 
156
156
  return tree_lines
@@ -95,7 +95,7 @@ class CodeReferenceReader(BaseRepoTool):
95
95
  logger.error(f"[Source Reference Tool] File {file_path} does not exist.")
96
96
  return f"Error: File {file_path} does not exist."
97
97
 
98
- with open(file_path, "r") as f:
98
+ with open(file_path, "r", encoding="utf-8", errors="replace") as f:
99
99
  lines = f.readlines()
100
100
 
101
101
  if start_line < 0 or end_line > len(lines):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeboarding
3
- Version: 0.9.3
3
+ Version: 0.9.5
4
4
  Summary: Interactive Diagrams for Code
5
5
  Author: CodeBoarding Team
6
6
  License: MIT
@@ -134,5 +134,8 @@ tests/test_incremental_analyzer.py
134
134
  tests/test_install.py
135
135
  tests/test_logging_config.py
136
136
  tests/test_main.py
137
+ tests/test_tool_registry.py
138
+ tests/test_user_config.py
137
139
  tests/test_vscode_constants.py
138
- tests/test_windows_compatibility.py
140
+ tests/test_windows_compatibility.py
141
+ tests/test_windows_encoding.py
@@ -114,7 +114,7 @@ class DiagramGenerator:
114
114
  )
115
115
  if health_report is not None:
116
116
  health_path = Path(self.output_dir) / "health" / "health_report.json"
117
- with open(health_path, "w") as f:
117
+ with open(health_path, "w", encoding="utf-8") as f:
118
118
  f.write(health_report.model_dump_json(indent=2, exclude_none=True))
119
119
  logger.info(f"Health report written to {health_path} (score: {health_report.overall_score:.3f})")
120
120
  else:
@@ -145,7 +145,7 @@ class DiagramGenerator:
145
145
  )
146
146
 
147
147
  coverage_path = Path(self.output_dir) / "file_coverage.json"
148
- with open(coverage_path, "w") as f:
148
+ with open(coverage_path, "w", encoding="utf-8") as f:
149
149
  f.write(report.model_dump_json(indent=2, exclude_none=True))
150
150
  logger.info(f"File coverage report written to {coverage_path}")
151
151
 
@@ -232,7 +232,7 @@ class DiagramGenerator:
232
232
  self._monitoring_agents["AbstractionAgent"] = self.abstraction_agent
233
233
 
234
234
  version_file = Path(self.output_dir) / "codeboarding_version.json"
235
- with open(version_file, "w") as f:
235
+ with open(version_file, "w", encoding="utf-8") as f:
236
236
  f.write(
237
237
  Version(
238
238
  commit_hash=get_git_commit_hash(self.repo_location),
@@ -253,7 +253,7 @@ class DiagramGenerator:
253
253
 
254
254
  # Save code_stats.json
255
255
  code_stats_file = monitoring_dir / "code_stats.json"
256
- with open(code_stats_file, "w") as f:
256
+ with open(code_stats_file, "w", encoding="utf-8") as f:
257
257
  json.dump(static_stats, f, indent=2)
258
258
  logger.debug(f"Written code_stats.json to {code_stats_file}")
259
259
 
@@ -187,7 +187,7 @@ class FileCoverage:
187
187
  return None
188
188
 
189
189
  try:
190
- with open(coverage_path, "r") as f:
190
+ with open(coverage_path, "r", encoding="utf-8") as f:
191
191
  data = json.load(f)
192
192
  # Validate basic structure
193
193
  if "analyzed_files" in data and "not_analyzed_files" in data:
@@ -207,6 +207,6 @@ class FileCoverage:
207
207
  coverage: File coverage dictionary to save
208
208
  """
209
209
  coverage_path = output_dir / "file_coverage.json"
210
- with open(coverage_path, "w") as f:
210
+ with open(coverage_path, "w", encoding="utf-8") as f:
211
211
  json.dump(coverage, f, indent=2)
212
212
  logger.info(f"File coverage saved to {coverage_path}")
@@ -79,7 +79,7 @@ class _AnalysisFileStore:
79
79
  return None
80
80
 
81
81
  try:
82
- with open(self._analysis_path, "r") as f:
82
+ with open(self._analysis_path, "r", encoding="utf-8") as f:
83
83
  data = json.load(f)
84
84
 
85
85
  root_analysis, sub_analyses = parse_unified_analysis(data)
@@ -200,7 +200,7 @@ class _AnalysisFileStore:
200
200
  sub_expandable = self._compute_expandable_components(sub, parent_had_clusters=parent_had_clusters)
201
201
  sub_analyses_tuples[cid] = (sub, sub_expandable)
202
202
 
203
- with open(self._analysis_path, "w") as f:
203
+ with open(self._analysis_path, "w", encoding="utf-8") as f:
204
204
  f.write(
205
205
  build_unified_analysis_json(
206
206
  analysis=analysis,
@@ -58,11 +58,11 @@ class ChangeImpact:
58
58
  f"Dirty components: {self.dirty_components}",
59
59
  ]
60
60
  if self.components_needing_reexpansion:
61
- lines.append(f"🔄 Components needing re-expansion: {self.components_needing_reexpansion}")
61
+ lines.append(f"Components needing re-expansion: {self.components_needing_reexpansion}")
62
62
  if self.architecture_dirty:
63
- lines.append("⚠️ Architecture refresh needed")
63
+ lines.append("WARNING: Architecture refresh needed")
64
64
  if self.unassigned_files:
65
- lines.append(f"⚠️ Unassigned files: {self.unassigned_files}")
65
+ lines.append(f"WARNING: Unassigned files: {self.unassigned_files}")
66
66
  return "\n".join(lines)
67
67
 
68
68
 
@@ -109,7 +109,7 @@ def save_manifest(manifest: AnalysisManifest, output_dir: Path) -> Path:
109
109
  """
110
110
  manifest_path = output_dir / MANIFEST_FILENAME
111
111
 
112
- with open(manifest_path, "w") as f:
112
+ with open(manifest_path, "w", encoding="utf-8") as f:
113
113
  f.write(manifest.model_dump_json(indent=2))
114
114
 
115
115
  logger.info(f"Saved analysis manifest to {manifest_path}")
@@ -129,7 +129,7 @@ def load_manifest(output_dir: Path) -> AnalysisManifest | None:
129
129
  return None
130
130
 
131
131
  try:
132
- with open(manifest_path, "r") as f:
132
+ with open(manifest_path, "r", encoding="utf-8") as f:
133
133
  data = json.load(f)
134
134
 
135
135
  manifest = AnalysisManifest.model_validate(data)
@@ -22,7 +22,7 @@ def _load_all_analyses(analysis_path: Path) -> list[tuple[str, AnalysisInsights,
22
22
 
23
23
  Returns the root analysis as 'overview' plus one entry per expanded component.
24
24
  """
25
- with open(analysis_path, "r") as f:
25
+ with open(analysis_path, "r", encoding="utf-8") as f:
26
26
  data = json.load(f)
27
27
 
28
28
  root_analysis, sub_analyses = parse_unified_analysis(data)