codeboarding 0.14.3__tar.gz → 0.14.4__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 (200) hide show
  1. {codeboarding-0.14.3/codeboarding.egg-info → codeboarding-0.14.4}/PKG-INFO +1 -1
  2. {codeboarding-0.14.3 → codeboarding-0.14.4/codeboarding.egg-info}/PKG-INFO +1 -1
  3. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding.egg-info/SOURCES.txt +1 -0
  4. codeboarding-0.14.4/health_main.py +152 -0
  5. {codeboarding-0.14.3 → codeboarding-0.14.4}/pyproject.toml +1 -1
  6. codeboarding-0.14.4/static_analyzer/dotnet_solution.py +62 -0
  7. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/csharp_adapter.py +50 -13
  8. codeboarding-0.14.3/static_analyzer/dotnet_solution.py +0 -29
  9. {codeboarding-0.14.3 → codeboarding-0.14.4}/LICENSE +0 -0
  10. {codeboarding-0.14.3 → codeboarding-0.14.4}/PYPI.md +0 -0
  11. {codeboarding-0.14.3 → codeboarding-0.14.4}/README.md +0 -0
  12. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/__init__.py +0 -0
  13. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/agent_responses.py +0 -0
  14. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/change_status.py +0 -0
  15. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/component_ownership.py +0 -0
  16. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/constants.py +0 -0
  17. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/content_hash.py +0 -0
  18. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/file_index_models.py +0 -0
  19. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/incremental_results.py +0 -0
  20. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/llm_config.py +0 -0
  21. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/llm_errors.py +0 -0
  22. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/llm_renderers/__init__.py +0 -0
  23. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/llm_renderers/call_graph.py +0 -0
  24. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/llm_renderers/scope.py +0 -0
  25. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/model_capabilities.py +0 -0
  26. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/planner_agent.py +0 -0
  27. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/prompts/__init__.py +0 -0
  28. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/prompts/profiles.py +0 -0
  29. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/prompts/shared.py +0 -0
  30. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/relation_edges.py +0 -0
  31. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/retry.py +0 -0
  32. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/scope_analysis_agent.py +0 -0
  33. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/scope_ids.py +0 -0
  34. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/tools/__init__.py +0 -0
  35. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/tools/base.py +0 -0
  36. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/tools/get_method_calls.py +0 -0
  37. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/tools/read_file.py +0 -0
  38. {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/tree_planner_agent.py +0 -0
  39. {codeboarding-0.14.3 → codeboarding-0.14.4}/clustering_ids.py +0 -0
  40. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding.egg-info/dependency_links.txt +0 -0
  41. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding.egg-info/entry_points.txt +0 -0
  42. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding.egg-info/requires.txt +0 -0
  43. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding.egg-info/top_level.txt +0 -0
  44. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/__init__.py +0 -0
  45. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/bootstrap.py +0 -0
  46. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/commands/__init__.py +0 -0
  47. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/commands/full_analysis.py +0 -0
  48. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/commands/incremental_analysis.py +0 -0
  49. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/commands/partial_analysis.py +0 -0
  50. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/render.py +0 -0
  51. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/view_instructions.py +0 -0
  52. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/__init__.py +0 -0
  53. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/analysis.py +0 -0
  54. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/orchestration.py +0 -0
  55. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/sources/__init__.py +0 -0
  56. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/sources/local.py +0 -0
  57. {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/sources/remote.py +0 -0
  58. {codeboarding-0.14.3 → codeboarding-0.14.4}/constants.py +0 -0
  59. {codeboarding-0.14.3 → codeboarding-0.14.4}/core/__init__.py +0 -0
  60. {codeboarding-0.14.3 → codeboarding-0.14.4}/core/plugin_loader.py +0 -0
  61. {codeboarding-0.14.3 → codeboarding-0.14.4}/core/protocols.py +0 -0
  62. {codeboarding-0.14.3 → codeboarding-0.14.4}/core/registry.py +0 -0
  63. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/__init__.py +0 -0
  64. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/analysis_json.py +0 -0
  65. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/diagram_generator.py +0 -0
  66. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/exceptions.py +0 -0
  67. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/file_coverage.py +0 -0
  68. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/file_index.py +0 -0
  69. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/incremental_changes.py +0 -0
  70. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/incremental_update.py +0 -0
  71. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/io_utils.py +0 -0
  72. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/run_context.py +0 -0
  73. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/run_mode.py +0 -0
  74. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/scope_assembly.py +0 -0
  75. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/scope_plan.py +0 -0
  76. {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/tree_shape.py +0 -0
  77. {codeboarding-0.14.3 → codeboarding-0.14.4}/github_action.py +0 -0
  78. {codeboarding-0.14.3 → codeboarding-0.14.4}/health/__init__.py +0 -0
  79. {codeboarding-0.14.3 → codeboarding-0.14.4}/health/checks/__init__.py +0 -0
  80. {codeboarding-0.14.3 → codeboarding-0.14.4}/health/checks/circular_deps.py +0 -0
  81. {codeboarding-0.14.3 → codeboarding-0.14.4}/health/checks/function_size.py +0 -0
  82. {codeboarding-0.14.3 → codeboarding-0.14.4}/health/checks/unused_code_diagnostics.py +0 -0
  83. {codeboarding-0.14.3 → codeboarding-0.14.4}/health/config.py +0 -0
  84. {codeboarding-0.14.3 → codeboarding-0.14.4}/health/models.py +0 -0
  85. {codeboarding-0.14.3 → codeboarding-0.14.4}/health/runner.py +0 -0
  86. {codeboarding-0.14.3 → codeboarding-0.14.4}/install.py +0 -0
  87. {codeboarding-0.14.3 → codeboarding-0.14.4}/logging_config.py +0 -0
  88. {codeboarding-0.14.3 → codeboarding-0.14.4}/main.py +0 -0
  89. {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/__init__.py +0 -0
  90. {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/callbacks.py +0 -0
  91. {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/context.py +0 -0
  92. {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/mixin.py +0 -0
  93. {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/paths.py +0 -0
  94. {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/stats.py +0 -0
  95. {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/writers.py +0 -0
  96. {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/__init__.py +0 -0
  97. {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/html.py +0 -0
  98. {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/html_template.py +0 -0
  99. {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/markdown.py +0 -0
  100. {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/mdx.py +0 -0
  101. {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/rendering.py +0 -0
  102. {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/sphinx.py +0 -0
  103. {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/__init__.py +0 -0
  104. {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/change_detector.py +0 -0
  105. {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/errors.py +0 -0
  106. {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/fingerprint_diff.py +0 -0
  107. {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/git_ops.py +0 -0
  108. {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/ignore.py +0 -0
  109. {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/path_utils.py +0 -0
  110. {codeboarding-0.14.3 → codeboarding-0.14.4}/setup.cfg +0 -0
  111. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/__init__.py +0 -0
  112. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/analysis_cache.py +0 -0
  113. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/analysis_result.py +0 -0
  114. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/cfg/__init__.py +0 -0
  115. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/cfg/call_graph.py +0 -0
  116. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/cfg/edge.py +0 -0
  117. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/cfg/location_key.py +0 -0
  118. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/cluster_relations.py +0 -0
  119. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/__init__.py +0 -0
  120. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/exceptions.py +0 -0
  121. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/models.py +0 -0
  122. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/__init__.py +0 -0
  123. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/draft.py +0 -0
  124. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/frontier.py +0 -0
  125. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/inventory.py +0 -0
  126. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/replay.py +0 -0
  127. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/spec.py +0 -0
  128. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/tokens.py +0 -0
  129. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/service.py +0 -0
  130. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/config.py +0 -0
  131. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/csharp_config_scanner.py +0 -0
  132. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/dotnet_sdk.py +0 -0
  133. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/__init__.py +0 -0
  134. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/__init__.py +0 -0
  135. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/go_adapter.py +0 -0
  136. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/java_adapter.py +0 -0
  137. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/php_adapter.py +0 -0
  138. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/python_adapter.py +0 -0
  139. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/rust_adapter.py +0 -0
  140. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/typescript_adapter.py +0 -0
  141. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/call_graph_builder.py +0 -0
  142. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/edge_build_context.py +0 -0
  143. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/edge_builder.py +0 -0
  144. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/hierarchy_builder.py +0 -0
  145. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/language_adapter.py +0 -0
  146. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/lsp_client.py +0 -0
  147. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/lsp_constants.py +0 -0
  148. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/lsp_recycler.py +0 -0
  149. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/models.py +0 -0
  150. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/process_memory.py +0 -0
  151. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/progress.py +0 -0
  152. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/protocols.py +0 -0
  153. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/result_converter.py +0 -0
  154. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/source_inspector.py +0 -0
  155. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/symbol_table.py +0 -0
  156. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/utils.py +0 -0
  157. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/exceptions.py +0 -0
  158. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/external_calls.py +0 -0
  159. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/graph_definitions.py +0 -0
  160. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/incremental_orchestrator.py +0 -0
  161. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/internal_references.py +0 -0
  162. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/java_config_scanner.py +0 -0
  163. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/java_utils.py +0 -0
  164. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/language_results.py +0 -0
  165. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/lsp_client/__init__.py +0 -0
  166. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/lsp_client/diagnostics.py +0 -0
  167. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/node.py +0 -0
  168. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/programming_language.py +0 -0
  169. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/reference_resolver.py +0 -0
  170. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/scanner.py +0 -0
  171. {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/typescript_config_scanner.py +0 -0
  172. {codeboarding-0.14.3 → codeboarding-0.14.4}/telemetry/__init__.py +0 -0
  173. {codeboarding-0.14.3 → codeboarding-0.14.4}/telemetry/device_id.py +0 -0
  174. {codeboarding-0.14.3 → codeboarding-0.14.4}/telemetry/events.py +0 -0
  175. {codeboarding-0.14.3 → codeboarding-0.14.4}/telemetry/schemas.py +0 -0
  176. {codeboarding-0.14.3 → codeboarding-0.14.4}/telemetry/service.py +0 -0
  177. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_cli_parser.py +0 -0
  178. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_github_action.py +0 -0
  179. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_install.py +0 -0
  180. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_logging_config.py +0 -0
  181. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_main.py +0 -0
  182. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_persisted_analysis_artifacts.py +0 -0
  183. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_pyproject_packages.py +0 -0
  184. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_registry_coverage.py +0 -0
  185. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_telemetry_events.py +0 -0
  186. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_telemetry_service.py +0 -0
  187. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_tool_registry.py +0 -0
  188. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_user_config.py +0 -0
  189. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_view_instructions.py +0 -0
  190. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_vscode_constants.py +0 -0
  191. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_windows_compatibility.py +0 -0
  192. {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_windows_encoding.py +0 -0
  193. {codeboarding-0.14.3 → codeboarding-0.14.4}/tool_registry/__init__.py +0 -0
  194. {codeboarding-0.14.3 → codeboarding-0.14.4}/tool_registry/installers.py +0 -0
  195. {codeboarding-0.14.3 → codeboarding-0.14.4}/tool_registry/manifest.py +0 -0
  196. {codeboarding-0.14.3 → codeboarding-0.14.4}/tool_registry/paths.py +0 -0
  197. {codeboarding-0.14.3 → codeboarding-0.14.4}/tool_registry/registry.py +0 -0
  198. {codeboarding-0.14.3 → codeboarding-0.14.4}/user_config.py +0 -0
  199. {codeboarding-0.14.3 → codeboarding-0.14.4}/utils.py +0 -0
  200. {codeboarding-0.14.3 → codeboarding-0.14.4}/vscode_constants.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeboarding
3
- Version: 0.14.3
3
+ Version: 0.14.4
4
4
  Summary: Interactive Diagrams for Code
5
5
  Author: CodeBoarding Team
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeboarding
3
- Version: 0.14.3
3
+ Version: 0.14.4
4
4
  Summary: Interactive Diagrams for Code
5
5
  Author: CodeBoarding Team
6
6
  License-Expression: MIT
@@ -4,6 +4,7 @@ README.md
4
4
  clustering_ids.py
5
5
  constants.py
6
6
  github_action.py
7
+ health_main.py
7
8
  install.py
8
9
  logging_config.py
9
10
  main.py
@@ -0,0 +1,152 @@
1
+ """Standalone entry point for running health checks on a repository.
2
+
3
+ Runs static analysis and health checks only — no LLM agents or diagram generation.
4
+ Useful for testing health checks in isolation and for CI/CD health gates.
5
+
6
+ Usage:
7
+ # Local repository (output written to <repo>/.codeboarding/health/)
8
+ python health_main.py --local /path/to/repo
9
+
10
+ # Remote repository (cloned to cwd/repos/, output to cwd/<repo_name>/.codeboarding/health/)
11
+ python health_main.py https://github.com/user/repo
12
+ """
13
+
14
+ import argparse
15
+ import logging
16
+ from pathlib import Path
17
+
18
+ from health.runner import run_health_checks
19
+ from health.config import initialize_health_dir, load_health_config
20
+ from logging_config import setup_logging
21
+ from repo_utils import clone_repository, get_repo_name
22
+ from static_analyzer import get_static_analysis
23
+ from utils import CODEBOARDING_DIR_NAME, get_artifact_dir
24
+ from vscode_constants import update_config
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ def run_health_check_local(
30
+ repo_path: Path,
31
+ project_name: str | None = None,
32
+ ) -> None:
33
+ """Run health checks on a local repository.
34
+
35
+ Args:
36
+ repo_path: Path to a local repository
37
+ project_name: Optional project name (default: repo directory name)
38
+ """
39
+ resolved_repo_path = repo_path.resolve()
40
+ if not resolved_repo_path.is_dir():
41
+ raise ValueError(f"Repository path does not exist: {resolved_repo_path}")
42
+
43
+ resolved_project_name = project_name or resolved_repo_path.name
44
+ output_dir = resolved_repo_path / CODEBOARDING_DIR_NAME
45
+
46
+ output_dir.mkdir(parents=True, exist_ok=True)
47
+ setup_logging(log_dir=output_dir)
48
+
49
+ _run_health_checks(resolved_repo_path, resolved_project_name, output_dir)
50
+
51
+
52
+ def run_health_check_remote(
53
+ repo_url: str,
54
+ project_name: str | None = None,
55
+ ) -> None:
56
+ """Run health checks on a remote repository.
57
+
58
+ Args:
59
+ repo_url: URL of a remote Git repository
60
+ project_name: Optional project name (default: extracted from URL)
61
+ """
62
+ repo_root = Path("repos")
63
+ repo_name = clone_repository(repo_url, repo_root)
64
+ resolved_repo_path = repo_root / repo_name
65
+ resolved_project_name = project_name or get_repo_name(repo_url)
66
+ output_dir = Path.cwd() / repo_name / CODEBOARDING_DIR_NAME
67
+
68
+ output_dir.mkdir(parents=True, exist_ok=True)
69
+ setup_logging(log_dir=output_dir)
70
+
71
+ _run_health_checks(resolved_repo_path, resolved_project_name, output_dir)
72
+
73
+
74
+ def _run_health_checks(repo_path: Path, project_name: str, output_dir: Path) -> None:
75
+ """Core health check logic shared by local and remote paths."""
76
+ logger.info(f"Running health checks on '{project_name}' at {repo_path}")
77
+
78
+ static_analysis = get_static_analysis(repo_path, cache_dir=get_artifact_dir(repo_path))
79
+
80
+ # Load health check configuration and initialize health config dir
81
+ health_config_dir = output_dir / "health"
82
+ initialize_health_dir(health_config_dir)
83
+ health_config = load_health_config(health_config_dir)
84
+
85
+ report = run_health_checks(static_analysis, project_name, config=health_config, repo_path=repo_path)
86
+
87
+ if report is None:
88
+ logger.warning("Health checks skipped: no languages found in static analysis results")
89
+ return
90
+
91
+ report_path = health_config_dir / "health_report.json"
92
+ report_path.write_text(report.model_dump_json(indent=2, exclude_none=True))
93
+
94
+ logger.info(f"Health report written to {report_path} (overall score: {report.overall_score:.3f})")
95
+
96
+
97
+ def main():
98
+ """Main entry point that parses CLI arguments and routes to subcommands."""
99
+ parser = argparse.ArgumentParser(
100
+ description="Run static analysis health checks on a repository (local or remote)",
101
+ formatter_class=argparse.RawDescriptionHelpFormatter,
102
+ epilog="""
103
+ Examples:
104
+ # Local repository (output written to <repo>/.codeboarding/health/)
105
+ python health_main.py --local /path/to/repo
106
+
107
+ # Remote repository (cloned to cwd/repos/, output to cwd/<repo_name>/.codeboarding/health/)
108
+ python health_main.py https://github.com/user/repo
109
+
110
+ """,
111
+ )
112
+ parser.add_argument(
113
+ "repositories",
114
+ nargs="*",
115
+ help="One or more remote Git repository URLs to run health checks on",
116
+ )
117
+ parser.add_argument("--local", type=Path, help="Path to a local repository")
118
+ parser.add_argument(
119
+ "--project-name",
120
+ type=str,
121
+ default=None,
122
+ help="Name of the project (default: extracted from repo path or URL)",
123
+ )
124
+ parser.add_argument(
125
+ "--binary-location", type=Path, help="Path to the binary directory for language servers and tools"
126
+ )
127
+
128
+ args = parser.parse_args()
129
+
130
+ # Validate: must provide either remote repos or --local, not both
131
+ has_remote = bool(args.repositories)
132
+ has_local = args.local is not None
133
+
134
+ if has_remote == has_local:
135
+ parser.error("Provide either one or more remote repositories or --local, but not both.")
136
+
137
+ # Resolve binary paths for tools (tokei, LSP servers, etc.)
138
+ if args.binary_location:
139
+ update_config(args.binary_location)
140
+
141
+ try:
142
+ if has_local:
143
+ run_health_check_local(args.local, args.project_name)
144
+ else:
145
+ for repo_url in args.repositories:
146
+ run_health_check_remote(repo_url, args.project_name)
147
+ except ValueError as e:
148
+ parser.error(str(e))
149
+
150
+
151
+ if __name__ == "__main__":
152
+ main()
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codeboarding"
7
- version = "0.14.3"
7
+ version = "0.14.4"
8
8
  description = "Interactive Diagrams for Code"
9
9
  readme = "PYPI.md"
10
10
  license = "MIT"
@@ -0,0 +1,62 @@
1
+ """The projects a .NET solution file lists."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ import xml.etree.ElementTree as ElementTree
7
+ from pathlib import Path
8
+
9
+ PROJECT_SUFFIXES = (".csproj", ".fsproj")
10
+ # ``Project("{type guid}") = "Name", "relative\path.csproj", "{project guid}"``
11
+ _SLN_PROJECT_LINE = re.compile(r'^Project\("\{[^}]*\}"\)\s*=\s*"[^"]*",\s*"([^"]+)"', re.MULTILINE)
12
+
13
+
14
+ def solution_projects(solution: Path) -> list[Path]:
15
+ """The project files a ``.sln`` or ``.slnx`` lists, absolute, in listing order.
16
+
17
+ Solution folders and files that do not exist are left out; a ``.sln`` names
18
+ its solution folders with the same ``Project(...)`` syntax as its projects.
19
+ """
20
+ if solution.suffix.lower() == ".slnx":
21
+ listed = [element.get("Path") or "" for element in ElementTree.parse(solution).iter("Project")]
22
+ else:
23
+ listed = _SLN_PROJECT_LINE.findall(solution.read_text(encoding="utf-8-sig", errors="replace"))
24
+ projects: list[Path] = []
25
+ for raw in listed:
26
+ path = _project_file(solution.parent, raw)
27
+ if path is not None and path not in projects:
28
+ projects.append(path)
29
+ return projects
30
+
31
+
32
+ def analyzer_project_references(projects: list[Path]) -> list[Path]:
33
+ """The projects referenced with ``OutputItemType="Analyzer"``, absolute, in listing order.
34
+
35
+ Why: an analyzer reference resolves to the referenced project's output assembly, so
36
+ it stays unresolved until that project is built.
37
+ """
38
+ analyzers: list[Path] = []
39
+ for project in projects:
40
+ try:
41
+ root = ElementTree.parse(project).getroot()
42
+ except (ElementTree.ParseError, OSError):
43
+ continue
44
+ for reference in root.iter():
45
+ # Legacy-format projects namespace every tag, so match on the local name.
46
+ if reference.tag.rpartition("}")[2] != "ProjectReference":
47
+ continue
48
+ if (reference.get("OutputItemType") or "").strip().lower() != "analyzer":
49
+ continue
50
+ raw = reference.get("Include") or ""
51
+ if not raw:
52
+ continue
53
+ path = _project_file(project.parent, raw)
54
+ if path is not None and path not in analyzers:
55
+ analyzers.append(path)
56
+ return analyzers
57
+
58
+
59
+ def _project_file(base: Path, raw: str) -> Path | None:
60
+ """The project ``raw`` names relative to ``base``, or None if it is not one on disk."""
61
+ path = (base / raw.replace("\\", "/")).resolve()
62
+ return path if path.suffix.lower() in PROJECT_SUFFIXES and path.is_file() else None
@@ -12,7 +12,7 @@ from pathlib import Path
12
12
  from repo_utils.ignore import RepoIgnoreManager
13
13
  from static_analyzer.config import Language, NodeType
14
14
  from static_analyzer.dotnet_sdk import DotnetSdkError, resolve_dotnet_sdk, system_dotnet_env
15
- from static_analyzer.dotnet_solution import solution_projects
15
+ from static_analyzer.dotnet_solution import analyzer_project_references, solution_projects
16
16
  from static_analyzer.engine.language_adapter import LanguageAdapter
17
17
  from static_analyzer.engine.lsp_client import LSPClient
18
18
  from static_analyzer.engine.source_inspector import SourceInspector
@@ -29,6 +29,7 @@ from tool_registry import (
29
29
  logger = logging.getLogger(__name__)
30
30
 
31
31
  _MULTI_TARGET_PROJECT_THRESHOLD = 25
32
+ _DOTNET_TIMEOUT_SECONDS = 600
32
33
  _SINGLE_TARGET_FRAMEWORK_TARGETS = r"""<Project>
33
34
  <PropertyGroup Condition="'$(CodeBoardingOriginalDirectoryBuildTargetsPath)' == ''">
34
35
  <CodeBoardingDirectoryBuildTargetsPath>$([MSBuild]::GetPathOfFileAbove('Directory.Build.targets', '$(MSBuildProjectDirectory)'))</CodeBoardingDirectoryBuildTargetsPath>
@@ -47,6 +48,14 @@ _SINGLE_TARGET_FRAMEWORK_TARGETS = r"""<Project>
47
48
  <TargetFrameworks>$([System.String]::Copy('$(CodeBoardingTargetFrameworks)').Trim(';').Split(';')[0])</TargetFrameworks>
48
49
  <TargetFrameworks Condition="'$(CodeBoardingPreferredTargetFramework)' != '' and $(CodeBoardingTargetFrameworks.Contains(';$(CodeBoardingPreferredTargetFramework);'))">$(CodeBoardingPreferredTargetFramework)</TargetFrameworks>
49
50
  </PropertyGroup>
51
+ <!-- An analyzer whose assembly is absent cannot run, but Roslyn keeps it as an
52
+ UnresolvedAnalyzerReference whose checksum throws, failing every
53
+ textDocument/implementation request in the solution. -->
54
+ <Target Name="CodeBoardingDropMissingAnalyzers" BeforeTargets="CoreCompile">
55
+ <ItemGroup>
56
+ <Analyzer Remove="@(Analyzer)" Condition="!Exists('%(Analyzer.FullPath)')" />
57
+ </ItemGroup>
58
+ </Target>
50
59
  </Project>
51
60
  """
52
61
 
@@ -326,14 +335,15 @@ class CSharpAdapter(LanguageAdapter):
326
335
  client.wait_for_diagnostics_quiesce(idle_seconds=2.0, max_wait=30.0)
327
336
 
328
337
  def prepare_project(self, project_root: Path) -> None:
329
- """Run ``dotnet restore`` so csharp-ls can resolve framework references.
338
+ """Run ``dotnet restore``, then build any analyzer projects, so csharp-ls can
339
+ resolve framework references and analyzer assemblies.
330
340
 
331
341
  Why: csharp-ls relies on Roslyn / MSBuild to load the project, and
332
342
  MSBuild needs ``obj/project.assets.json`` (produced by restore) to
333
343
  find the .NET runtime reference assemblies. Without it, csharp-ls
334
344
  emits a flood of bogus ``CS0518: Predefined type System.X is not
335
- defined`` diagnostics for every file. Restore is idempotent and
336
- only writes under ``obj/`` (which we already gitignore).
345
+ defined`` diagnostics for every file. Restore is idempotent and only writes
346
+ under ``obj/``; building an analyzer project also writes its ``bin/``.
337
347
 
338
348
  Restore runs under the MSBuild environment csharp-ls gets, so the two
339
349
  evaluate every path the same way and the server finds what restore wrote.
@@ -357,7 +367,12 @@ class CSharpAdapter(LanguageAdapter):
357
367
 
358
368
  env = os.environ.copy()
359
369
  env.update(self.get_lsp_env(project_root))
360
- if self._restore(resolution.dotnet_path, target, project_root, env) or target.suffix not in (".sln", ".slnx"):
370
+ if target.suffix not in (".sln", ".slnx"):
371
+ self._dotnet("restore", resolution.dotnet_path, target, project_root, env)
372
+ self._build_analyzers(resolution.dotnet_path, [target], project_root, env)
373
+ return
374
+ if self._dotnet("restore", resolution.dotnet_path, target, project_root, env):
375
+ self._build_analyzers(resolution.dotnet_path, solution_projects(target), project_root, env)
361
376
  return
362
377
  # A solution restore evaluates every project before writing any assets, so one
363
378
  # project it cannot evaluate (a missing workload, a broken import) leaves the
@@ -365,8 +380,11 @@ class CSharpAdapter(LanguageAdapter):
365
380
  # or transitive project reference anywhere. Each member on its own only fails
366
381
  # for itself.
367
382
  projects = solution_projects(target)
368
- restored = sum(self._restore(resolution.dotnet_path, project, project_root, env) for project in projects)
383
+ restored = sum(
384
+ self._dotnet("restore", resolution.dotnet_path, project, project_root, env) for project in projects
385
+ )
369
386
  logger.info("dotnet restore per project: %d of %d restored", restored, len(projects))
387
+ self._build_analyzers(resolution.dotnet_path, projects, project_root, env)
370
388
 
371
389
  def get_lsp_env(self, project_root: Path | None = None) -> dict[str, str]:
372
390
  """Return the .NET environment needed by csharp-ls.
@@ -411,29 +429,48 @@ class CSharpAdapter(LanguageAdapter):
411
429
  found.append(sym.get("name", ""))
412
430
  return found
413
431
 
414
- def _restore(self, dotnet_path: str, target: Path, project_root: Path, env: dict[str, str]) -> bool:
432
+ def _build_analyzers(self, dotnet_path: str, projects: list[Path], project_root: Path, env: dict[str, str]) -> None:
433
+ """Build the projects referenced as analyzers so Roslyn can resolve them.
434
+
435
+ Why: restore does not produce an output assembly, so Roslyn holds an
436
+ ``UnresolvedAnalyzerReference`` whose checksum throws, failing every
437
+ ``textDocument/implementation`` request across the whole solution.
438
+ """
439
+ analyzers = analyzer_project_references(projects)
440
+ if not analyzers:
441
+ return
442
+ built = sum(self._dotnet("build", dotnet_path, analyzer, project_root, env) for analyzer in analyzers)
443
+ if built < len(analyzers):
444
+ # The injected target drops what stays missing, so analysis continues without
445
+ # the symbols that generator would have produced.
446
+ logger.warning("dotnet build analyzer projects: only %d of %d built", built, len(analyzers))
447
+ else:
448
+ logger.info("dotnet build analyzer projects: %d of %d built", built, len(analyzers))
449
+
450
+ def _dotnet(self, verb: str, dotnet_path: str, target: Path, project_root: Path, env: dict[str, str]) -> bool:
415
451
  try:
416
452
  result = subprocess.run(
417
- [dotnet_path, "restore", os.path.relpath(target, project_root), "--nologo", "--verbosity", "minimal"],
453
+ [dotnet_path, verb, os.path.relpath(target, project_root), "--nologo", "--verbosity", "minimal"],
418
454
  cwd=str(project_root),
419
455
  env=env,
420
456
  capture_output=True,
421
457
  text=True,
422
- timeout=600,
458
+ timeout=_DOTNET_TIMEOUT_SECONDS,
423
459
  )
424
460
  except subprocess.TimeoutExpired:
425
- logger.warning("dotnet restore timed out after 600s for %s", target.name)
461
+ logger.warning("dotnet %s timed out after %ds for %s", verb, _DOTNET_TIMEOUT_SECONDS, target.name)
426
462
  return False
427
463
  except OSError as exc:
428
- logger.warning("dotnet restore could not be invoked: %s", exc)
464
+ logger.warning("dotnet %s could not be invoked: %s", verb, exc)
429
465
  return False
430
466
  if result.returncode != 0:
431
467
  logger.warning(
432
- "dotnet restore failed for %s (exit %d): %s",
468
+ "dotnet %s failed for %s (exit %d): %s",
469
+ verb,
433
470
  target.name,
434
471
  result.returncode,
435
472
  (result.stderr or result.stdout)[-500:],
436
473
  )
437
474
  return False
438
- logger.info("dotnet restore completed for %s", target.name)
475
+ logger.info("dotnet %s completed for %s", verb, target.name)
439
476
  return True
@@ -1,29 +0,0 @@
1
- """The projects a .NET solution file lists."""
2
-
3
- from __future__ import annotations
4
-
5
- import re
6
- import xml.etree.ElementTree as ElementTree
7
- from pathlib import Path
8
-
9
- PROJECT_SUFFIXES = (".csproj", ".fsproj")
10
- # ``Project("{type guid}") = "Name", "relative\path.csproj", "{project guid}"``
11
- _SLN_PROJECT_LINE = re.compile(r'^Project\("\{[^}]*\}"\)\s*=\s*"[^"]*",\s*"([^"]+)"', re.MULTILINE)
12
-
13
-
14
- def solution_projects(solution: Path) -> list[Path]:
15
- """The project files a ``.sln`` or ``.slnx`` lists, absolute, in listing order.
16
-
17
- Solution folders and files that do not exist are left out; a ``.sln`` names
18
- its solution folders with the same ``Project(...)`` syntax as its projects.
19
- """
20
- if solution.suffix.lower() == ".slnx":
21
- listed = [element.get("Path") or "" for element in ElementTree.parse(solution).iter("Project")]
22
- else:
23
- listed = _SLN_PROJECT_LINE.findall(solution.read_text(encoding="utf-8-sig", errors="replace"))
24
- projects: list[Path] = []
25
- for raw in listed:
26
- path = (solution.parent / raw.replace("\\", "/")).resolve()
27
- if path.suffix.lower() in PROJECT_SUFFIXES and path.is_file() and path not in projects:
28
- projects.append(path)
29
- return projects
File without changes
File without changes
File without changes
File without changes
File without changes