codeboarding 0.12.0__tar.gz → 0.12.2__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.
- {codeboarding-0.12.0/codeboarding.egg-info → codeboarding-0.12.2}/PKG-INFO +7 -3
- {codeboarding-0.12.0 → codeboarding-0.12.2}/PYPI.md +4 -2
- {codeboarding-0.12.0 → codeboarding-0.12.2}/README.md +24 -7
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/cluster_methods_mixin.py +27 -5
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/llm_config.py +135 -39
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/model_capabilities.py +6 -2
- {codeboarding-0.12.0 → codeboarding-0.12.2/codeboarding.egg-info}/PKG-INFO +7 -3
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding.egg-info/SOURCES.txt +8 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding.egg-info/requires.txt +2 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding.egg-info/top_level.txt +1 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_workflows/analysis.py +4 -3
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/diagram_generator.py +11 -2
- {codeboarding-0.12.0 → codeboarding-0.12.2}/github_action.py +1 -0
- codeboarding-0.12.2/health_main.py +152 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/main.py +2 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/pyproject.toml +4 -1
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/__init__.py +88 -12
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/cfg_skip_planner.py +7 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/csharp_config_scanner.py +14 -7
- codeboarding-0.12.2/static_analyzer/dotnet_sdk.py +327 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/adapters/csharp_adapter.py +75 -29
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/adapters/go_adapter.py +1 -1
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/language_adapter.py +6 -1
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/lsp_client.py +15 -8
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/scanner.py +2 -0
- codeboarding-0.12.2/telemetry/__init__.py +10 -0
- codeboarding-0.12.2/telemetry/device_id.py +91 -0
- codeboarding-0.12.2/telemetry/events.py +246 -0
- codeboarding-0.12.2/telemetry/schemas.py +67 -0
- codeboarding-0.12.2/telemetry/service.py +97 -0
- codeboarding-0.12.2/tests/test_telemetry_events.py +196 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_tool_registry.py +93 -8
- codeboarding-0.12.2/tests/test_user_config.py +220 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tool_registry/__init__.py +1 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tool_registry/installers.py +79 -4
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tool_registry/manifest.py +8 -8
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tool_registry/paths.py +13 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tool_registry/registry.py +5 -7
- {codeboarding-0.12.0 → codeboarding-0.12.2}/user_config.py +31 -5
- codeboarding-0.12.0/tests/test_user_config.py +0 -98
- {codeboarding-0.12.0 → codeboarding-0.12.2}/LICENSE +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/abstraction_agent.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/agent.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/agent_responses.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/change_status.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/cluster_budget.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/constants.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/dependency_discovery.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/details_agent.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/incremental_agent.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/meta_agent.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/planner_agent.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/prompts/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/prompts/abstract_prompt_factory.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/prompts/claude_prompts.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/prompts/deepseek_prompts.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/prompts/gemini_flash_prompts.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/prompts/glm_prompts.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/prompts/gpt_prompts.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/prompts/kimi_prompts.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/prompts/prompt_factory.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/retry.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/base.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/get_external_deps.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/get_method_invocations.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/read_cfg.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/read_docs.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/read_file.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/read_file_structure.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/read_packages.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/read_source.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/read_structure.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/tools/toolkit.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/agents/validation.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/caching/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/caching/cache.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/caching/details_cache.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/caching/meta_cache.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding.egg-info/dependency_links.txt +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding.egg-info/entry_points.txt +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_cli/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_cli/bootstrap.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_cli/commands/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_cli/commands/full_analysis.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_cli/commands/incremental_analysis.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_cli/commands/partial_analysis.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_workflows/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_workflows/orchestration.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_workflows/rendering.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_workflows/sources/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_workflows/sources/local.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/codeboarding_workflows/sources/remote.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/constants.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/core/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/core/plugin_loader.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/core/protocols.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/core/registry.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/analysis_json.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/cluster_delta.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/cluster_snapshot.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/exceptions.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/file_coverage.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/io_utils.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/run_context.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/run_mode.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/diagram_analysis/version.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/checks/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/checks/circular_deps.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/checks/cohesion.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/checks/coupling.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/checks/function_size.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/checks/god_class.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/checks/inheritance.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/checks/instability.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/checks/unused_code_diagnostics.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/config.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/models.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/health/runner.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/install.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/logging_config.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/monitoring/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/monitoring/callbacks.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/monitoring/context.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/monitoring/mixin.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/monitoring/paths.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/monitoring/stats.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/monitoring/writers.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/output_generators/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/output_generators/html.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/output_generators/html_template.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/output_generators/markdown.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/output_generators/mdx.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/output_generators/sphinx.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/repo_utils/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/repo_utils/change_detector.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/repo_utils/diff_parser.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/repo_utils/errors.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/repo_utils/git_ops.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/repo_utils/ignore.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/setup.cfg +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/analysis_cache.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/analysis_result.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/cluster_helpers.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/cluster_relations.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/constants.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/adapters/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/adapters/java_adapter.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/adapters/php_adapter.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/adapters/python_adapter.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/adapters/rust_adapter.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/adapters/typescript_adapter.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/call_graph_builder.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/edge_build_context.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/edge_builder.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/hierarchy_builder.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/lsp_constants.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/models.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/progress.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/protocols.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/result_converter.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/source_inspector.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/symbol_table.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/engine/utils.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/graph.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/incremental_orchestrator.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/java_config_scanner.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/java_utils.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/language_results.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/leiden_utils.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/lsp_client/__init__.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/lsp_client/diagnostics.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/node.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/programming_language.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/reference_resolve_mixin.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/static_analyzer/typescript_config_scanner.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_cli_parser.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_github_action.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_install.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_logging_config.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_main.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_pyproject_packages.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_registry_coverage.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_vscode_constants.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_windows_compatibility.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/tests/test_windows_encoding.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/utils.py +0 -0
- {codeboarding-0.12.0 → codeboarding-0.12.2}/vscode_constants.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeboarding
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.2
|
|
4
4
|
Summary: Interactive Diagrams for Code
|
|
5
5
|
Author: CodeBoarding Team
|
|
6
6
|
License-Expression: MIT
|
|
@@ -40,6 +40,8 @@ Requires-Dist: markitdown>=0.1
|
|
|
40
40
|
Requires-Dist: networkx>=3.4
|
|
41
41
|
Requires-Dist: nodeenv>=1.10.0
|
|
42
42
|
Requires-Dist: pathspec>=0.12
|
|
43
|
+
Requires-Dist: posthog>=3.7
|
|
44
|
+
Requires-Dist: pydantic>=2.0
|
|
43
45
|
Requires-Dist: pyyaml>=6.0
|
|
44
46
|
Requires-Dist: regex>=2024.11
|
|
45
47
|
Requires-Dist: rich>=12.6
|
|
@@ -93,15 +95,17 @@ Dynamic: license-file
|
|
|
93
95
|
The recommended way to install the CLI is with [pipx](https://pipx.pypa.io), which automatically creates an isolated environment:
|
|
94
96
|
|
|
95
97
|
```bash
|
|
96
|
-
pipx install codeboarding --python python3.12
|
|
98
|
+
pipx install codeboarding --python python3.12 --pip-args="--extra-index-url https://pip.codeboarding.org/simple/"
|
|
97
99
|
```
|
|
98
100
|
|
|
99
101
|
Alternatively, install into an existing virtual environment with pip:
|
|
100
102
|
|
|
101
103
|
```bash
|
|
102
|
-
pip install codeboarding
|
|
104
|
+
pip install codeboarding --extra-index-url https://pip.codeboarding.org/simple/
|
|
103
105
|
```
|
|
104
106
|
|
|
107
|
+
|
|
108
|
+
|
|
105
109
|
> Installing into the global Python environment with `pip` is not recommended — it can cause dependency conflicts and will fail if the system Python is not 3.12 or 3.13.
|
|
106
110
|
|
|
107
111
|
Language server binaries are downloaded automatically on first use. To pre-install them explicitly (useful in CI or restricted environments):
|
|
@@ -23,15 +23,17 @@
|
|
|
23
23
|
The recommended way to install the CLI is with [pipx](https://pipx.pypa.io), which automatically creates an isolated environment:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
pipx install codeboarding --python python3.12
|
|
26
|
+
pipx install codeboarding --python python3.12 --pip-args="--extra-index-url https://pip.codeboarding.org/simple/"
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
Alternatively, install into an existing virtual environment with pip:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
pip install codeboarding
|
|
32
|
+
pip install codeboarding --extra-index-url https://pip.codeboarding.org/simple/
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
|
|
36
|
+
|
|
35
37
|
> Installing into the global Python environment with `pip` is not recommended — it can cause dependency conflicts and will fail if the system Python is not 3.12 or 3.13.
|
|
36
38
|
|
|
37
39
|
Language server binaries are downloaded automatically on first use. To pre-install them explicitly (useful in CI or restricted environments):
|
|
@@ -4,9 +4,9 @@ See what your AI is building before it breaks.
|
|
|
4
4
|
|
|
5
5
|
CodeBoarding gives developers and coding agents a visual map of a codebase. It combines static analysis with LLM reasoning to generate architecture diagrams, component-level documentation, and navigable outputs you can use in your IDE, CI, and docs.
|
|
6
6
|
|
|
7
|
-
[Website](https://codeboarding.org) · [Open VSX extension](https://open-vsx.org/extension/CodeBoarding/codeboarding) · [Explore examples](https://codeboarding.org/diagrams) · [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Codeboarding.codeboarding) · [GitHub Action](https://github.com/marketplace/actions/codeboarding-
|
|
7
|
+
[Website](https://codeboarding.org) <img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=0855d476-b2d0-44cc-b93d-69b47504719c" width="0" height="0" /> · [Open VSX extension](https://open-vsx.org/extension/CodeBoarding/codeboarding) <img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=ce87464c-2792-46b0-9ea2-87eefe853d7e" width="0" height="0" /> · [Explore examples](https://codeboarding.org/diagrams) · [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Codeboarding.codeboarding) <img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=8a3d26e0-6f6b-49c0-8482-114445de56a5" width="0" height="0" /> · [GitHub Action](https://github.com/marketplace/actions/codeboarding-action) ·[Discord](https://discord.gg/T5zHTJYFuy)
|
|
8
8
|
|
|
9
|
-
[](https://open-vsx.org/extension/CodeBoarding/codeboarding)
|
|
9
|
+
[](https://open-vsx.org/extension/CodeBoarding/codeboarding) <img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=ce87464c-2792-46b0-9ea2-87eefe853d7e" width="0" height="0" />
|
|
10
10
|
|
|
11
11
|
Install the extension from Open VSX.
|
|
12
12
|
|
|
@@ -86,7 +86,7 @@ codeboarding full --local /path/to/repo
|
|
|
86
86
|
Or, if you prefer pip, install into a virtual environment (not the global Python):
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
-
pip install codeboarding
|
|
89
|
+
pip install codeboarding --extra-index-url https://pip.codeboarding.org/simple/
|
|
90
90
|
codeboarding-setup
|
|
91
91
|
codeboarding full --local /path/to/repo
|
|
92
92
|
```
|
|
@@ -108,6 +108,8 @@ On first run, CodeBoarding creates `~/.codeboarding/config.toml`. Set one provid
|
|
|
108
108
|
# aws_bearer_token_bedrock = "..."
|
|
109
109
|
# ollama_base_url = "http://localhost:11434"
|
|
110
110
|
# openrouter_api_key = "sk-..."
|
|
111
|
+
# litellm_base_url = "http://localhost:4000" # LiteLLM proxy server URL (required)
|
|
112
|
+
# litellm_api_key = "sk-..." # LiteLLM proxy server key (optional)
|
|
111
113
|
|
|
112
114
|
[llm]
|
|
113
115
|
# agent_model = "gemini-3-flash"
|
|
@@ -138,19 +140,32 @@ python main.py full https://github.com/pytorch/pytorch
|
|
|
138
140
|
## Where to use it
|
|
139
141
|
|
|
140
142
|
- [CLI](https://github.com/CodeBoarding/CodeBoarding) for local analysis, automation, and CI workflows.
|
|
141
|
-
- [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Codeboarding.codeboarding) for in-editor visual architecture.
|
|
142
|
-
- [GitHub Action](https://github.com/marketplace/actions/codeboarding-
|
|
143
|
+
- [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Codeboarding.codeboarding) <img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=8a3d26e0-6f6b-49c0-8482-114445de56a5" width="0" height="0" /> for in-editor visual architecture.
|
|
144
|
+
- [GitHub Action](https://github.com/marketplace/actions/codeboarding-action) to keep diagrams updated in CI.
|
|
143
145
|
|
|
144
146
|
## Supported stack
|
|
145
147
|
|
|
146
148
|
- Languages: Python, TypeScript, JavaScript, Java, Go, PHP, Rust, C#.
|
|
147
|
-
- LLM providers: OpenAI, Anthropic, Google, Vercel AI Gateway, AWS Bedrock, Ollama, OpenRouter, and more.
|
|
149
|
+
- LLM providers: OpenAI, Anthropic, Google, Vercel AI Gateway, AWS Bedrock, Ollama, OpenRouter, LiteLLM proxy, and more.
|
|
148
150
|
|
|
149
151
|
## Examples
|
|
150
152
|
|
|
151
153
|
- Visualized 800+ open-source repositories.
|
|
152
154
|
- Browse generated examples in [GeneratedOnBoardings](https://github.com/CodeBoarding/GeneratedOnBoardings).
|
|
153
|
-
- Try the hosted explorer at [codeboarding.org/diagrams](https://codeboarding.org/diagrams).
|
|
155
|
+
- Try the hosted explorer at [codeboarding.org/diagrams](https://codeboarding.org/diagrams) <img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=0855d476-b2d0-44cc-b93d-69b47504719c" width="0" height="0" />.
|
|
156
|
+
|
|
157
|
+
## Telemetry
|
|
158
|
+
|
|
159
|
+
CodeBoarding collects anonymous, aggregate usage telemetry (which command ran,
|
|
160
|
+
success/failure, duration, and token cost) to help us improve the tool. It is on
|
|
161
|
+
by default and never collects source code, file names, repository names, paths,
|
|
162
|
+
prompts, model outputs, API keys, or any personal information. Opt out anytime:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
export CODEBOARDING_TELEMETRY=false # or: export DO_NOT_TRACK=1
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
See [TELEMETRY.md](TELEMETRY.md) for the full list of events and properties.
|
|
154
169
|
|
|
155
170
|
## Contributing
|
|
156
171
|
|
|
@@ -159,3 +174,5 @@ If you want to improve CodeBoarding, open an [issue](https://github.com/CodeBoar
|
|
|
159
174
|
## Vision
|
|
160
175
|
|
|
161
176
|
CodeBoarding is building an open standard for code understanding: a visual, accurate, high-level representation of a codebase that both humans and agents can use.
|
|
177
|
+
|
|
178
|
+
<img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=1942e7e7-0762-4cdd-9f08-024acc098071" />
|
|
@@ -16,7 +16,8 @@ from agents.agent_responses import (
|
|
|
16
16
|
MethodEntry,
|
|
17
17
|
)
|
|
18
18
|
from agents.cluster_budget import ClusterPromptBudget
|
|
19
|
-
from agents.llm_config import get_current_agent_context_window
|
|
19
|
+
from agents.llm_config import get_current_agent_context_window, get_current_agent_model_ref
|
|
20
|
+
from agents.model_capabilities import ContextWindow
|
|
20
21
|
from constants import MIN_CLUSTERS_THRESHOLD
|
|
21
22
|
from static_analyzer.analysis_result import StaticAnalysisResults
|
|
22
23
|
from static_analyzer.cfg_skip_planner import ContextBudgetExceededError, plan_skip_set
|
|
@@ -46,6 +47,20 @@ class _RenderedClusterString:
|
|
|
46
47
|
cluster_ids: set[int]
|
|
47
48
|
|
|
48
49
|
|
|
50
|
+
def _describe_window(ctx: ContextWindow) -> str:
|
|
51
|
+
suffix = "; fallback default, model window unresolved" if ctx.is_fallback else ""
|
|
52
|
+
return f"{ctx.input_tokens} input tokens for {get_current_agent_model_ref()}{suffix}"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _window_telemetry(ctx: ContextWindow, char_budget: int) -> dict:
|
|
56
|
+
return {
|
|
57
|
+
"char_budget": char_budget,
|
|
58
|
+
"window_input_tokens": ctx.input_tokens,
|
|
59
|
+
"window_is_fallback": ctx.is_fallback,
|
|
60
|
+
"agent_model": get_current_agent_model_ref(),
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
49
64
|
class ClusterMethodsMixin:
|
|
50
65
|
"""
|
|
51
66
|
Mixin providing shared cluster-related functionality for agents.
|
|
@@ -156,10 +171,10 @@ class ClusterMethodsMixin:
|
|
|
156
171
|
ctx = get_current_agent_context_window()
|
|
157
172
|
msg = (
|
|
158
173
|
f"Prompt overhead ({prompt_overhead_chars} chars) consumes the entire agent input "
|
|
159
|
-
f"window ({ctx
|
|
174
|
+
f"window ({_describe_window(ctx)}); no room for cluster renderings."
|
|
160
175
|
)
|
|
161
176
|
logger.error("[CFG skip planner] %s", msg)
|
|
162
|
-
raise ContextBudgetExceededError(msg)
|
|
177
|
+
raise ContextBudgetExceededError(msg, telemetry_properties=_window_telemetry(ctx, char_budget))
|
|
163
178
|
|
|
164
179
|
langs_with_clusters = [l for l in programming_langs if cluster_results.get(l)]
|
|
165
180
|
if not langs_with_clusters:
|
|
@@ -240,14 +255,21 @@ class ClusterMethodsMixin:
|
|
|
240
255
|
rendered: _RenderedClusterString,
|
|
241
256
|
skip_sets: dict[str, set[str]],
|
|
242
257
|
) -> NoReturn:
|
|
258
|
+
ctx = get_current_agent_context_window()
|
|
243
259
|
per_lang_sizes = {lang: len(text) for lang, text in rendered.by_language.items()}
|
|
244
260
|
skipped_counts = {lang: len(skip) for lang, skip in skip_sets.items() if skip}
|
|
245
261
|
msg = (
|
|
246
|
-
f"Cluster render {len(rendered.text)} chars exceeds budget {char_budget}
|
|
262
|
+
f"Cluster render {len(rendered.text)} chars exceeds budget {char_budget} "
|
|
263
|
+
f"(agent window: {_describe_window(ctx)}). "
|
|
247
264
|
f"Per-language sizes: {per_lang_sizes}; skipped nodes: {skipped_counts}."
|
|
248
265
|
)
|
|
249
266
|
logger.error("[CFG skip planner] %s", msg)
|
|
250
|
-
|
|
267
|
+
telemetry = _window_telemetry(ctx, char_budget) | {
|
|
268
|
+
"render_chars": len(rendered.text),
|
|
269
|
+
"per_language_chars": per_lang_sizes,
|
|
270
|
+
"skipped_node_counts": skipped_counts,
|
|
271
|
+
}
|
|
272
|
+
raise ContextBudgetExceededError(msg, telemetry_properties=telemetry)
|
|
251
273
|
|
|
252
274
|
@staticmethod
|
|
253
275
|
def _cluster_prompt_budget(prompt_overhead_chars: int) -> int:
|
|
@@ -23,6 +23,8 @@ MONITORING_CALLBACK = MonitoringCallback(stats_container=RunStats())
|
|
|
23
23
|
|
|
24
24
|
logger = logging.getLogger(__name__)
|
|
25
25
|
|
|
26
|
+
_OPENROUTER_FALLBACK_CONTEXT_WINDOW = ContextWindow(1_048_576, 65_536, is_fallback=True)
|
|
27
|
+
|
|
26
28
|
# ---------------------------------------------------------------------------
|
|
27
29
|
# Module-level model overrides – set once by the orchestrator (main.py) and
|
|
28
30
|
# consumed by initialize_llms() without needing to thread the values through
|
|
@@ -67,6 +69,9 @@ class LLMConfig:
|
|
|
67
69
|
Configuration for LLM providers.
|
|
68
70
|
|
|
69
71
|
Attributes:
|
|
72
|
+
selection_envs: Env vars that select this provider — any one being set selects it.
|
|
73
|
+
api_key_env: Env var holding the provider's secret, or None when the
|
|
74
|
+
underlying SDK reads its credentials from the environment itself.
|
|
70
75
|
agent_model: The "agent" model used for complex reasoning and agentic tasks.
|
|
71
76
|
parsing_model: The "parsing" model used for fast, cost-effective extraction and parsing tasks.
|
|
72
77
|
agent_temperature: Temperature for the agent model. Defaults to 0 for deterministic behavior
|
|
@@ -77,23 +82,37 @@ class LLMConfig:
|
|
|
77
82
|
"""
|
|
78
83
|
|
|
79
84
|
chat_class: Type[BaseChatModel]
|
|
80
|
-
|
|
85
|
+
selection_envs: list[str]
|
|
81
86
|
agent_model: str
|
|
82
87
|
parsing_model: str
|
|
83
88
|
llm_type: LLMType
|
|
84
89
|
agent_temperature: float = LLMDefaults.DEFAULT_AGENT_TEMPERATURE
|
|
85
90
|
parsing_temperature: float = LLMDefaults.DEFAULT_PARSING_TEMPERATURE
|
|
86
91
|
extra_args: dict[str, Any] = field(default_factory=dict)
|
|
87
|
-
|
|
92
|
+
api_key_env: str | None = None
|
|
93
|
+
keyless_capable: bool = False
|
|
94
|
+
"""Whether this provider can run without a real API key.
|
|
95
|
+
|
|
96
|
+
True for self-hosted / OpenAI-compatible endpoints that accept
|
|
97
|
+
unauthenticated requests. When such a provider is the sole selected one
|
|
98
|
+
and no real key is set, key validation warns instead of failing, and the
|
|
99
|
+
client uses a placeholder.
|
|
100
|
+
"""
|
|
88
101
|
|
|
89
102
|
def get_api_key(self) -> str | None:
|
|
90
|
-
return os.getenv(self.api_key_env)
|
|
103
|
+
return os.getenv(self.api_key_env) if self.api_key_env else None
|
|
104
|
+
|
|
105
|
+
def has_real_api_key(self) -> bool:
|
|
106
|
+
"""True if the provider's API-key env var holds a value.
|
|
107
|
+
|
|
108
|
+
Distinct from ``is_selected_by_env()``: a keyless-capable provider can
|
|
109
|
+
be selected via a base-URL var while having no real key here.
|
|
110
|
+
"""
|
|
111
|
+
return bool(self.get_api_key())
|
|
91
112
|
|
|
92
|
-
def
|
|
93
|
-
"""
|
|
94
|
-
|
|
95
|
-
return True
|
|
96
|
-
return any(os.getenv(var) for var in self.alt_env_vars)
|
|
113
|
+
def is_selected_by_env(self) -> bool:
|
|
114
|
+
"""True when any of this provider's selection env vars is set."""
|
|
115
|
+
return any(os.getenv(var) for var in self.selection_envs)
|
|
97
116
|
|
|
98
117
|
def get_resolved_extra_args(self) -> dict[str, Any]:
|
|
99
118
|
resolved = {}
|
|
@@ -108,11 +127,12 @@ class LLMConfig:
|
|
|
108
127
|
LLM_PROVIDERS = {
|
|
109
128
|
"openai": LLMConfig(
|
|
110
129
|
chat_class=ChatOpenAI,
|
|
130
|
+
selection_envs=["OPENAI_API_KEY", "OPENAI_BASE_URL"],
|
|
111
131
|
api_key_env="OPENAI_API_KEY",
|
|
112
132
|
agent_model="gpt-4o",
|
|
113
133
|
parsing_model="gpt-4o-mini",
|
|
114
134
|
llm_type=LLMType.GPT4,
|
|
115
|
-
|
|
135
|
+
keyless_capable=True,
|
|
116
136
|
extra_args={
|
|
117
137
|
"base_url": lambda: os.getenv("OPENAI_BASE_URL"),
|
|
118
138
|
"max_tokens": None,
|
|
@@ -122,11 +142,11 @@ LLM_PROVIDERS = {
|
|
|
122
142
|
),
|
|
123
143
|
"vercel": LLMConfig(
|
|
124
144
|
chat_class=ChatOpenAI,
|
|
145
|
+
selection_envs=["VERCEL_API_KEY", "VERCEL_BASE_URL"],
|
|
125
146
|
api_key_env="VERCEL_API_KEY",
|
|
126
147
|
agent_model="google/gemini-3-flash",
|
|
127
148
|
parsing_model="openai/gpt-5-mini",
|
|
128
149
|
llm_type=LLMType.GEMINI_FLASH,
|
|
129
|
-
alt_env_vars=["VERCEL_BASE_URL"],
|
|
130
150
|
extra_args={
|
|
131
151
|
"base_url": lambda: os.getenv("VERCEL_BASE_URL", f"https://ai-gateway.vercel.sh/v1"),
|
|
132
152
|
"max_tokens": None,
|
|
@@ -136,6 +156,7 @@ LLM_PROVIDERS = {
|
|
|
136
156
|
),
|
|
137
157
|
"anthropic": LLMConfig(
|
|
138
158
|
chat_class=ChatAnthropic,
|
|
159
|
+
selection_envs=["ANTHROPIC_API_KEY"],
|
|
139
160
|
api_key_env="ANTHROPIC_API_KEY",
|
|
140
161
|
agent_model="claude-sonnet-4-6",
|
|
141
162
|
parsing_model="claude-haiku-4-5",
|
|
@@ -148,6 +169,7 @@ LLM_PROVIDERS = {
|
|
|
148
169
|
),
|
|
149
170
|
"google": LLMConfig(
|
|
150
171
|
chat_class=ChatGoogleGenerativeAI,
|
|
172
|
+
selection_envs=["GOOGLE_API_KEY"],
|
|
151
173
|
api_key_env="GOOGLE_API_KEY",
|
|
152
174
|
agent_model="gemini-3-flash-preview",
|
|
153
175
|
parsing_model="gemini-3.1-flash-lite",
|
|
@@ -160,7 +182,8 @@ LLM_PROVIDERS = {
|
|
|
160
182
|
),
|
|
161
183
|
"aws": LLMConfig(
|
|
162
184
|
chat_class=ChatBedrockConverse,
|
|
163
|
-
api_key_env
|
|
185
|
+
# No api_key_env: botocore reads AWS_BEARER_TOKEN_BEDROCK from the environment itself.
|
|
186
|
+
selection_envs=["AWS_BEARER_TOKEN_BEDROCK"],
|
|
164
187
|
agent_model="anthropic.claude-sonnet-4-6",
|
|
165
188
|
parsing_model="claude-haiku-4-5",
|
|
166
189
|
llm_type=LLMType.CLAUDE_SONNET,
|
|
@@ -172,6 +195,7 @@ LLM_PROVIDERS = {
|
|
|
172
195
|
),
|
|
173
196
|
"cerebras": LLMConfig(
|
|
174
197
|
chat_class=ChatCerebras,
|
|
198
|
+
selection_envs=["CEREBRAS_API_KEY"],
|
|
175
199
|
api_key_env="CEREBRAS_API_KEY",
|
|
176
200
|
agent_model="zai-glm-4.7",
|
|
177
201
|
parsing_model="gpt-oss-120b",
|
|
@@ -184,7 +208,11 @@ LLM_PROVIDERS = {
|
|
|
184
208
|
),
|
|
185
209
|
"ollama": LLMConfig(
|
|
186
210
|
chat_class=ChatOllama,
|
|
187
|
-
|
|
211
|
+
# OLLAMA_HOST is Ollama's canonical host var; the client falls back to it
|
|
212
|
+
# when no base_url is passed, and sends OLLAMA_API_KEY (Ollama cloud) itself.
|
|
213
|
+
selection_envs=["OLLAMA_BASE_URL", "OLLAMA_HOST"],
|
|
214
|
+
api_key_env="OLLAMA_API_KEY",
|
|
215
|
+
keyless_capable=True,
|
|
188
216
|
agent_model="qwen3:30b",
|
|
189
217
|
parsing_model="qwen2.5:7b",
|
|
190
218
|
llm_type=LLMType.GEMINI_FLASH,
|
|
@@ -196,11 +224,11 @@ LLM_PROVIDERS = {
|
|
|
196
224
|
),
|
|
197
225
|
"deepseek": LLMConfig(
|
|
198
226
|
chat_class=ChatOpenAI,
|
|
227
|
+
selection_envs=["DEEPSEEK_API_KEY", "DEEPSEEK_BASE_URL"],
|
|
199
228
|
api_key_env="DEEPSEEK_API_KEY",
|
|
200
229
|
agent_model="deepseek-chat",
|
|
201
230
|
parsing_model="deepseek-chat",
|
|
202
231
|
llm_type=LLMType.DEEPSEEK,
|
|
203
|
-
alt_env_vars=["DEEPSEEK_BASE_URL"],
|
|
204
232
|
extra_args={
|
|
205
233
|
"base_url": lambda: os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com/v1"),
|
|
206
234
|
"max_tokens": None,
|
|
@@ -210,11 +238,11 @@ LLM_PROVIDERS = {
|
|
|
210
238
|
),
|
|
211
239
|
"glm": LLMConfig(
|
|
212
240
|
chat_class=ChatOpenAI,
|
|
241
|
+
selection_envs=["GLM_API_KEY", "GLM_BASE_URL"],
|
|
213
242
|
api_key_env="GLM_API_KEY",
|
|
214
243
|
agent_model="glm-4.7-flash",
|
|
215
244
|
parsing_model="glm-4.7-flash",
|
|
216
245
|
llm_type=LLMType.GLM,
|
|
217
|
-
alt_env_vars=["GLM_BASE_URL"],
|
|
218
246
|
extra_args={
|
|
219
247
|
"base_url": lambda: os.getenv("GLM_BASE_URL", "https://open.bigmodel.cn/api/paas/v4"),
|
|
220
248
|
"max_tokens": None,
|
|
@@ -224,11 +252,11 @@ LLM_PROVIDERS = {
|
|
|
224
252
|
),
|
|
225
253
|
"kimi": LLMConfig(
|
|
226
254
|
chat_class=ChatOpenAI,
|
|
255
|
+
selection_envs=["KIMI_API_KEY", "KIMI_BASE_URL"],
|
|
227
256
|
api_key_env="KIMI_API_KEY",
|
|
228
257
|
agent_model="kimi-k2.5",
|
|
229
258
|
parsing_model="kimi-k2.5",
|
|
230
259
|
llm_type=LLMType.KIMI,
|
|
231
|
-
alt_env_vars=["KIMI_BASE_URL"],
|
|
232
260
|
extra_args={
|
|
233
261
|
"base_url": lambda: os.getenv("KIMI_BASE_URL", "https://api.moonshot.cn/v1"),
|
|
234
262
|
"max_tokens": None,
|
|
@@ -238,6 +266,7 @@ LLM_PROVIDERS = {
|
|
|
238
266
|
),
|
|
239
267
|
"openrouter": LLMConfig(
|
|
240
268
|
chat_class=ChatOpenAI,
|
|
269
|
+
selection_envs=["OPENROUTER_API_KEY"],
|
|
241
270
|
api_key_env="OPENROUTER_API_KEY",
|
|
242
271
|
agent_model="google/gemini-3-flash-preview",
|
|
243
272
|
parsing_model="google/gemini-3-flash-preview",
|
|
@@ -249,9 +278,45 @@ LLM_PROVIDERS = {
|
|
|
249
278
|
"max_retries": 0,
|
|
250
279
|
},
|
|
251
280
|
),
|
|
281
|
+
"litellm": LLMConfig(
|
|
282
|
+
chat_class=ChatOpenAI,
|
|
283
|
+
# Base URL only: a key alone must not select litellm, since there is no
|
|
284
|
+
# universal proxy endpoint to default to.
|
|
285
|
+
selection_envs=["LITELLM_BASE_URL"],
|
|
286
|
+
api_key_env="LITELLM_API_KEY",
|
|
287
|
+
agent_model="gpt-4o",
|
|
288
|
+
parsing_model="gpt-4o-mini",
|
|
289
|
+
llm_type=LLMType.GPT4,
|
|
290
|
+
keyless_capable=True,
|
|
291
|
+
extra_args={
|
|
292
|
+
"base_url": lambda: os.getenv("LITELLM_BASE_URL"),
|
|
293
|
+
"max_tokens": None,
|
|
294
|
+
"timeout": None,
|
|
295
|
+
"max_retries": 0,
|
|
296
|
+
},
|
|
297
|
+
),
|
|
252
298
|
}
|
|
253
299
|
|
|
254
300
|
|
|
301
|
+
def _all_selection_envs() -> list[str]:
|
|
302
|
+
return sorted({var for config in LLM_PROVIDERS.values() for var in config.selection_envs})
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _unselected_key_hints() -> list[str]:
|
|
306
|
+
"""Messages for providers whose API key is set but which nothing selects."""
|
|
307
|
+
return [
|
|
308
|
+
f"{config.api_key_env} is set, but the '{name}' provider is selected by "
|
|
309
|
+
f"{' or '.join(config.selection_envs)}."
|
|
310
|
+
for name, config in LLM_PROVIDERS.items()
|
|
311
|
+
if config.has_real_api_key() and not config.is_selected_by_env()
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def selected_providers() -> list[str]:
|
|
316
|
+
"""Names of providers the environment currently selects."""
|
|
317
|
+
return [name for name, config in LLM_PROVIDERS.items() if config.is_selected_by_env()]
|
|
318
|
+
|
|
319
|
+
|
|
255
320
|
def _initialize_llm(
|
|
256
321
|
model_override: str | None,
|
|
257
322
|
model_attr: str,
|
|
@@ -259,16 +324,10 @@ def _initialize_llm(
|
|
|
259
324
|
log_prefix: str,
|
|
260
325
|
init_factory: bool = False,
|
|
261
326
|
) -> tuple[BaseChatModel, str]:
|
|
262
|
-
resolved =
|
|
327
|
+
resolved = _resolve_selected_provider(model_override, model_attr)
|
|
263
328
|
if resolved is None:
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
required_vars.append(config.api_key_env)
|
|
267
|
-
required_vars.extend(config.alt_env_vars)
|
|
268
|
-
|
|
269
|
-
raise ValueError(
|
|
270
|
-
f"No valid LLM configuration found. Please set one of: {', '.join(sorted(set(required_vars)))}"
|
|
271
|
-
)
|
|
329
|
+
message = f"No valid LLM configuration found. Please set one of: {', '.join(_all_selection_envs())}."
|
|
330
|
+
raise ValueError(" ".join([message, *_unselected_key_hints()]))
|
|
272
331
|
|
|
273
332
|
name, config, model_name = resolved
|
|
274
333
|
|
|
@@ -288,6 +347,8 @@ def _initialize_llm(
|
|
|
288
347
|
}
|
|
289
348
|
kwargs.update(config.get_resolved_extra_args())
|
|
290
349
|
|
|
350
|
+
# ChatBedrockConverse and ChatOllama take no api_key kwarg; their SDKs read
|
|
351
|
+
# AWS_BEARER_TOKEN_BEDROCK / OLLAMA_API_KEY from the environment directly.
|
|
291
352
|
if name not in ["aws", "ollama"]:
|
|
292
353
|
api_key = config.get_api_key()
|
|
293
354
|
kwargs["api_key"] = api_key or "no-key-required"
|
|
@@ -296,13 +357,13 @@ def _initialize_llm(
|
|
|
296
357
|
return model, model_name
|
|
297
358
|
|
|
298
359
|
|
|
299
|
-
def
|
|
360
|
+
def _resolve_selected_provider(
|
|
300
361
|
model_override: str | None,
|
|
301
362
|
model_attr: str,
|
|
302
363
|
) -> tuple[str, LLMConfig, str] | None:
|
|
303
|
-
"""Return the
|
|
364
|
+
"""Return the selected provider, config, and resolved model name."""
|
|
304
365
|
for name, config in LLM_PROVIDERS.items():
|
|
305
|
-
if not config.
|
|
366
|
+
if not config.is_selected_by_env():
|
|
306
367
|
continue
|
|
307
368
|
return name, config, model_override or getattr(config, model_attr)
|
|
308
369
|
return None
|
|
@@ -313,13 +374,36 @@ class LLMConfigError(ValueError):
|
|
|
313
374
|
|
|
314
375
|
|
|
315
376
|
def validate_api_key_provided() -> None:
|
|
316
|
-
"""Raise LLMConfigError
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
377
|
+
"""Raise LLMConfigError unless exactly one LLM provider is selected.
|
|
378
|
+
|
|
379
|
+
A provider is selected when any of its ``selection_envs`` is set. Keyless-
|
|
380
|
+
capable providers (self-hosted / OpenAI-compatible endpoints, e.g. an
|
|
381
|
+
``OPENAI_BASE_URL`` with no key) are therefore valid: they are selected by
|
|
382
|
+
their base URL, and the client falls back to a placeholder key downstream.
|
|
383
|
+
In that case we log a warning rather than fail. Ambiguity detection (more
|
|
384
|
+
than one selected provider) is preserved so a stray second key is still
|
|
385
|
+
surfaced, and a key set for an unselected provider (e.g. LITELLM_API_KEY
|
|
386
|
+
without LITELLM_BASE_URL) is reported rather than silently ignored.
|
|
387
|
+
"""
|
|
388
|
+
hints = _unselected_key_hints()
|
|
389
|
+
selected = selected_providers()
|
|
390
|
+
if not selected:
|
|
391
|
+
message = f"No LLM provider selected. Set one of: {', '.join(_all_selection_envs())}."
|
|
392
|
+
raise LLMConfigError(" ".join([message, *hints]))
|
|
393
|
+
if len(selected) > 1:
|
|
394
|
+
raise LLMConfigError(f"Multiple LLM providers selected ({', '.join(selected)}); please set only one.")
|
|
395
|
+
for hint in hints:
|
|
396
|
+
logger.warning(hint)
|
|
397
|
+
|
|
398
|
+
(name,) = selected
|
|
399
|
+
config = LLM_PROVIDERS[name]
|
|
400
|
+
if config.keyless_capable and not config.has_real_api_key():
|
|
401
|
+
logger.warning(
|
|
402
|
+
"Provider '%s' is selected via a base URL with no %s set; "
|
|
403
|
+
"treating as a keyless local endpoint (a placeholder key is used).",
|
|
404
|
+
name,
|
|
405
|
+
config.api_key_env,
|
|
406
|
+
)
|
|
323
407
|
|
|
324
408
|
|
|
325
409
|
def initialize_agent_llm(model_override: str | None = None) -> BaseChatModel:
|
|
@@ -329,17 +413,29 @@ def initialize_agent_llm(model_override: str | None = None) -> BaseChatModel:
|
|
|
329
413
|
|
|
330
414
|
|
|
331
415
|
def get_current_agent_context_window() -> ContextWindow:
|
|
332
|
-
"""Context window for the currently
|
|
416
|
+
"""Context window for the currently selected agent provider/model.
|
|
333
417
|
|
|
334
|
-
Resolves the first
|
|
418
|
+
Resolves the first selected provider (same rule as ``_initialize_llm``) on
|
|
335
419
|
every call. ``get_context_window`` handles its own caching, so this is
|
|
336
420
|
cheap enough to call without a module-level cache.
|
|
337
421
|
"""
|
|
338
|
-
resolved =
|
|
422
|
+
resolved = _resolve_selected_provider(_agent_model_override or os.getenv("AGENT_MODEL"), "agent_model")
|
|
339
423
|
if resolved is not None:
|
|
340
424
|
name, _config, model_name = resolved
|
|
341
|
-
|
|
342
|
-
|
|
425
|
+
ctx = get_context_window(name, model_name)
|
|
426
|
+
if name == "openrouter" and ctx.is_fallback:
|
|
427
|
+
return _OPENROUTER_FALLBACK_CONTEXT_WINDOW
|
|
428
|
+
return ctx
|
|
429
|
+
return ContextWindow(ModelCapabilities.FALLBACK_INPUT, ModelCapabilities.FALLBACK_OUTPUT, is_fallback=True)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def get_current_agent_model_ref() -> str:
|
|
433
|
+
"""``provider/model`` for the currently active agent LLM, or ``"unknown"``."""
|
|
434
|
+
resolved = _resolve_selected_provider(_agent_model_override or os.getenv("AGENT_MODEL"), "agent_model")
|
|
435
|
+
if resolved is None:
|
|
436
|
+
return "unknown"
|
|
437
|
+
name, _config, model_name = resolved
|
|
438
|
+
return f"{name}/{model_name}"
|
|
343
439
|
|
|
344
440
|
|
|
345
441
|
def initialize_parsing_llm(model_override: str | None = None) -> BaseChatModel:
|
|
@@ -24,6 +24,7 @@ _OLLAMA_CACHE: dict[tuple[str, str], tuple[int, int]] = {}
|
|
|
24
24
|
class ContextWindow:
|
|
25
25
|
input_tokens: int
|
|
26
26
|
output_tokens: int
|
|
27
|
+
is_fallback: bool = False
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
def get_context_window(provider: str, model_name: str) -> ContextWindow:
|
|
@@ -40,7 +41,7 @@ def get_context_window(provider: str, model_name: str) -> ContextWindow:
|
|
|
40
41
|
if hit is not None:
|
|
41
42
|
return ContextWindow(*hit)
|
|
42
43
|
logger.warning(f"No context window for {provider}/{model_name}; using fallback {ModelCapabilities.FALLBACK_INPUT}")
|
|
43
|
-
return ContextWindow(ModelCapabilities.FALLBACK_INPUT, ModelCapabilities.FALLBACK_OUTPUT)
|
|
44
|
+
return ContextWindow(ModelCapabilities.FALLBACK_INPUT, ModelCapabilities.FALLBACK_OUTPUT, is_fallback=True)
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
def _resolve_env(provider: str, model_name: str) -> tuple[int, int] | None:
|
|
@@ -81,9 +82,12 @@ def _user_context_window_override() -> int | None:
|
|
|
81
82
|
def _resolve_ollama(provider: str, model_name: str) -> tuple[int, int] | None:
|
|
82
83
|
if provider != "ollama":
|
|
83
84
|
return None
|
|
84
|
-
base = os.getenv("OLLAMA_BASE_URL")
|
|
85
|
+
base = os.getenv("OLLAMA_BASE_URL") or os.getenv("OLLAMA_HOST")
|
|
85
86
|
if not base:
|
|
86
87
|
return None
|
|
88
|
+
if "://" not in base:
|
|
89
|
+
# OLLAMA_HOST conventionally allows bare host:port.
|
|
90
|
+
base = f"http://{base}"
|
|
87
91
|
return _ollama_show(model_name, base.rstrip("/"))
|
|
88
92
|
|
|
89
93
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeboarding
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.2
|
|
4
4
|
Summary: Interactive Diagrams for Code
|
|
5
5
|
Author: CodeBoarding Team
|
|
6
6
|
License-Expression: MIT
|
|
@@ -40,6 +40,8 @@ Requires-Dist: markitdown>=0.1
|
|
|
40
40
|
Requires-Dist: networkx>=3.4
|
|
41
41
|
Requires-Dist: nodeenv>=1.10.0
|
|
42
42
|
Requires-Dist: pathspec>=0.12
|
|
43
|
+
Requires-Dist: posthog>=3.7
|
|
44
|
+
Requires-Dist: pydantic>=2.0
|
|
43
45
|
Requires-Dist: pyyaml>=6.0
|
|
44
46
|
Requires-Dist: regex>=2024.11
|
|
45
47
|
Requires-Dist: rich>=12.6
|
|
@@ -93,15 +95,17 @@ Dynamic: license-file
|
|
|
93
95
|
The recommended way to install the CLI is with [pipx](https://pipx.pypa.io), which automatically creates an isolated environment:
|
|
94
96
|
|
|
95
97
|
```bash
|
|
96
|
-
pipx install codeboarding --python python3.12
|
|
98
|
+
pipx install codeboarding --python python3.12 --pip-args="--extra-index-url https://pip.codeboarding.org/simple/"
|
|
97
99
|
```
|
|
98
100
|
|
|
99
101
|
Alternatively, install into an existing virtual environment with pip:
|
|
100
102
|
|
|
101
103
|
```bash
|
|
102
|
-
pip install codeboarding
|
|
104
|
+
pip install codeboarding --extra-index-url https://pip.codeboarding.org/simple/
|
|
103
105
|
```
|
|
104
106
|
|
|
107
|
+
|
|
108
|
+
|
|
105
109
|
> Installing into the global Python environment with `pip` is not recommended — it can cause dependency conflicts and will fail if the system Python is not 3.12 or 3.13.
|
|
106
110
|
|
|
107
111
|
Language server binaries are downloaded automatically on first use. To pre-install them explicitly (useful in CI or restricted environments):
|
|
@@ -3,6 +3,7 @@ PYPI.md
|
|
|
3
3
|
README.md
|
|
4
4
|
constants.py
|
|
5
5
|
github_action.py
|
|
6
|
+
health_main.py
|
|
6
7
|
install.py
|
|
7
8
|
logging_config.py
|
|
8
9
|
main.py
|
|
@@ -126,6 +127,7 @@ static_analyzer/cluster_helpers.py
|
|
|
126
127
|
static_analyzer/cluster_relations.py
|
|
127
128
|
static_analyzer/constants.py
|
|
128
129
|
static_analyzer/csharp_config_scanner.py
|
|
130
|
+
static_analyzer/dotnet_sdk.py
|
|
129
131
|
static_analyzer/graph.py
|
|
130
132
|
static_analyzer/incremental_orchestrator.py
|
|
131
133
|
static_analyzer/java_config_scanner.py
|
|
@@ -162,6 +164,11 @@ static_analyzer/engine/adapters/rust_adapter.py
|
|
|
162
164
|
static_analyzer/engine/adapters/typescript_adapter.py
|
|
163
165
|
static_analyzer/lsp_client/__init__.py
|
|
164
166
|
static_analyzer/lsp_client/diagnostics.py
|
|
167
|
+
telemetry/__init__.py
|
|
168
|
+
telemetry/device_id.py
|
|
169
|
+
telemetry/events.py
|
|
170
|
+
telemetry/schemas.py
|
|
171
|
+
telemetry/service.py
|
|
165
172
|
tests/test_cli_parser.py
|
|
166
173
|
tests/test_github_action.py
|
|
167
174
|
tests/test_install.py
|
|
@@ -169,6 +176,7 @@ tests/test_logging_config.py
|
|
|
169
176
|
tests/test_main.py
|
|
170
177
|
tests/test_pyproject_packages.py
|
|
171
178
|
tests/test_registry_coverage.py
|
|
179
|
+
tests/test_telemetry_events.py
|
|
172
180
|
tests/test_tool_registry.py
|
|
173
181
|
tests/test_user_config.py
|
|
174
182
|
tests/test_vscode_constants.py
|