codeboarding 0.14.2__tar.gz → 0.14.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 (206) hide show
  1. {codeboarding-0.14.2/codeboarding.egg-info → codeboarding-0.14.5}/PKG-INFO +1 -1
  2. codeboarding-0.14.5/README.md +282 -0
  3. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/llm_config.py +24 -0
  4. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/llm_errors.py +66 -9
  5. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/llm_renderers/scope.py +80 -7
  6. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/prompts/shared.py +4 -1
  7. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/scope_analysis_agent.py +88 -6
  8. {codeboarding-0.14.2 → codeboarding-0.14.5/codeboarding.egg-info}/PKG-INFO +1 -1
  9. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding.egg-info/SOURCES.txt +4 -1
  10. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_cli/commands/full_analysis.py +7 -2
  11. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_cli/commands/incremental_analysis.py +5 -0
  12. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_workflows/analysis.py +34 -16
  13. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/diagram_generator.py +36 -15
  14. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/exceptions.py +12 -0
  15. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/incremental_update.py +14 -1
  16. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/io_utils.py +16 -0
  17. {codeboarding-0.14.2 → codeboarding-0.14.5}/main.py +17 -5
  18. {codeboarding-0.14.2 → codeboarding-0.14.5}/pyproject.toml +1 -1
  19. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/__init__.py +132 -46
  20. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/analysis_cache.py +6 -1
  21. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/clustering/names/__init__.py +1 -6
  22. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/clustering/names/draft.py +334 -145
  23. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/clustering/names/frontier.py +18 -48
  24. codeboarding-0.14.5/static_analyzer/clustering/names/inventory.py +139 -0
  25. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/clustering/names/replay.py +4 -5
  26. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/clustering/names/spec.py +3 -13
  27. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/clustering/names/tokens.py +0 -6
  28. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/clustering/service.py +20 -13
  29. codeboarding-0.14.5/static_analyzer/dotnet_solution.py +62 -0
  30. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/adapters/csharp_adapter.py +108 -46
  31. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/adapters/go_adapter.py +6 -13
  32. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/adapters/java_adapter.py +9 -21
  33. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/adapters/php_adapter.py +0 -10
  34. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/adapters/rust_adapter.py +0 -6
  35. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/adapters/typescript_adapter.py +6 -0
  36. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/call_graph_builder.py +69 -61
  37. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/edge_build_context.py +5 -5
  38. codeboarding-0.14.5/static_analyzer/engine/edge_builder.py +612 -0
  39. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/language_adapter.py +32 -41
  40. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/lsp_client.py +153 -123
  41. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/lsp_constants.py +11 -15
  42. codeboarding-0.14.5/static_analyzer/engine/lsp_recycler.py +46 -0
  43. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/models.py +25 -0
  44. codeboarding-0.14.5/static_analyzer/engine/progress.py +59 -0
  45. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/protocols.py +0 -9
  46. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/result_converter.py +8 -3
  47. codeboarding-0.14.5/static_analyzer/engine/source_inspector.py +1285 -0
  48. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/symbol_table.py +75 -78
  49. codeboarding-0.14.5/static_analyzer/exceptions.py +5 -0
  50. codeboarding-0.14.5/static_analyzer/external_calls.py +142 -0
  51. codeboarding-0.14.5/static_analyzer/graph_definitions.py +369 -0
  52. codeboarding-0.14.5/static_analyzer/incremental_orchestrator.py +284 -0
  53. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/internal_references.py +5 -0
  54. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_main.py +68 -1
  55. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_telemetry_service.py +11 -0
  56. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_user_config.py +14 -0
  57. {codeboarding-0.14.2 → codeboarding-0.14.5}/user_config.py +4 -0
  58. codeboarding-0.14.2/README.md +0 -235
  59. codeboarding-0.14.2/health_main.py +0 -152
  60. codeboarding-0.14.2/static_analyzer/clustering/names/inventory.py +0 -116
  61. codeboarding-0.14.2/static_analyzer/engine/edge_builder.py +0 -794
  62. codeboarding-0.14.2/static_analyzer/engine/lsp_recycler.py +0 -158
  63. codeboarding-0.14.2/static_analyzer/engine/progress.py +0 -83
  64. codeboarding-0.14.2/static_analyzer/engine/source_inspector.py +0 -765
  65. codeboarding-0.14.2/static_analyzer/incremental_orchestrator.py +0 -632
  66. {codeboarding-0.14.2 → codeboarding-0.14.5}/LICENSE +0 -0
  67. {codeboarding-0.14.2 → codeboarding-0.14.5}/PYPI.md +0 -0
  68. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/__init__.py +0 -0
  69. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/agent_responses.py +0 -0
  70. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/change_status.py +0 -0
  71. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/component_ownership.py +0 -0
  72. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/constants.py +0 -0
  73. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/content_hash.py +0 -0
  74. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/file_index_models.py +0 -0
  75. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/incremental_results.py +0 -0
  76. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/llm_renderers/__init__.py +0 -0
  77. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/llm_renderers/call_graph.py +0 -0
  78. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/model_capabilities.py +0 -0
  79. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/planner_agent.py +0 -0
  80. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/prompts/__init__.py +0 -0
  81. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/prompts/profiles.py +0 -0
  82. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/relation_edges.py +0 -0
  83. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/retry.py +0 -0
  84. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/scope_ids.py +0 -0
  85. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/tools/__init__.py +0 -0
  86. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/tools/base.py +0 -0
  87. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/tools/get_method_calls.py +0 -0
  88. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/tools/read_file.py +0 -0
  89. {codeboarding-0.14.2 → codeboarding-0.14.5}/agents/tree_planner_agent.py +0 -0
  90. {codeboarding-0.14.2 → codeboarding-0.14.5}/clustering_ids.py +0 -0
  91. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding.egg-info/dependency_links.txt +0 -0
  92. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding.egg-info/entry_points.txt +0 -0
  93. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding.egg-info/requires.txt +0 -0
  94. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding.egg-info/top_level.txt +0 -0
  95. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_cli/__init__.py +0 -0
  96. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_cli/bootstrap.py +0 -0
  97. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_cli/commands/__init__.py +0 -0
  98. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_cli/commands/partial_analysis.py +0 -0
  99. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_cli/render.py +0 -0
  100. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_cli/view_instructions.py +0 -0
  101. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_workflows/__init__.py +0 -0
  102. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_workflows/orchestration.py +0 -0
  103. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_workflows/sources/__init__.py +0 -0
  104. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_workflows/sources/local.py +0 -0
  105. {codeboarding-0.14.2 → codeboarding-0.14.5}/codeboarding_workflows/sources/remote.py +0 -0
  106. {codeboarding-0.14.2 → codeboarding-0.14.5}/constants.py +0 -0
  107. {codeboarding-0.14.2 → codeboarding-0.14.5}/core/__init__.py +0 -0
  108. {codeboarding-0.14.2 → codeboarding-0.14.5}/core/plugin_loader.py +0 -0
  109. {codeboarding-0.14.2 → codeboarding-0.14.5}/core/protocols.py +0 -0
  110. {codeboarding-0.14.2 → codeboarding-0.14.5}/core/registry.py +0 -0
  111. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/__init__.py +0 -0
  112. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/analysis_json.py +0 -0
  113. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/file_coverage.py +0 -0
  114. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/file_index.py +0 -0
  115. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/incremental_changes.py +0 -0
  116. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/run_context.py +0 -0
  117. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/run_mode.py +0 -0
  118. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/scope_assembly.py +0 -0
  119. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/scope_plan.py +0 -0
  120. {codeboarding-0.14.2 → codeboarding-0.14.5}/diagram_analysis/tree_shape.py +0 -0
  121. {codeboarding-0.14.2 → codeboarding-0.14.5}/github_action.py +0 -0
  122. {codeboarding-0.14.2 → codeboarding-0.14.5}/health/__init__.py +0 -0
  123. {codeboarding-0.14.2 → codeboarding-0.14.5}/health/checks/__init__.py +0 -0
  124. {codeboarding-0.14.2 → codeboarding-0.14.5}/health/checks/circular_deps.py +0 -0
  125. {codeboarding-0.14.2 → codeboarding-0.14.5}/health/checks/function_size.py +0 -0
  126. {codeboarding-0.14.2 → codeboarding-0.14.5}/health/checks/unused_code_diagnostics.py +0 -0
  127. {codeboarding-0.14.2 → codeboarding-0.14.5}/health/config.py +0 -0
  128. {codeboarding-0.14.2 → codeboarding-0.14.5}/health/models.py +0 -0
  129. {codeboarding-0.14.2 → codeboarding-0.14.5}/health/runner.py +0 -0
  130. {codeboarding-0.14.2 → codeboarding-0.14.5}/install.py +0 -0
  131. {codeboarding-0.14.2 → codeboarding-0.14.5}/logging_config.py +0 -0
  132. {codeboarding-0.14.2 → codeboarding-0.14.5}/monitoring/__init__.py +0 -0
  133. {codeboarding-0.14.2 → codeboarding-0.14.5}/monitoring/callbacks.py +0 -0
  134. {codeboarding-0.14.2 → codeboarding-0.14.5}/monitoring/context.py +0 -0
  135. {codeboarding-0.14.2 → codeboarding-0.14.5}/monitoring/mixin.py +0 -0
  136. {codeboarding-0.14.2 → codeboarding-0.14.5}/monitoring/paths.py +0 -0
  137. {codeboarding-0.14.2 → codeboarding-0.14.5}/monitoring/stats.py +0 -0
  138. {codeboarding-0.14.2 → codeboarding-0.14.5}/monitoring/writers.py +0 -0
  139. {codeboarding-0.14.2 → codeboarding-0.14.5}/output_generators/__init__.py +0 -0
  140. {codeboarding-0.14.2 → codeboarding-0.14.5}/output_generators/html.py +0 -0
  141. {codeboarding-0.14.2 → codeboarding-0.14.5}/output_generators/html_template.py +0 -0
  142. {codeboarding-0.14.2 → codeboarding-0.14.5}/output_generators/markdown.py +0 -0
  143. {codeboarding-0.14.2 → codeboarding-0.14.5}/output_generators/mdx.py +0 -0
  144. {codeboarding-0.14.2 → codeboarding-0.14.5}/output_generators/rendering.py +0 -0
  145. {codeboarding-0.14.2 → codeboarding-0.14.5}/output_generators/sphinx.py +0 -0
  146. {codeboarding-0.14.2 → codeboarding-0.14.5}/repo_utils/__init__.py +0 -0
  147. {codeboarding-0.14.2 → codeboarding-0.14.5}/repo_utils/change_detector.py +0 -0
  148. {codeboarding-0.14.2 → codeboarding-0.14.5}/repo_utils/errors.py +0 -0
  149. {codeboarding-0.14.2 → codeboarding-0.14.5}/repo_utils/fingerprint_diff.py +0 -0
  150. {codeboarding-0.14.2 → codeboarding-0.14.5}/repo_utils/git_ops.py +0 -0
  151. {codeboarding-0.14.2 → codeboarding-0.14.5}/repo_utils/ignore.py +0 -0
  152. {codeboarding-0.14.2 → codeboarding-0.14.5}/repo_utils/path_utils.py +0 -0
  153. {codeboarding-0.14.2 → codeboarding-0.14.5}/setup.cfg +0 -0
  154. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/analysis_result.py +0 -0
  155. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/cfg/__init__.py +0 -0
  156. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/cfg/call_graph.py +0 -0
  157. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/cfg/edge.py +0 -0
  158. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/cfg/location_key.py +0 -0
  159. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/cluster_relations.py +0 -0
  160. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/clustering/__init__.py +0 -0
  161. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/clustering/exceptions.py +0 -0
  162. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/clustering/models.py +0 -0
  163. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/config.py +0 -0
  164. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/csharp_config_scanner.py +0 -0
  165. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/dotnet_sdk.py +0 -0
  166. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/__init__.py +0 -0
  167. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/adapters/__init__.py +0 -0
  168. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/adapters/python_adapter.py +0 -0
  169. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/hierarchy_builder.py +0 -0
  170. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/process_memory.py +0 -0
  171. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/engine/utils.py +0 -0
  172. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/java_config_scanner.py +0 -0
  173. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/java_utils.py +0 -0
  174. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/language_results.py +0 -0
  175. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/lsp_client/__init__.py +0 -0
  176. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/lsp_client/diagnostics.py +0 -0
  177. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/node.py +0 -0
  178. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/programming_language.py +0 -0
  179. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/reference_resolver.py +0 -0
  180. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/scanner.py +0 -0
  181. {codeboarding-0.14.2 → codeboarding-0.14.5}/static_analyzer/typescript_config_scanner.py +0 -0
  182. {codeboarding-0.14.2 → codeboarding-0.14.5}/telemetry/__init__.py +0 -0
  183. {codeboarding-0.14.2 → codeboarding-0.14.5}/telemetry/device_id.py +0 -0
  184. {codeboarding-0.14.2 → codeboarding-0.14.5}/telemetry/events.py +0 -0
  185. {codeboarding-0.14.2 → codeboarding-0.14.5}/telemetry/schemas.py +0 -0
  186. {codeboarding-0.14.2 → codeboarding-0.14.5}/telemetry/service.py +0 -0
  187. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_cli_parser.py +0 -0
  188. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_github_action.py +0 -0
  189. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_install.py +0 -0
  190. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_logging_config.py +0 -0
  191. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_persisted_analysis_artifacts.py +0 -0
  192. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_pyproject_packages.py +0 -0
  193. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_registry_coverage.py +0 -0
  194. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_telemetry_events.py +0 -0
  195. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_tool_registry.py +0 -0
  196. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_view_instructions.py +0 -0
  197. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_vscode_constants.py +0 -0
  198. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_windows_compatibility.py +0 -0
  199. {codeboarding-0.14.2 → codeboarding-0.14.5}/tests/test_windows_encoding.py +0 -0
  200. {codeboarding-0.14.2 → codeboarding-0.14.5}/tool_registry/__init__.py +0 -0
  201. {codeboarding-0.14.2 → codeboarding-0.14.5}/tool_registry/installers.py +0 -0
  202. {codeboarding-0.14.2 → codeboarding-0.14.5}/tool_registry/manifest.py +0 -0
  203. {codeboarding-0.14.2 → codeboarding-0.14.5}/tool_registry/paths.py +0 -0
  204. {codeboarding-0.14.2 → codeboarding-0.14.5}/tool_registry/registry.py +0 -0
  205. {codeboarding-0.14.2 → codeboarding-0.14.5}/utils.py +0 -0
  206. {codeboarding-0.14.2 → codeboarding-0.14.5}/vscode_constants.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeboarding
3
- Version: 0.14.2
3
+ Version: 0.14.5
4
4
  Summary: Interactive Diagrams for Code
5
5
  Author: CodeBoarding Team
6
6
  License-Expression: MIT
@@ -0,0 +1,282 @@
1
+ # CodeBoarding
2
+
3
+ **Review the change, not the diff.**
4
+
5
+ See what a pull request does to your system before you merge it. CodeBoarding turns code into interactive architecture maps so you can explore components, follow their dependencies, and review analyzed pull requests alongside code diffs.
6
+
7
+ This repository contains the open-source analysis engine and CLI. Static analysis extracts code relationships; language models help name and describe the components. Use the resulting map in the web platform, your editor, CI, or generated documentation.
8
+
9
+ [Discord](https://discord.gg/T5zHTJYFuy) · [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Codeboarding.codeboarding) <img alt="" referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=8a3d26e0-6f6b-49c0-8482-114445de56a5" width="0" height="0" /> · [Open VSX extension](https://open-vsx.org/extension/CodeBoarding/codeboarding) <img alt="" referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=ce87464c-2792-46b0-9ea2-87eefe853d7e" width="0" height="0" /> · [Web platform](https://app.codeboarding.org) · [Website](https://codeboarding.org) <img alt="" referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=0855d476-b2d0-44cc-b93d-69b47504719c" width="0" height="0" /> · [Getting started](https://codeboarding.org/getting-started)
10
+
11
+ [![Website animation: a pull-request diff becomes a six-component system map, revealing a new dependency from Payments to Identity.](docs/images/codeboarding-story.gif)](https://codeboarding.org)
12
+
13
+ *The website's illustrative animation (plays once, about 18 seconds). [View the static map](docs/images/codeboarding-story-static.png) or [replay the interactive story on the website](https://codeboarding.org).*
14
+
15
+ The example starts with a large pull-request diff, then shows the six components it touches. Identity and Payments have changed: a new dependency means a Google sign-in outage can block card payments.
16
+
17
+ [![JavaScript](https://img.shields.io/badge/JavaScript-222222?style=flat-square&logo=javascript&logoColor=F7DF1E)](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
18
+ [![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
19
+ [![Java](https://img.shields.io/badge/Java-E76F00?style=flat-square&logo=openjdk&logoColor=white)](https://www.java.com/)
20
+ [![Python](https://img.shields.io/badge/Python-3776AB?style=flat-square&logo=python&logoColor=white)](https://www.python.org/)
21
+ [![Go](https://img.shields.io/badge/Go-00ADD8?style=flat-square&logo=go&logoColor=white)](https://go.dev/)
22
+ [![PHP](https://img.shields.io/badge/PHP-777BB4?style=flat-square&logo=php&logoColor=white)](https://www.php.net/)
23
+ [![Rust](https://img.shields.io/badge/Rust-000000?style=flat-square&logo=rust&logoColor=white)](https://www.rust-lang.org/)
24
+ [![C#](https://custom-icon-badges.demolab.com/badge/C%23-512BD4.svg?style=flat-square&logo=cshrp&logoColor=white)](https://learn.microsoft.com/en-us/dotnet/csharp/)
25
+
26
+ ## Explore the system. Review the change
27
+
28
+ - **Explore:** start with the architecture map, expand components, and navigate to the source behind them. Open prepared public repositories without signing in.
29
+ - **Review:** see changed components and dependencies, read changes grouped by component, and inspect code diffs. PR review requires an available analysis from the GitHub Action; architecture comparisons also need a baseline.
30
+ - **Bring your own analysis:** open an `analysis.json` or compare two local analysis files. Files are parsed and compared in your browser.
31
+ - **Share context:** use component descriptions and diagrams in documentation, reviews, and your coding agent's next prompt.
32
+
33
+ ## What CodeBoarding generates
34
+
35
+ - An `analysis.json` containing the architecture, component descriptions, relationships, and source references.
36
+ - Nested component diagrams for exploring subsystems.
37
+ - Markdown with Mermaid diagrams, HTML, MDX, or reStructuredText documentation when you request rendering.
38
+ - Incremental updates against a previous analysis, or updates to a selected component.
39
+
40
+ ## How it works
41
+
42
+ 1. **Analyze the code.** The engine scans the repository and extracts symbols and relationships with static analysis.
43
+ 2. **Build the map.** It groups code into components and uses your configured model provider to describe their responsibilities. Analysis can send code excerpts to that provider.
44
+ 3. **Explore or review.** Load the analysis in the web platform or editor, render it as documentation, or use the GitHub Action to publish architecture changes on pull requests.
45
+
46
+ The engine's top-level architecture, generated from the [committed analysis](https://github.com/CodeBoarding/CodeBoarding/blob/58291a48b2a609f68e0d19dccd0f3a605907ed28/.codeboarding/analysis.json) dated September 21, 2026:
47
+
48
+ ```mermaid
49
+ graph LR
50
+ Static_Analysis_Engine["Static Analysis Engine"]
51
+ Diagram_Generation_and_Health_Orchestration["Diagram Generation and Health Orchestration"]
52
+ LLM_Planning_and_Analysis_Agents["LLM Planning and Analysis Agents"]
53
+ CLI_Workflows_and_Output_Generators["CLI, Workflows, and Output Generators"]
54
+ Repository_and_File_Utilities["Repository and File Utilities"]
55
+ Application_Entry_Points_and_Runtime_Configuration["Application Entry Points and Runtime Configuration"]
56
+ Execution_Monitoring_and_Metrics["Execution Monitoring and Metrics"]
57
+ Tool_Registry_and_Environment_Installer["Tool Registry and Environment Installer"]
58
+ Static_Analysis_Engine -- "tracks telemetry events" --> Diagram_Generation_and_Health_Orchestration
59
+ Static_Analysis_Engine -- "checks repository ignores and git changes" --> Repository_and_File_Utilities
60
+ Static_Analysis_Engine -- "locates tool binaries and runtime directories" --> Tool_Registry_and_Environment_Installer
61
+ Static_Analysis_Engine -- "builds agent insight models" --> LLM_Planning_and_Analysis_Agents
62
+ Static_Analysis_Engine -- "formats cluster identifiers" --> Application_Entry_Points_and_Runtime_Configuration
63
+ Diagram_Generation_and_Health_Orchestration -- "queries static analysis graphs and specs" --> Static_Analysis_Engine
64
+ Diagram_Generation_and_Health_Orchestration -- "configures LLMs and models file index entries" --> LLM_Planning_and_Analysis_Agents
65
+ Diagram_Generation_and_Health_Orchestration -- "normalizes paths and checks git changes" --> Repository_and_File_Utilities
66
+ Diagram_Generation_and_Health_Orchestration -- "resolves cluster hierarchy and ordering" --> Application_Entry_Points_and_Runtime_Configuration
67
+ Diagram_Generation_and_Health_Orchestration -- "initializes stats writers and logs runs" --> Execution_Monitoring_and_Metrics
68
+ Diagram_Generation_and_Health_Orchestration -- "executes plugin health checks" --> CLI_Workflows_and_Output_Generators
69
+ LLM_Planning_and_Analysis_Agents -- "reads call graph edges and nodes" --> Static_Analysis_Engine
70
+ LLM_Planning_and_Analysis_Agents -- "filters repository files and normalizes paths" --> Repository_and_File_Utilities
71
+ LLM_Planning_and_Analysis_Agents -- "checks cluster hierarchy and loads user configuration" --> Application_Entry_Points_and_Runtime_Configuration
72
+ LLM_Planning_and_Analysis_Agents -- "attaches monitoring callbacks and mixins" --> Execution_Monitoring_and_Metrics
73
+ CLI_Workflows_and_Output_Generators -- "resolves execution context and loads analysis metadata" --> Diagram_Generation_and_Health_Orchestration
74
+ CLI_Workflows_and_Output_Generators -- "initializes LLM credentials and computes source hashes" --> LLM_Planning_and_Analysis_Agents
75
+ CLI_Workflows_and_Output_Generators -- "manages ignore files and repository git operations" --> Repository_and_File_Utilities
76
+ CLI_Workflows_and_Output_Generators -- "loads user configuration and sets up logging" --> Application_Entry_Points_and_Runtime_Configuration
77
+ CLI_Workflows_and_Output_Generators -- "wraps workflow execution in monitoring context" --> Execution_Monitoring_and_Metrics
78
+ CLI_Workflows_and_Output_Generators -- "ensures required tool binaries are installed" --> Tool_Registry_and_Environment_Installer
79
+ CLI_Workflows_and_Output_Generators -- "retrieves node type definitions for output rendering" --> Static_Analysis_Engine
80
+ Repository_and_File_Utilities -- "builds tool configurations from manifest" --> Tool_Registry_and_Environment_Installer
81
+ Repository_and_File_Utilities -- "reads fingerprint data for change detection" --> Diagram_Generation_and_Health_Orchestration
82
+ Repository_and_File_Utilities -- "hashes repository source files for fingerprint comparison" --> LLM_Planning_and_Analysis_Agents
83
+ Application_Entry_Points_and_Runtime_Configuration -- "loads analysis metadata and resolves run context" --> Diagram_Generation_and_Health_Orchestration
84
+ Application_Entry_Points_and_Runtime_Configuration -- "triggers incremental analysis and renders documentation formats" --> CLI_Workflows_and_Output_Generators
85
+ Application_Entry_Points_and_Runtime_Configuration -- "clones and checks out repositories in temporary folders" --> Repository_and_File_Utilities
86
+ Execution_Monitoring_and_Metrics -- "resolves project root directory for monitoring storage" --> Repository_and_File_Utilities
87
+ Tool_Registry_and_Environment_Installer -- "inspects language definitions and runtime environments" --> Static_Analysis_Engine
88
+ Tool_Registry_and_Environment_Installer -- "locates executable runnables and initializes configuration templates" --> Application_Entry_Points_and_Runtime_Configuration
89
+ ```
90
+
91
+ For the engine's own architecture, [open its interactive map](https://app.codeboarding.org/CodeBoarding/CodeBoarding).
92
+
93
+ ## Quick start
94
+
95
+ To try the product without installing anything, [open a public map](https://app.codeboarding.org/CodeBoarding/CodeBoarding). To connect your own repositories, [sign in to the web platform](https://app.codeboarding.org) and choose which repositories CodeBoarding can access. See the [getting-started guide](https://codeboarding.org/getting-started) for the GitHub and editor workflows.
96
+
97
+ To run the analysis engine yourself, use either option below. Both require **Python 3.12** and a [configured model provider](#configuration).
98
+
99
+ ### Run from source
100
+
101
+ ```bash
102
+ git clone https://github.com/CodeBoarding/CodeBoarding.git
103
+ cd CodeBoarding
104
+ uv sync --frozen
105
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
106
+ python install.py
107
+ python main.py full --local /path/to/repo
108
+ ```
109
+
110
+ ### Use the packaged CLI
111
+
112
+ The recommended install method is [pipx](https://pipx.pypa.io), which keeps the CLI in its own isolated environment:
113
+
114
+ ```bash
115
+ pipx install codeboarding --python python3.12
116
+ codeboarding-setup
117
+ codeboarding full --local /path/to/repo
118
+ ```
119
+
120
+ Or, if you prefer pip, install into a virtual environment (not the global Python):
121
+
122
+ ```bash
123
+ pip install codeboarding --extra-index-url https://pip.codeboarding.org/simple/
124
+ codeboarding-setup
125
+ codeboarding full --local /path/to/repo
126
+ ```
127
+
128
+ Output is written to `/path/to/repo/.codeboarding/`. To explore it interactively, open the
129
+ [web platform](https://app.codeboarding.org) and load the generated `analysis.json` through
130
+ the viewer's **Switch source** → **File** picker.
131
+ Local analysis files are parsed and compared in your browser; this is separate from generating
132
+ the analysis with your configured model provider.
133
+
134
+ To also generate `overview` and one file per expanded component, pass `--render` with one of
135
+ `md`, `html`, `mdx`, or `rst`. Rendering is available after full, incremental, and partial local analyses;
136
+ previously generated files for the selected format are reconciled from a renderer-owned manifest:
137
+
138
+ ```bash
139
+ codeboarding full --local /path/to/repo --render md
140
+ codeboarding incremental --local /path/to/repo --render html
141
+ codeboarding partial --local /path/to/repo --component-id "1.2" --render rst
142
+ ```
143
+
144
+ You can render an existing analysis without rerunning analysis or configuring an LLM:
145
+
146
+ ```bash
147
+ codeboarding-render /path/to/repo/.codeboarding/analysis.json
148
+ # Select a format or output directory:
149
+ codeboarding-render /path/to/analysis.json --format mdx --output-dir /path/to/docs
150
+
151
+ # From a source checkout in development:
152
+ python codeboarding_cli/render.py ../../demo/markitdown/.codeboarding/analysis.json --format md
153
+ ```
154
+
155
+ `python install.py` and `codeboarding-setup` download language server binaries to `~/.codeboarding/servers/`, shared across projects. Node.js (and its bundled `npm`) is required for the Python, TypeScript, JavaScript, and PHP language servers; if neither `node` nor `CODEBOARDING_NODE_PATH` is set, setup downloads a pinned Node.js runtime into `~/.codeboarding/servers/nodeenv/` automatically.
156
+
157
+ ## Configuration
158
+
159
+ On first run, CodeBoarding creates `~/.codeboarding/config.toml`. Set one provider there or use environment variables.
160
+
161
+ ```toml
162
+ [provider]
163
+ # openai_api_key = "sk-..."
164
+ # openai_base_url = "https://api.example.com/v1" # any OpenAI-compatible gateway
165
+ # anthropic_api_key = "sk-ant-..."
166
+ # anthropic_base_url = "https://resource.services.ai.azure.com/anthropic" # Azure Foundry
167
+ # google_api_key = "AIza..."
168
+ # vercel_api_key = "vck_..."
169
+ # aws_bearer_token_bedrock = "..."
170
+ # ollama_base_url = "http://localhost:11434"
171
+ # openrouter_api_key = "sk-..."
172
+ # orcarouter_api_key = "sk-orca-..." # model routing gateway (https://www.orcarouter.ai)
173
+ # requesty_api_key = "rqsty-..." # LLM gateway (https://www.requesty.ai)
174
+ # litellm_base_url = "http://localhost:4000" # LiteLLM proxy server URL (required)
175
+ # litellm_api_key = "sk-..." # LiteLLM proxy server key (optional)
176
+
177
+ [llm]
178
+ # agent_model = "gemini-3.8-flash"
179
+ ```
180
+
181
+ `openai_base_url` points CodeBoarding at any OpenAI-compatible gateway, including LM Studio. Set its model ID with `agent_model`; CodeBoarding adapts its prompts for the model families already represented by its provider defaults, including Qwen. The equivalent shell variables are `OPENAI_BASE_URL`, `OPENAI_API_KEY`, and `AGENT_MODEL`.
182
+
183
+ `anthropic_base_url` points the Anthropic client at a compatible Messages API, including Azure Foundry Claude deployments. Set the deployment key as `anthropic_api_key` and use canonical Anthropic model IDs such as `claude-sonnet-5` for `agent_model` so CodeBoarding selects the correct model capabilities and prompts.
184
+
185
+ 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.
186
+
187
+ Two environment variables tune the static analysis itself:
188
+
189
+ | Variable | Effect |
190
+ | --- | --- |
191
+ | `CODEBOARDING_LSP_REQUEST_TIMEOUT` | Seconds a language-server request may block *when it uses the per-language default* (120s for C#, 60s elsewhere). Not a hard cap on every request: the indexing and didOpen-drain probes pass their own scaled budget (60s plus 2s per file, capped at 1800s) and are unaffected. Applies to every language in the run. Unset or empty leaves the defaults alone; any other unusable value fails the run rather than falling back. |
192
+ | `CODEBOARDING_MAX_CONCURRENT_ENGINES` | How many language servers may be resident at once. `0` (the default) leaves the bound off. |
193
+
194
+ ## Common commands
195
+
196
+ ```bash
197
+ # Analyze a local repository
198
+ python main.py full --local ./my-project
199
+
200
+ # Raise the depth ceiling to auto-expand deeper (rarely needed — a component that
201
+ # outgrows the leaf ceiling is flagged expandable at whatever depth the run stops
202
+ # and can be expanded on demand; --depth-cap is a safety-valve cap, default 3)
203
+ python main.py full --local ./my-project --depth-cap 5
204
+
205
+ # Re-analyze only changed parts when possible
206
+ python main.py incremental --local ./my-project
207
+
208
+ # Update a single component by ID
209
+ python main.py partial --local ./my-project --component-id "1.2"
210
+
211
+ # Analyze a remote GitHub repository
212
+ python main.py full https://github.com/pytorch/pytorch
213
+ ```
214
+
215
+ `--depth-cap` configures `metadata.depth_cap`; `metadata.depth_level` records the
216
+ depth actually reached. The cap is a maximum, not a target depth. `--depth-level`
217
+ is rejected; there is no compatibility alias.
218
+
219
+ Python callers must use `run_full(..., depth_cap=...)`,
220
+ `build_generator(..., depth_cap=...)`, and `DiagramGenerator(..., depth_cap=...)`.
221
+ The generator attribute is `depth_cap` and the exported default is
222
+ `diagram_analysis.DEFAULT_DEPTH_CAP` (3). The GitHub helper uses `DIAGRAM_DEPTH_CAP`
223
+ and rejects `DIAGRAM_DEPTH_LEVEL`. Telemetry reports configured `depth_cap`, not
224
+ `depth_level`. Readers of analysis results must keep reading `metadata.depth_level`
225
+ for the actual depth. Existing baseline loading behavior is unchanged: prefer
226
+ `metadata.depth_cap`, fall back to legacy `metadata.depth_level`, then use
227
+ `DEFAULT_DEPTH_CAP` if neither exists. This metadata fallback is not a CLI alias.
228
+
229
+ > **Incremental needs a baseline.** `incremental` diffs the working tree against the previous
230
+ > analysis in `.codeboarding/` (`analysis.json` + `fingerprint.json`). That baseline can live
231
+ > purely locally — a prior `full`/`incremental` run in the same output dir is enough. Commit
232
+ > `.codeboarding/` only if you want the baseline to travel with the branch (so a teammate or a
233
+ > fresh checkout can run incremental too). With no baseline at all — or one that predates content
234
+ > versioning — `incremental` fails fast with "run a full analysis first" rather than silently
235
+ > doing a full run. Static-analysis caches are versioned but not migrated; after a cache-version
236
+ > upgrade, run a full analysis once to reindex.
237
+
238
+ ## Where to use it
239
+
240
+ - **CLI:** [CodeBoarding CLI](#quick-start) — this repository — for local analysis, automation, and documentation generation.
241
+ - **Browser:** [web platform](https://app.codeboarding.org) for Explore and Review, public maps, and local analysis files.
242
+ - **Editor:** [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=Codeboarding.codeboarding) or [Open VSX](https://open-vsx.org/extension/CodeBoarding/codeboarding) for in-editor architecture exploration.
243
+ - **CI:** [GitHub Action](https://github.com/marketplace/actions/codeboarding-action) to keep analysis updated and post architecture change maps on pull requests.
244
+
245
+ ## Supported stack
246
+
247
+ - Languages: Python, TypeScript, JavaScript, Java, Go, PHP, Rust, C#.
248
+ - LLM providers: OpenAI, Anthropic, Google, Vercel AI Gateway, AWS Bedrock, Ollama, OpenRouter, OrcaRouter, Requesty, LiteLLM proxy, and more.
249
+
250
+ ## Examples
251
+
252
+ - [Explore CodeBoarding's architecture](https://app.codeboarding.org/CodeBoarding/CodeBoarding) — the engine, drawn from its own code.
253
+ - [Review CodeBoarding pull request #586](https://app.codeboarding.org/CodeBoarding/CodeBoarding/pull/586) — component changes and code diffs together.
254
+ - [Browse example diagrams](https://codeboarding.org/diagrams).
255
+ - [Awesome Architecture MDs](https://github.com/CodeBoarding/awesome-architecture-mds) — generated architecture documentation for open-source repositories (formerly GeneratedOnBoardings).
256
+
257
+ Public maps need a committed `.codeboarding/analysis.json` at the selected branch or commit.
258
+ Open one at `https://app.codeboarding.org/<owner>/<repo>` without signing in; opening a URL does not generate a new analysis.
259
+
260
+ ## Telemetry
261
+
262
+ CodeBoarding collects usage telemetry (which command ran, success/failure,
263
+ duration, token cost, repository size and languages, and the account the
264
+ repository belongs to) to help us improve the tool. It is on by default and
265
+ never collects source code, file names, repository names, paths, prompts, model
266
+ outputs, or API keys. Opt out anytime:
267
+
268
+ ```bash
269
+ export CODEBOARDING_TELEMETRY=false # or: export DO_NOT_TRACK=1
270
+ ```
271
+
272
+ See [TELEMETRY.md](TELEMETRY.md) for the full list of events and properties.
273
+
274
+ ## Contributing
275
+
276
+ 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.
277
+
278
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and testing guidance.
279
+
280
+ ## License
281
+
282
+ The analysis engine and CLI in this repository are released under the [MIT License](LICENSE).
@@ -294,6 +294,19 @@ LLM_PROVIDERS = {
294
294
  "max_retries": 0,
295
295
  },
296
296
  ),
297
+ "requesty": LLMConfig(
298
+ chat_class=ChatOpenAI,
299
+ selection_envs=["REQUESTY_API_KEY"],
300
+ api_key_env="REQUESTY_API_KEY",
301
+ agent_model="gemini-3.8-flash",
302
+ base_url_env="REQUESTY_BASE_URL",
303
+ default_base_url="https://router.requesty.ai/v1",
304
+ extra_args={
305
+ "max_tokens": None,
306
+ "timeout": LLMDefaults.REQUEST_TIMEOUT_SECONDS,
307
+ "max_retries": 0,
308
+ },
309
+ ),
297
310
  "litellm": LLMConfig(
298
311
  chat_class=ChatOpenAI,
299
312
  # Base URL only: a key alone must not select litellm, since there is no
@@ -463,6 +476,15 @@ def get_current_prompt_profile(llm: BaseChatModel | None = None) -> PromptProfil
463
476
  return resolve_prompt_profile(get_current_agent_model_ref())
464
477
 
465
478
 
479
+ #: What CodeBoarding-action writes as ``OPENROUTER_API_KEY`` for hosted credentials: a placeholder its
480
+ #: local relay swaps for a GitHub OIDC token. Keep in step with the action's ``configure-auth.sh``.
481
+ OIDC_RELAY_PLACEHOLDER_KEY = "github-actions-oidc-relay"
482
+
483
+ #: ``key_tail`` for a run on hosted credentials: the placeholder's last four characters name no key
484
+ #: the user holds, so an auth error must not ask them to check it.
485
+ CODEBOARDING_KEY_TAIL = "hosted"
486
+
487
+
466
488
  def current_provider_key_context() -> tuple[str, str]:
467
489
  """The selected provider name and a masked key tail, for auth-error messages.
468
490
 
@@ -476,6 +498,8 @@ def current_provider_key_context() -> tuple[str, str]:
476
498
  return "unknown", "unknown"
477
499
  name = selected[0]
478
500
  key = LLM_PROVIDERS[name].get_api_key()
501
+ if key == OIDC_RELAY_PLACEHOLDER_KEY:
502
+ return name, CODEBOARDING_KEY_TAIL
479
503
  key_tail = key[-4:] if key and len(key) >= 4 else "unknown"
480
504
  return name, key_tail
481
505
 
@@ -18,7 +18,7 @@ from __future__ import annotations
18
18
  import logging
19
19
  import re
20
20
 
21
- from agents.llm_config import current_provider_key_context
21
+ from agents.llm_config import CODEBOARDING_KEY_TAIL, current_provider_key_context
22
22
 
23
23
  logger = logging.getLogger(__name__)
24
24
 
@@ -28,6 +28,9 @@ logger = logging.getLogger(__name__)
28
28
  # import it without pulling in Core's whole CLI module.
29
29
  EXIT_AUTH_ERROR = 2
30
30
 
31
+ # Process exit code for an exhausted token or credit quota: the key is fine, the account is not.
32
+ EXIT_QUOTA_EXHAUSTED = 3
33
+
31
34
  # Class names, across SDKs, that always mean "credentials were rejected".
32
35
  # openai/anthropic/cerebras raise ``AuthenticationError``; google raises
33
36
  # ``Unauthenticated``/``PermissionDenied``; Bedrock (botocore) surfaces
@@ -48,6 +51,8 @@ _AUTH_MESSAGE_PATTERNS = (
48
51
  re.compile(r"invalid[\s_-]*x?[\s_-]*api[\s_-]*key", re.IGNORECASE),
49
52
  re.compile(r"incorrect api key", re.IGNORECASE),
50
53
  re.compile(r"api key.*invalid", re.IGNORECASE),
54
+ # Google: "API key not valid" or reason API_KEY_INVALID.
55
+ re.compile(r"api[\s_]*key[\s_]*(?:not[\s_]*valid|invalid)", re.IGNORECASE),
51
56
  re.compile(r"authentication[\s_]*error", re.IGNORECASE),
52
57
  re.compile(r"authentication fails", re.IGNORECASE),
53
58
  re.compile(r"\bunauthorized\b", re.IGNORECASE),
@@ -57,6 +62,33 @@ _AUTH_MESSAGE_PATTERNS = (
57
62
  )
58
63
 
59
64
 
65
+ # What each provider says when the prompt is over the model's context window: Google, OpenAI, Anthropic.
66
+ _CONTEXT_OVERFLOW_PATTERNS = (
67
+ re.compile(r"exceeds the maximum number of tokens", re.IGNORECASE),
68
+ re.compile(r"maximum context length|context_length_exceeded", re.IGNORECASE),
69
+ re.compile(r"prompt is too long", re.IGNORECASE),
70
+ )
71
+
72
+
73
+ class ScopeContextTooLargeError(RuntimeError):
74
+ """A scope's context does not fit the model's budget even after every trim.
75
+
76
+ Why: sent anyway, the provider rejects it with a 400 worded differently by each provider — and
77
+ OpenRouter's embeds an upstream 401 that used to be read as a rejected key. Stopping before the
78
+ call names the real limit.
79
+ """
80
+
81
+ def __init__(self, scope_id: str, needed_tokens: int, allowed_tokens: int):
82
+ super().__init__(
83
+ f"Scope {scope_id!r} needs about {needed_tokens:,} tokens of context after trimming, over the "
84
+ f"{allowed_tokens:,} this model allows a scope. Use a model with a larger context window, or "
85
+ "narrow the analysis with .codeboardingignore."
86
+ )
87
+ self.scope_id = scope_id
88
+ self.needed_tokens = needed_tokens
89
+ self.allowed_tokens = allowed_tokens
90
+
91
+
60
92
  class LLMAuthError(RuntimeError):
61
93
  """An LLM provider rejected our credentials (HTTP 401 or equivalent).
62
94
 
@@ -88,9 +120,10 @@ def _status_code(exc: BaseException) -> int | None:
88
120
 
89
121
 
90
122
  def _is_auth_failure(exc: BaseException) -> bool:
91
- """True when *exc* represents rejected credentials, across providers."""
92
- if _status_code(exc) in (401, 403):
93
- return True
123
+ """Detect rejected credentials, preferring the response status over embedded upstream errors."""
124
+ status = _status_code(exc)
125
+ if status is not None:
126
+ return status in (401, 403)
94
127
  if type(exc).__name__ in _AUTH_TYPE_NAMES:
95
128
  return True
96
129
  text = str(exc)
@@ -110,11 +143,16 @@ def detect_auth_error(exc: BaseException, *, provider: str, key_tail: str) -> LL
110
143
 
111
144
  status = _status_code(exc)
112
145
  provider_message = str(exc)
113
- friendly = (
114
- f"Your {provider} API key was rejected"
115
- + (f" (HTTP {status})" if status is not None else "")
116
- + f". Verify the key ending in '…{key_tail}' and try again."
117
- )
146
+ status_note = f" (HTTP {status})" if status is not None else ""
147
+ if key_tail == CODEBOARDING_KEY_TAIL:
148
+ friendly = (
149
+ f"CodeBoarding's hosted {provider} credentials were rejected{status_note}. This run used no key of "
150
+ "yours: check that the workflow grants `id-token: write`, then re-run."
151
+ )
152
+ else:
153
+ friendly = (
154
+ f"Your {provider} API key was rejected{status_note}. Verify the key ending in '…{key_tail}' and try again."
155
+ )
118
156
  telemetry_properties = {
119
157
  "error_type": "auth",
120
158
  "error_provider": provider,
@@ -130,6 +168,25 @@ def detect_auth_error(exc: BaseException, *, provider: str, key_tail: str) -> LL
130
168
  )
131
169
 
132
170
 
171
+ def llm_failure_properties(exc: BaseException) -> dict:
172
+ """``$exception`` properties for a failed LLM call, telling an exhausted quota or an oversized prompt
173
+ apart from other failures.
174
+
175
+ Why: the hosted proxy's paywall is a 402, and OpenAI reports an empty balance as a 429 ``insufficient_quota``.
176
+ An oversized prompt is ours to fix, not the provider's, so it gets its own type on the dashboard.
177
+ """
178
+ status = _status_code(exc)
179
+ quota = status == 402 or (status == 429 and "insufficient_quota" in str(exc))
180
+ context = isinstance(exc, ScopeContextTooLargeError) or any(p.search(str(exc)) for p in _CONTEXT_OVERFLOW_PATTERNS)
181
+ provider, _key_tail = current_provider_key_context()
182
+ return {
183
+ "error_type": "quota" if quota else "context" if context else "llm",
184
+ "error_provider": provider,
185
+ "error_status_code": status,
186
+ "error_message": str(exc)[:500],
187
+ }
188
+
189
+
133
190
  def raise_if_auth_error(exc: Exception) -> None:
134
191
  """Raise a typed terminal error when a provider rejected its credentials."""
135
192
  provider, key_tail = current_provider_key_context()
@@ -3,21 +3,30 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
+ import logging
6
7
  from collections import defaultdict
7
8
  from collections.abc import Sequence
8
9
  from pathlib import Path
9
10
  from typing import Any
10
11
 
11
12
  from agents.agent_responses import AnalysisInsights
13
+ from agents.constants import ModelCapabilities
14
+ from agents.llm_errors import ScopeContextTooLargeError
12
15
  from repo_utils.path_utils import normalize_repo_path
13
16
  from static_analyzer.cfg.edge import EdgeKind
14
17
  from static_analyzer.clustering import ClusterConnectionEdge, ClusterGroup, ClusterScopeResult
15
18
  from static_analyzer.node import Node
16
19
 
20
+ logger = logging.getLogger(__name__)
21
+
17
22
  #: Example edges per directed group pair; the count is always given, the examples let
18
23
  #: a relation's ``key_edges`` cite exact symbols.
19
24
  MAX_EXAMPLE_EDGES = 5
20
25
 
26
+ #: The reason a file gets when no rule placed it. Most files carry it, so it is left out rather than
27
+ #: repeated: the prompt says a file without a reason is a plain member.
28
+ DEFAULT_GROUPING_REASON = "member of the deterministic group"
29
+
21
30
 
22
31
  def render_scope_context(
23
32
  scope: ClusterScopeResult,
@@ -28,11 +37,16 @@ def render_scope_context(
28
37
  changed_files: set[str] | frozenset[str],
29
38
  incremental: bool,
30
39
  enclosing_names: Sequence[str] = (),
40
+ max_tokens: int = ModelCapabilities.FALLBACK_INPUT,
31
41
  ) -> str:
32
42
  """Return complete group files, boundary candidates, and known calls as JSON.
33
43
 
34
44
  ``enclosing_names``: the components this scope sits inside, outermost first, so the
35
45
  model does not name a child after its parent.
46
+
47
+ ``max_tokens``: the most this context may take. Over it, the least load-bearing parts are trimmed
48
+ in order; if it still does not fit, :class:`ScopeContextTooLargeError` is raised instead of
49
+ sending a prompt the provider will reject.
36
50
  """
37
51
  boundary_reasons = _boundary_reasons(scope, repo_dir)
38
52
  components = {component.component_id: component for component in analysis.components}
@@ -46,11 +60,9 @@ def render_scope_context(
46
60
  "status": "changed" if group.group_id in editable_group_ids else "unchanged",
47
61
  "name_locked": group.group_id in locked_name_ids,
48
62
  "files": [
49
- {
50
- "path": file_path,
51
- "grouping_reason": reason,
52
- "changed": file_path in changed_files,
53
- }
63
+ {"path": file_path}
64
+ | ({"grouping_reason": reason} if reason != DEFAULT_GROUPING_REASON else {})
65
+ | ({"changed": file_path in changed_files} if incremental else {})
54
66
  for file_path, reason in file_reasons.items()
55
67
  ],
56
68
  "bordering_files": [
@@ -87,7 +99,68 @@ def render_scope_context(
87
99
  if relation.src_id and relation.dst_id
88
100
  ],
89
101
  }
90
- return json.dumps(payload, indent=2, sort_keys=True)
102
+ text = _dump(payload)
103
+ for trim, what in _TRIMS:
104
+ if _tokens(text) <= max_tokens:
105
+ return text
106
+ logger.warning(
107
+ "Scope %s context is ~%d tokens, over its %d budget: %s",
108
+ scope.scope_id,
109
+ _tokens(text),
110
+ max_tokens,
111
+ what,
112
+ )
113
+ trim(payload)
114
+ text = _dump(payload)
115
+ if _tokens(text) > max_tokens:
116
+ raise ScopeContextTooLargeError(scope.scope_id, _tokens(text), max_tokens)
117
+ return text
118
+
119
+
120
+ def _dump(payload: dict[str, Any]) -> str:
121
+ """Why: nobody reads this JSON but the model, and indentation was a third of its size."""
122
+ return json.dumps(payload, separators=(",", ":"), sort_keys=True)
123
+
124
+
125
+ def _tokens(text: str) -> int:
126
+ return int(len(text) / ModelCapabilities.CHARS_PER_TOKEN)
127
+
128
+
129
+ def _drop_bordering_files(payload: dict[str, Any]) -> None:
130
+ for group in payload["groups"]:
131
+ references = sorted(
132
+ {
133
+ reason
134
+ for entry in group.pop("bordering_files", [])
135
+ for reason in entry["reasons"]
136
+ if " reference " in reason
137
+ }
138
+ )
139
+ if references:
140
+ group["boundary_references"] = references
141
+
142
+
143
+ def _one_example_without_locations(payload: dict[str, Any]) -> None:
144
+ for connection in payload["known_connections"]:
145
+ connection["examples"] = [
146
+ {"source": example["source"], "target": example["target"]} for example in connection["examples"][:1]
147
+ ]
148
+
149
+
150
+ def _files_by_path_only(payload: dict[str, Any]) -> None:
151
+ for group in payload["groups"]:
152
+ group["files"] = [
153
+ {"path": entry["path"], "changed": True} if entry.get("changed") else entry["path"]
154
+ for entry in group["files"]
155
+ ]
156
+
157
+
158
+ #: Trim optional detail in order, preserving structural references and changed-file markers.
159
+ _TRIMS = (
160
+ (_drop_bordering_files, "compacting boundary evidence"),
161
+ (_one_example_without_locations, "keeping one example per connection, without locations"),
162
+ (_files_by_path_only, "listing files by path only"),
163
+ )
91
164
 
92
165
 
93
166
  def scope_file_paths(scope: ClusterScopeResult, repo_dir: Path) -> frozenset[str]:
@@ -121,7 +194,7 @@ def _group_file_reasons(
121
194
  if name in scope.graphs_by_language[language].nodes
122
195
  }
123
196
  for file_path in files:
124
- reasons.setdefault(file_path, "member of the deterministic group")
197
+ reasons.setdefault(file_path, DEFAULT_GROUPING_REASON)
125
198
  return dict(sorted(reasons.items()))
126
199
 
127
200
 
@@ -31,7 +31,10 @@ SCOPE_ANALYSIS_SYSTEM_MESSAGE = """You name and describe fixed, deterministic co
31
31
  The supplied group IDs, file membership, hierarchy, and known directed calls are authoritative. Never merge,
32
32
  split, move, add, or remove groups. Work at the supplied scope exactly the same way whether it is root or nested.
33
33
 
34
- Use the supplied files, grouping reasons, bordering files, and known connections before calling tools. A known
34
+ Use the supplied files, grouping reasons, bordering files, and known connections before calling tools. A file
35
+ listed without a `grouping_reason` is a plain member of its group. Compact file lists retain `changed: true`
36
+ on modified files. `boundary_references` summarizes directed structural references between groups when
37
+ per-file boundary details are omitted. A known
35
38
  connection gives the number of distinct calls from one group to another and a few of them in full; cite only
36
39
  symbols that appear in the input. Never reuse a name listed under `enclosing_components`: those are the
37
40
  components this scope sits inside, and a child named after its parent overwrites its document. `readFile`