codeboarding 0.15.3__tar.gz → 0.15.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 (200) hide show
  1. {codeboarding-0.15.3/codeboarding.egg-info → codeboarding-0.15.5}/PKG-INFO +4 -1
  2. {codeboarding-0.15.3 → codeboarding-0.15.5}/README.md +6 -4
  3. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/prompts/shared.py +12 -2
  4. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/scope_analysis_agent.py +44 -11
  5. {codeboarding-0.15.3 → codeboarding-0.15.5/codeboarding.egg-info}/PKG-INFO +4 -1
  6. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding.egg-info/SOURCES.txt +3 -0
  7. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding.egg-info/requires.txt +3 -0
  8. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_cli/commands/incremental_analysis.py +24 -13
  9. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_workflows/analysis.py +20 -3
  10. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_workflows/fingerprint_diff.py +15 -0
  11. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/analysis_json.py +4 -1
  12. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/diagram_generator.py +8 -0
  13. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/scope_assembly.py +19 -2
  14. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/install.py +115 -87
  15. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/tool_registry/__init__.py +7 -1
  16. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/tool_registry/installers.py +126 -11
  17. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/tool_registry/java.py +23 -0
  18. codeboarding-0.15.5/infra/tool_registry/kotlin-server-1.json +11 -0
  19. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/tool_registry/manifest.py +8 -3
  20. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/tool_registry/registry.py +79 -24
  21. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/vscode_constants.py +10 -0
  22. {codeboarding-0.15.3 → codeboarding-0.15.5}/pyproject.toml +6 -1
  23. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/__init__.py +56 -30
  24. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/analysis_cache.py +7 -1
  25. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/models.py +3 -2
  26. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/names/tokens.py +61 -0
  27. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/config.py +5 -0
  28. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/adapters/__init__.py +2 -0
  29. codeboarding-0.15.5/static_analyzer/engine/adapters/cpp_adapter.py +322 -0
  30. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/adapters/java_adapter.py +110 -1
  31. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/adapters/kotlin_adapter.py +9 -1
  32. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/adapters/rust_adapter.py +2 -0
  33. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/call_graph_builder.py +9 -2
  34. codeboarding-0.15.5/static_analyzer/engine/cpp_templates.py +174 -0
  35. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/edge_build_context.py +2 -0
  36. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/edge_builder.py +51 -10
  37. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/hierarchy_builder.py +53 -32
  38. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/language_adapter.py +54 -2
  39. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/lsp_client.py +132 -27
  40. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/models.py +5 -0
  41. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/protocols.py +6 -0
  42. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/result_converter.py +12 -3
  43. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/source_inspector.py +137 -9
  44. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/symbol_table.py +15 -6
  45. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/graph_definitions.py +9 -3
  46. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/incremental_orchestrator.py +25 -4
  47. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/java_config_scanner.py +32 -0
  48. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/lsp_client/diagnostics.py +2 -0
  49. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/node.py +6 -0
  50. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/programming_language.py +5 -1
  51. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/scanner.py +16 -2
  52. {codeboarding-0.15.3 → codeboarding-0.15.5}/LICENSE +0 -0
  53. {codeboarding-0.15.3 → codeboarding-0.15.5}/PYPI.md +0 -0
  54. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/__init__.py +0 -0
  55. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/agent_responses.py +0 -0
  56. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/change_status.py +0 -0
  57. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/component_ownership.py +0 -0
  58. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/constants.py +0 -0
  59. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/content_hash.py +0 -0
  60. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/file_index_models.py +0 -0
  61. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/incremental_results.py +0 -0
  62. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/llm_config.py +0 -0
  63. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/llm_errors.py +0 -0
  64. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/llm_renderers/__init__.py +0 -0
  65. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/llm_renderers/call_graph.py +0 -0
  66. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/llm_renderers/scope.py +0 -0
  67. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/model_capabilities.py +0 -0
  68. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/planner_agent.py +0 -0
  69. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/prompts/__init__.py +0 -0
  70. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/prompts/profiles.py +0 -0
  71. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/relation_edges.py +0 -0
  72. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/retry.py +0 -0
  73. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/scope_ids.py +0 -0
  74. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/tools/__init__.py +0 -0
  75. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/tools/base.py +0 -0
  76. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/tools/get_method_calls.py +0 -0
  77. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/tools/read_file.py +0 -0
  78. {codeboarding-0.15.3 → codeboarding-0.15.5}/agents/tree_planner_agent.py +0 -0
  79. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding.egg-info/dependency_links.txt +0 -0
  80. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding.egg-info/entry_points.txt +0 -0
  81. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding.egg-info/top_level.txt +0 -0
  82. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_cli/__init__.py +0 -0
  83. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_cli/bootstrap.py +0 -0
  84. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_cli/commands/__init__.py +0 -0
  85. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_cli/commands/full_analysis.py +0 -0
  86. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_cli/commands/partial_analysis.py +0 -0
  87. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_cli/github_action.py +0 -0
  88. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_cli/main.py +0 -0
  89. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_cli/render.py +0 -0
  90. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_cli/view_instructions.py +0 -0
  91. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_workflows/__init__.py +0 -0
  92. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_workflows/orchestration.py +0 -0
  93. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_workflows/sources/__init__.py +0 -0
  94. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_workflows/sources/local.py +0 -0
  95. {codeboarding-0.15.3 → codeboarding-0.15.5}/codeboarding_workflows/sources/remote.py +0 -0
  96. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/__init__.py +0 -0
  97. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/cluster_relations.py +0 -0
  98. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/exceptions.py +0 -0
  99. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/file_coverage.py +0 -0
  100. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/file_index.py +0 -0
  101. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/incremental_changes.py +0 -0
  102. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/incremental_update.py +0 -0
  103. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/io_utils.py +0 -0
  104. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/reference_resolver.py +0 -0
  105. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/run_context.py +0 -0
  106. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/run_mode.py +0 -0
  107. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/scope_plan.py +0 -0
  108. {codeboarding-0.15.3 → codeboarding-0.15.5}/diagram_analysis/tree_shape.py +0 -0
  109. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/__init__.py +0 -0
  110. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/checks/__init__.py +0 -0
  111. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/checks/circular_deps.py +0 -0
  112. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/checks/function_size.py +0 -0
  113. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/checks/unused_code_diagnostics.py +0 -0
  114. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/config.py +0 -0
  115. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/main.py +0 -0
  116. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/models.py +0 -0
  117. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/plugins/__init__.py +0 -0
  118. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/plugins/plugin_loader.py +0 -0
  119. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/plugins/protocols.py +0 -0
  120. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/plugins/registry.py +0 -0
  121. {codeboarding-0.15.3 → codeboarding-0.15.5}/health/runner.py +0 -0
  122. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/__init__.py +0 -0
  123. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/clustering_ids.py +0 -0
  124. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/constants.py +0 -0
  125. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/logging_config.py +0 -0
  126. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/__init__.py +0 -0
  127. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/callbacks.py +0 -0
  128. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/context.py +0 -0
  129. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/mixin.py +0 -0
  130. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/paths.py +0 -0
  131. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/stats.py +0 -0
  132. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/telemetry/__init__.py +0 -0
  133. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/telemetry/device_id.py +0 -0
  134. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/telemetry/events.py +0 -0
  135. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/telemetry/schemas.py +0 -0
  136. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/telemetry/service.py +0 -0
  137. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/monitoring/writers.py +0 -0
  138. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/repo_utils/__init__.py +0 -0
  139. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/repo_utils/change_detector.py +0 -0
  140. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/repo_utils/errors.py +0 -0
  141. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/repo_utils/git_ops.py +0 -0
  142. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/repo_utils/ignore.py +0 -0
  143. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/repo_utils/path_utils.py +0 -0
  144. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/tool_registry/grammars.py +0 -0
  145. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/tool_registry/paths.py +0 -0
  146. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/user_config.py +0 -0
  147. {codeboarding-0.15.3 → codeboarding-0.15.5}/infra/utils.py +0 -0
  148. {codeboarding-0.15.3 → codeboarding-0.15.5}/output_generators/__init__.py +0 -0
  149. {codeboarding-0.15.3 → codeboarding-0.15.5}/output_generators/html.py +0 -0
  150. {codeboarding-0.15.3 → codeboarding-0.15.5}/output_generators/html_template.py +0 -0
  151. {codeboarding-0.15.3 → codeboarding-0.15.5}/output_generators/markdown.py +0 -0
  152. {codeboarding-0.15.3 → codeboarding-0.15.5}/output_generators/mdx.py +0 -0
  153. {codeboarding-0.15.3 → codeboarding-0.15.5}/output_generators/rendering.py +0 -0
  154. {codeboarding-0.15.3 → codeboarding-0.15.5}/output_generators/sphinx.py +0 -0
  155. {codeboarding-0.15.3 → codeboarding-0.15.5}/setup.cfg +0 -0
  156. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/analysis_result.py +0 -0
  157. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/cfg/__init__.py +0 -0
  158. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/cfg/call_graph.py +0 -0
  159. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/cfg/edge.py +0 -0
  160. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/cfg/location_key.py +0 -0
  161. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/__init__.py +0 -0
  162. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/exceptions.py +0 -0
  163. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/names/__init__.py +0 -0
  164. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/names/draft.py +0 -0
  165. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/names/frontier.py +0 -0
  166. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/names/inventory.py +0 -0
  167. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/names/replay.py +0 -0
  168. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/names/spec.py +0 -0
  169. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/clustering/service.py +0 -0
  170. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/csharp_config_scanner.py +0 -0
  171. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/dotnet_sdk.py +0 -0
  172. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/dotnet_solution.py +0 -0
  173. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/__init__.py +0 -0
  174. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/adapters/csharp_adapter.py +0 -0
  175. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/adapters/go_adapter.py +0 -0
  176. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/adapters/php_adapter.py +0 -0
  177. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/adapters/python_adapter.py +0 -0
  178. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/adapters/typescript_adapter.py +0 -0
  179. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/lsp_constants.py +0 -0
  180. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/lsp_recycler.py +0 -0
  181. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/process_memory.py +0 -0
  182. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/progress.py +0 -0
  183. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/engine/utils.py +0 -0
  184. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/exceptions.py +0 -0
  185. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/external_calls.py +0 -0
  186. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/internal_references.py +0 -0
  187. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/java_utils.py +0 -0
  188. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/language_results.py +0 -0
  189. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/lsp_client/__init__.py +0 -0
  190. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/typescript_config_scanner.py +0 -0
  191. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/typescript_plugin/node_modules/codeboarding-workspace-sources/index.js +0 -0
  192. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/typescript_plugin/node_modules/codeboarding-workspace-sources/package.json +0 -0
  193. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/typescript_workspace.py +0 -0
  194. {codeboarding-0.15.3 → codeboarding-0.15.5}/static_analyzer/workspace_dependencies.py +0 -0
  195. {codeboarding-0.15.3 → codeboarding-0.15.5}/tests/test_devcontainer.py +0 -0
  196. {codeboarding-0.15.3 → codeboarding-0.15.5}/tests/test_persisted_analysis_artifacts.py +0 -0
  197. {codeboarding-0.15.3 → codeboarding-0.15.5}/tests/test_pyproject_packages.py +0 -0
  198. {codeboarding-0.15.3 → codeboarding-0.15.5}/tests/test_view_instructions.py +0 -0
  199. {codeboarding-0.15.3 → codeboarding-0.15.5}/tests/test_windows_compatibility.py +0 -0
  200. {codeboarding-0.15.3 → codeboarding-0.15.5}/tests/test_windows_encoding.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeboarding
3
- Version: 0.15.3
3
+ Version: 0.15.5
4
4
  Summary: Interactive Diagrams for Code
5
5
  Author: CodeBoarding Team
6
6
  License-Expression: MIT
@@ -34,6 +34,7 @@ Requires-Dist: langchain-google-genai>=3.1
34
34
  Requires-Dist: langchain-ollama>=1.0
35
35
  Requires-Dist: langchain-openai>=1.1
36
36
  Requires-Dist: langgraph>=1.0
37
+ Requires-Dist: libclang==18.1.1
37
38
  Requires-Dist: markdown>=3.8
38
39
  Requires-Dist: markdown-it-py>=3.0
39
40
  Requires-Dist: markitdown>=0.1
@@ -49,6 +50,8 @@ Requires-Dist: rich>=12.6
49
50
  Requires-Dist: tqdm>=4.67
50
51
  Requires-Dist: tree-sitter==0.25.2
51
52
  Requires-Dist: tree-sitter-c-sharp==0.23.5
53
+ Requires-Dist: tree-sitter-cpp==0.23.4
54
+ Requires-Dist: tree-sitter-cuda==0.21.2
52
55
  Requires-Dist: tree-sitter-go==0.25.0
53
56
  Requires-Dist: tree-sitter-java==0.23.5
54
57
  Requires-Dist: tree-sitter-javascript==0.25.0
@@ -235,8 +235,9 @@ for the actual depth. Existing baseline loading behavior is unchanged: prefer
235
235
  > `.codeboarding/` only if you want the baseline to travel with the branch (so a teammate or a
236
236
  > fresh checkout can run incremental too). With no baseline at all — or one that predates content
237
237
  > versioning — `incremental` fails fast with "run a full analysis first" rather than silently
238
- > doing a full run. Static-analysis caches are versioned but not migrated; after a cache-version
239
- > upgrade, run a full analysis once to reindex.
238
+ > doing a full run. Static-analysis caches are versioned but not migrated: after a cache-version
239
+ > upgrade, `incremental` logs a warning and runs one full analysis at the baseline's depth, which
240
+ > counts against your LLM provider like any other full run.
240
241
 
241
242
  ## Where to use it
242
243
 
@@ -247,9 +248,10 @@ for the actual depth. Existing baseline loading behavior is unchanged: prefer
247
248
 
248
249
  ## Supported stack
249
250
 
250
- - Languages: Python, TypeScript, JavaScript, Java, Kotlin, Go, PHP, Rust, C#.
251
+ - Languages: Python, TypeScript, JavaScript, Java, Kotlin, Go, PHP, Rust, C#, C++ and CUDA (preview).
251
252
  - Java needs a JDK (21 recommended).
252
- - Kotlin is analysed with JetBrains' [kotlin-lsp](https://github.com/Kotlin/kotlin-lsp) (about 360 MB with its own Java runtime, under the [JetBrains Free Plugin License](https://github.com/Kotlin/kotlin-lsp/blob/main/kotlin-vscode/LICENSE.txt)) and needs glibc 2.34 or newer on Linux. Kotlin calls into Java are not drawn yet.
253
+ - Kotlin is analysed with JetBrains' [kotlin-lsp](https://github.com/Kotlin/kotlin-lsp) (about 360 MB with its own Java runtime, under the [JetBrains Free Plugin License](https://github.com/Kotlin/kotlin-lsp/blob/main/kotlin-vscode/LICENSE.txt)) and needs glibc 2.34 or newer on Linux. JetBrains' builds expire after about 30 days, so a run that needs Kotlin reads the current build number and checksums from this repository, and keeps the build it has when it cannot. Kotlin calls into Java are not drawn yet.
254
+ - C++ and CUDA are analysed with [clangd](https://clangd.llvm.org/), bundled on Linux x86-64, macOS and Windows x64; other platforms need clangd 20 or newer on `PATH`. Provide `compile_commands.json`, `compile_flags.txt` or `.clangd` for full coverage, since CodeBoarding does not build the project. Incremental updates, and so PR reviews, can still miss or keep stale relations for out-of-line class members and header templates.
253
255
  - LLM providers: OpenAI, Anthropic, Google, Vercel AI Gateway, AWS Bedrock, Ollama, OpenRouter, OrcaRouter, Requesty, Opper, LiteLLM proxy, and more.
254
256
 
255
257
  ## Examples
@@ -41,7 +41,11 @@ components this scope sits inside, and a child named after its parent overwrites
41
41
  may inspect a specific in-scope file and `getMethodCalls` may inspect one exact in-scope symbol in one direction.
42
42
  Do not inventory the scope, browse every file, or repeat a tool call. A runtime budget limits all tools to six calls.
43
43
 
44
- Name each editable group for one responsibility using the codebase's own vocabulary, add a concise description,
44
+ Name each editable group for one responsibility in natural English: two to five words separated by spaces that
45
+ tell a reader what the group does, such as "License Validation API" or "Order Checkout Flow". A directory, file,
46
+ package, or symbol name is not a component name: never answer with snake_case, kebab-case, camelCase, or
47
+ PascalCase identifiers, and do not re-case one either ("billing_jobs" and "Billing Jobs" both just repeat
48
+ the directory). Add a concise description,
45
49
  and select only clearly evidenced key entities. Label known directed connections by their architectural meaning.
46
50
  You may add a missing non-static relation such as REST, queue, plugin, registry, file, or configuration wiring only
47
51
  when exact source symbols on both component sides and concrete textual evidence support it. Names alone are not
@@ -57,7 +61,7 @@ Call `ScopeAnalysisResult` with exactly this shape:
57
61
  "components": [
58
62
  {{
59
63
  "group_id": "an exact supplied group_id",
60
- "name": "one responsibility",
64
+ "name": "natural-language name for one responsibility",
61
65
  "description": "one concise sentence",
62
66
  "key_entities": [{{"qualified_name": "exact in-scope symbol"}}]
63
67
  }}
@@ -84,6 +88,12 @@ true, repeat its existing name exactly. Relations may be returned for any pair t
84
88
  relations between two unchanged groups alone. Include one component entry per editable group. Do not invent group
85
89
  IDs, file membership, source symbols, or calls."""
86
90
 
91
+ SCOPE_NAME_RETRY_MESSAGE = """These component names are identifiers or directory and file names, not natural text:
92
+ {names}
93
+
94
+ Call `ScopeAnalysisResult` again with the same content, giving each of these groups a natural-language name of
95
+ two to five words separated by spaces that says what it does. Do not call any other tool."""
96
+
87
97
  STRICT_TREE_PLAN_SYSTEM_SUFFIX = """
88
98
 
89
99
  Follow every constraint literally. Do not explain your reasoning or emit markdown."""
@@ -30,12 +30,14 @@ from infra.monitoring.callbacks import MONITORING_CALLBACK
30
30
  from agents.llm_errors import ScopeContextTooLargeError, raise_if_auth_error
31
31
  from agents.llm_renderers import render_scope_context, scope_file_paths, scope_method_names
32
32
  from agents.prompts import get_scope_analysis_prompts
33
+ from agents.prompts.shared import SCOPE_NAME_RETRY_MESSAGE
33
34
  from agents.retry import LLM_MAX_ATTEMPTS, classify_llm_error, with_retries
34
35
  from agents.tools import MethodCallsTool, ReadFileTool
35
36
  from agents.tools.base import RepoContext
36
37
  from infra.monitoring.mixin import MonitoringMixin
37
38
  from static_analyzer.analysis_result import StaticAnalysisResults
38
39
  from static_analyzer.clustering import ClusterScopeResult
40
+ from static_analyzer.clustering.names.tokens import identifier_path_names, is_natural_name
39
41
 
40
42
  logger = logging.getLogger(__name__)
41
43
 
@@ -249,19 +251,50 @@ class ScopeAnalysisAgent(MonitoringMixin):
249
251
  enclosing_names,
250
252
  max_tokens=max(0, input_budget.max_tokens - prompt_tokens),
251
253
  )
252
- try:
253
- response = agent.invoke(
254
- {"messages": [HumanMessage(content=self.analysis_prompt.format(scope_context=scope_context))]},
255
- config={
256
- "callbacks": [MONITORING_CALLBACK, self.agent_monitoring_callback],
257
- "recursion_limit": SCOPE_RECURSION_LIMIT,
258
- },
259
- )
260
- except Exception as error:
261
- raise_if_auth_error(error)
262
- raise
254
+
255
+ def invoke(messages: list) -> dict:
256
+ try:
257
+ return agent.invoke(
258
+ {"messages": messages},
259
+ config={
260
+ "callbacks": [MONITORING_CALLBACK, self.agent_monitoring_callback],
261
+ "recursion_limit": SCOPE_RECURSION_LIMIT,
262
+ },
263
+ )
264
+ except Exception as error:
265
+ raise_if_auth_error(error)
266
+ raise
267
+
268
+ response = invoke([HumanMessage(content=self.analysis_prompt.format(scope_context=scope_context))])
263
269
  result = response.get("structured_response")
264
270
  if not isinstance(result, ScopeAnalysisResult):
265
271
  logger.warning("Scope %s ended without a structured answer", scope.scope_id)
266
272
  return None
273
+
274
+ # Why a second turn rather than a stricter prompt alone: the same model and prompt name a
275
+ # scope well on one run and answer with its directory names on the next.
276
+ path_names = identifier_path_names(context.scope_files)
277
+ unnatural = {
278
+ component.group_id: component.name
279
+ for component in result.components
280
+ if component.group_id in editable_group_ids
281
+ and component.group_id not in locked_name_ids
282
+ and not is_natural_name(component.name, path_names)
283
+ }
284
+ if not unnatural:
285
+ return result
286
+ logger.info("Scope %s: asking again for natural names instead of %s", scope.scope_id, unnatural)
287
+ names = "\n".join(f"- {group_id}: {name}" for group_id, name in unnatural.items())
288
+ answer = invoke(
289
+ [*response["messages"], HumanMessage(content=SCOPE_NAME_RETRY_MESSAGE.format(names=names))]
290
+ ).get("structured_response")
291
+ renamed = (
292
+ {component.group_id: component.name for component in answer.components}
293
+ if isinstance(answer, ScopeAnalysisResult)
294
+ else {}
295
+ )
296
+ for component in result.components:
297
+ if component.group_id in unnatural:
298
+ name = renamed.get(component.group_id, "")
299
+ component.name = name if is_natural_name(name, path_names) else ""
267
300
  return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeboarding
3
- Version: 0.15.3
3
+ Version: 0.15.5
4
4
  Summary: Interactive Diagrams for Code
5
5
  Author: CodeBoarding Team
6
6
  License-Expression: MIT
@@ -34,6 +34,7 @@ Requires-Dist: langchain-google-genai>=3.1
34
34
  Requires-Dist: langchain-ollama>=1.0
35
35
  Requires-Dist: langchain-openai>=1.1
36
36
  Requires-Dist: langgraph>=1.0
37
+ Requires-Dist: libclang==18.1.1
37
38
  Requires-Dist: markdown>=3.8
38
39
  Requires-Dist: markdown-it-py>=3.0
39
40
  Requires-Dist: markitdown>=0.1
@@ -49,6 +50,8 @@ Requires-Dist: rich>=12.6
49
50
  Requires-Dist: tqdm>=4.67
50
51
  Requires-Dist: tree-sitter==0.25.2
51
52
  Requires-Dist: tree-sitter-c-sharp==0.23.5
53
+ Requires-Dist: tree-sitter-cpp==0.23.4
54
+ Requires-Dist: tree-sitter-cuda==0.21.2
52
55
  Requires-Dist: tree-sitter-go==0.25.0
53
56
  Requires-Dist: tree-sitter-java==0.23.5
54
57
  Requires-Dist: tree-sitter-javascript==0.25.0
@@ -111,6 +111,7 @@ infra/tool_registry/__init__.py
111
111
  infra/tool_registry/grammars.py
112
112
  infra/tool_registry/installers.py
113
113
  infra/tool_registry/java.py
114
+ infra/tool_registry/kotlin-server-1.json
114
115
  infra/tool_registry/manifest.py
115
116
  infra/tool_registry/paths.py
116
117
  infra/tool_registry/registry.py
@@ -159,6 +160,7 @@ static_analyzer/clustering/names/spec.py
159
160
  static_analyzer/clustering/names/tokens.py
160
161
  static_analyzer/engine/__init__.py
161
162
  static_analyzer/engine/call_graph_builder.py
163
+ static_analyzer/engine/cpp_templates.py
162
164
  static_analyzer/engine/edge_build_context.py
163
165
  static_analyzer/engine/edge_builder.py
164
166
  static_analyzer/engine/hierarchy_builder.py
@@ -175,6 +177,7 @@ static_analyzer/engine/source_inspector.py
175
177
  static_analyzer/engine/symbol_table.py
176
178
  static_analyzer/engine/utils.py
177
179
  static_analyzer/engine/adapters/__init__.py
180
+ static_analyzer/engine/adapters/cpp_adapter.py
178
181
  static_analyzer/engine/adapters/csharp_adapter.py
179
182
  static_analyzer/engine/adapters/go_adapter.py
180
183
  static_analyzer/engine/adapters/java_adapter.py
@@ -17,6 +17,7 @@ langchain-google-genai>=3.1
17
17
  langchain-ollama>=1.0
18
18
  langchain-openai>=1.1
19
19
  langgraph>=1.0
20
+ libclang==18.1.1
20
21
  markdown>=3.8
21
22
  markdown-it-py>=3.0
22
23
  markitdown>=0.1
@@ -32,6 +33,8 @@ rich>=12.6
32
33
  tqdm>=4.67
33
34
  tree-sitter==0.25.2
34
35
  tree-sitter-c-sharp==0.23.5
36
+ tree-sitter-cpp==0.23.4
37
+ tree-sitter-cuda==0.21.2
35
38
  tree-sitter-go==0.25.0
36
39
  tree-sitter-java==0.23.5
37
40
  tree-sitter-javascript==0.25.0
@@ -9,7 +9,7 @@ from agents.llm_errors import LLMAuthError, LLMQuotaError
9
9
  from diagram_analysis.exceptions import ScopeSemanticsError
10
10
  from codeboarding_cli.bootstrap import bootstrap_environment, resolve_local_run_paths
11
11
  from codeboarding_cli.view_instructions import print_view_instructions
12
- from codeboarding_workflows.analysis import BaselineUnavailableError, run_incremental
12
+ from codeboarding_workflows.analysis import BaselineUnavailableError, EngineChangedError, run_full, run_incremental
13
13
  from diagram_analysis import RunContext
14
14
  from diagram_analysis.run_mode import RunMode
15
15
  from infra.utils import monitoring_enabled
@@ -48,12 +48,21 @@ def run_from_args(args: argparse.Namespace, parser: argparse.ArgumentParser) ->
48
48
  return
49
49
 
50
50
  run_context = RunContext.resolve(project_name=run_paths.project_name)
51
+ should_monitor = args.enable_monitoring or monitoring_enabled()
52
+ mode = RunMode.INCREMENTAL
51
53
 
52
54
  try:
53
- analysis_path = run_incremental(
55
+ analysis_path = run_incremental(run_paths, run_context, monitoring_enabled=should_monitor)
56
+ except EngineChangedError as exc:
57
+ # Why: an engine release reaches CI unasked, and nobody is there to answer a prompt.
58
+ logger.warning("%s Running a full analysis instead.", exc)
59
+ mode = RunMode.FULL
60
+ analysis_path = run_full(
54
61
  run_paths,
55
62
  run_context,
56
- monitoring_enabled=args.enable_monitoring or monitoring_enabled(),
63
+ depth_cap=exc.depth_cap,
64
+ monitoring_enabled=should_monitor,
65
+ force_full=True,
57
66
  )
58
67
  except BaselineUnavailableError as exc:
59
68
  # Expected: no baseline, or diff failed against the requested base ref.
@@ -61,22 +70,24 @@ def run_from_args(args: argparse.Namespace, parser: argparse.ArgumentParser) ->
61
70
  # to prompt for a full run; no stack trace needed.
62
71
  logger.info("Incremental unavailable: %s", exc)
63
72
  _emit_error(str(exc))
73
+ return
64
74
  except (LLMAuthError, LLMQuotaError, ScopeSemanticsError):
65
75
  # A full run would fail the same way, so don't ask for one.
66
76
  raise
67
77
  except Exception as exc:
68
78
  logger.exception("Incremental analysis failed")
69
79
  _emit_error(str(exc))
70
- else:
71
- _emit(
72
- {
73
- "mode": RunMode.INCREMENTAL,
74
- "requiresFullAnalysis": False,
75
- "analysis_path": str(analysis_path),
76
- }
77
- )
78
- # Human-facing hint (logs to stderr, so the stdout JSON contract stays clean).
79
- print_view_instructions(analysis_path)
80
+ return
81
+
82
+ _emit(
83
+ {
84
+ "mode": mode,
85
+ "requiresFullAnalysis": False,
86
+ "analysis_path": str(analysis_path),
87
+ }
88
+ )
89
+ # Human-facing hint (logs to stderr, so the stdout JSON contract stays clean).
90
+ print_view_instructions(analysis_path)
80
91
 
81
92
 
82
93
  def _emit_error(message: str) -> None:
@@ -25,12 +25,24 @@ from diagram_analysis.io_utils import (
25
25
  )
26
26
  from diagram_analysis.run_context import DEFAULT_DEPTH_CAP, RunContext, RunPaths
27
27
  from infra.repo_utils.change_detector import ChangeSet
28
- from codeboarding_workflows.fingerprint_diff import BaselineUnavailableError, detect_changes_from_fingerprint
28
+ from codeboarding_workflows.fingerprint_diff import (
29
+ BaselineUnavailableError,
30
+ EngineChangedError,
31
+ detect_changes_from_fingerprint,
32
+ )
29
33
  from infra.monitoring.telemetry.events import track_analysis
34
+ from static_analyzer.analysis_cache import StaticAnalysisCache
30
35
 
31
36
  logger = logging.getLogger(__name__)
32
37
 
33
- __all__ = ["BaselineUnavailableError", "run_full", "run_partial", "run_incremental", "run_incremental_workflow"]
38
+ __all__ = [
39
+ "BaselineUnavailableError",
40
+ "EngineChangedError",
41
+ "run_full",
42
+ "run_partial",
43
+ "run_incremental",
44
+ "run_incremental_workflow",
45
+ ]
34
46
 
35
47
 
36
48
  def build_generator(
@@ -196,7 +208,8 @@ def run_incremental(
196
208
  passes a changed-file set or git refs — the CLI and the wrapper both just say
197
209
  "update this directory". The source-tree hash doubles as the warm-start tag.
198
210
 
199
- Raises ``BaselineUnavailableError`` when no baseline analysis exists — callers
211
+ Raises ``BaselineUnavailableError`` when no baseline analysis exists, and its
212
+ subclass ``EngineChangedError`` when another engine version wrote it — callers
200
213
  should surface a "run full analysis" prompt rather than silently degrading to
201
214
  an unscoped run.
202
215
  """
@@ -208,6 +221,10 @@ def run_incremental(
208
221
  )
209
222
  depth_cap = int(metadata.get("depth_cap", metadata.get("depth_level", DEFAULT_DEPTH_CAP)))
210
223
 
224
+ # Why here: the analyzer refuses this pkl too, but only after servers started and a failed run was reported.
225
+ if StaticAnalysisCache(run_paths.output_dir, run_paths.repo_path).from_another_engine():
226
+ raise EngineChangedError(run_paths.output_dir, depth_cap)
227
+
211
228
  changes = detect_changes_from_fingerprint(run_paths.repo_path, run_paths.output_dir)
212
229
  logger.info(
213
230
  f"Running INCREMENTAL analysis workflow for project '{run_paths.project_name}' "
@@ -11,6 +11,7 @@ from pathlib import Path
11
11
 
12
12
  from agents.content_hash import hash_repo_source_files
13
13
  from diagram_analysis.io_utils import read_fingerprint
14
+ from infra.constants import STATIC_ANALYSIS_PKL
14
15
  from infra.repo_utils.change_detector import ChangeSet
15
16
 
16
17
  logger = logging.getLogger(__name__)
@@ -31,6 +32,20 @@ class BaselineUnavailableError(RuntimeError):
31
32
  """
32
33
 
33
34
 
35
+ class EngineChangedError(BaselineUnavailableError):
36
+ """Raised when the baseline's static analysis came from an engine version this build cannot read.
37
+
38
+ Carries the baseline's depth cap, so a caller that recovers rebuilds at the same depth.
39
+ """
40
+
41
+ def __init__(self, output_dir: Path, depth_cap: int):
42
+ super().__init__(
43
+ f"{output_dir / STATIC_ANALYSIS_PKL} was written by a different engine version "
44
+ "and cannot be reused for an incremental run."
45
+ )
46
+ self.depth_cap = depth_cap
47
+
48
+
34
49
  def diff_file_maps(old: FileHashMap, new: FileHashMap) -> tuple[list[str], list[str], list[str]]:
35
50
  """Return ``(added, modified, deleted)`` repo-relative paths between two maps.
36
51
 
@@ -528,7 +528,10 @@ def parse_unified_analysis(
528
528
  root_analysis.files = {path: FileEntry().merge_from(entry) for path, entry in files_index.items()}
529
529
  _hydrate_component_methods_from_refs(root_analysis, methods_index)
530
530
  for sub in sub_analyses.values():
531
- sub.files = {path: FileEntry().merge_from(entry) for path, entry in files_index.items()}
531
+ # Same shape a live scope gets from ``build_files_index``: only the files its components
532
+ # own. The root carries the whole index, so a save loses nothing.
533
+ owned = {group.file_path for component in sub.components for group in component.file_methods}
534
+ sub.files = {path: FileEntry().merge_from(entry) for path, entry in files_index.items() if path in owned}
532
535
  _hydrate_component_methods_from_refs(sub, methods_index)
533
536
 
534
537
  return root_analysis, sub_analyses
@@ -84,6 +84,7 @@ from static_analyzer.clustering import (
84
84
  from static_analyzer.clustering.exceptions import IncrementalCacheMissingError, PlannerUnavailableError
85
85
  from static_analyzer.clustering.names import AffinityGrouper, Grouper, KinshipGrouper, TreeSpec
86
86
  from static_analyzer.clustering.names.spec import SPEC_VERSION
87
+ from static_analyzer.clustering.names.tokens import is_natural_name
87
88
  from static_analyzer.clustering.service import ClusteringService, hierarchy_differs
88
89
  from agents.tree_planner_agent import TreePlannerAgent
89
90
  from infra.user_config import GROUPER_ENV, GROUPERS
@@ -893,10 +894,16 @@ class DiagramGenerator:
893
894
  analysis = root_analysis if scope.scope_id == ROOT_SCOPE_ID else sub_analyses.get(scope.scope_id)
894
895
  if analysis is None:
895
896
  continue
897
+ # A baseline name that is a directory or an identifier is renamed even when nothing
898
+ # changed: locked or carried forward, it would ship on every later run.
899
+ unnatural_ids = {
900
+ component.component_id for component in analysis.components if not is_natural_name(component.name)
901
+ }
896
902
  editable_ids = {
897
903
  group.group_id
898
904
  for group in scope.groups
899
905
  if group.group_id in refreshed_ids
906
+ or group.group_id in unnatural_ids
900
907
  or bool(self._group_files(group, scope) & changed_files)
901
908
  or bool(group.qualified_names & self._changed_members)
902
909
  }
@@ -906,6 +913,7 @@ class DiagramGenerator:
906
913
  group.group_id
907
914
  for group in scope.groups
908
915
  if group.group_id in editable_ids
916
+ and group.group_id not in unnatural_ids
909
917
  and group.group_id in baseline_membership.meta_by_id
910
918
  and self._group_member_keys(group, scope) == baseline_membership.meta_by_id[group.group_id].member_keys
911
919
  )
@@ -24,6 +24,7 @@ from static_analyzer import StaticAnalysisFatalError
24
24
  from static_analyzer.cfg import Edge
25
25
  from infra.repo_utils.path_utils import normalize_repo_path
26
26
  from static_analyzer.clustering import ClusterGroup, ClusterScopeResult, GroupConnection
27
+ from static_analyzer.clustering.names.tokens import is_natural_name
27
28
  from diagram_analysis.reference_resolver import StaticReferenceResolver
28
29
 
29
30
  logger = logging.getLogger(__name__)
@@ -119,10 +120,26 @@ class ScopeAssembler:
119
120
  for group_id in ordered_ids
120
121
  if group_id in semantics_by_id
121
122
  and group_id not in locked_name_ids
122
- and semantics_by_id[group_id].name.strip()
123
+ and is_natural_name(semantics_by_id[group_id].name.strip())
124
+ }
125
+ # A directory or identifier name is not kept just because the model gave no better one:
126
+ # it is replaced by the rule name written as words.
127
+ fallbacks = {
128
+ group_id
129
+ for group_id in ordered_ids
130
+ if group_id not in proposals
131
+ and group_id not in locked_name_ids
132
+ and group_id in components
133
+ and not is_natural_name(components[group_id].name)
134
+ }
135
+ taken = {
136
+ component.name
137
+ for group_id, component in components.items()
138
+ if group_id not in proposals and group_id not in fallbacks
123
139
  }
124
- taken = {component.name for group_id, component in components.items() if group_id not in proposals}
125
140
  taken.update(reserved_names)
141
+ for group_id in fallbacks:
142
+ components[group_id].name = groups_by_id[group_id].unique_name(taken)
126
143
  named: set[str] = set()
127
144
  for group_id in ordered_ids:
128
145
  component = components.get(group_id)