codeboarding 0.10.1__tar.gz → 0.10.3__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.10.1/codeboarding.egg-info → codeboarding-0.10.3}/PKG-INFO +2 -1
- {codeboarding-0.10.1 → codeboarding-0.10.3}/README.md +4 -2
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/agent.py +5 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/agent_responses.py +5 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/cluster_methods_mixin.py +26 -6
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/llm_config.py +2 -2
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/meta_agent.py +0 -1
- {codeboarding-0.10.1 → codeboarding-0.10.3/codeboarding.egg-info}/PKG-INFO +2 -1
- {codeboarding-0.10.1 → codeboarding-0.10.3}/codeboarding.egg-info/SOURCES.txt +10 -3
- {codeboarding-0.10.1 → codeboarding-0.10.3}/codeboarding.egg-info/requires.txt +1 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/diagram_analysis/__init__.py +0 -1
- {codeboarding-0.10.1 → codeboarding-0.10.3}/diagram_analysis/diagram_generator.py +0 -27
- {codeboarding-0.10.1 → codeboarding-0.10.3}/diagram_analysis/incremental_updater.py +80 -19
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/checks/unused_code_diagnostics.py +13 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/install.py +265 -72
- {codeboarding-0.10.1 → codeboarding-0.10.3}/main.py +2 -2
- {codeboarding-0.10.1 → codeboarding-0.10.3}/pyproject.toml +6 -3
- {codeboarding-0.10.1 → codeboarding-0.10.3}/repo_utils/ignore.py +9 -2
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/__init__.py +134 -11
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/analysis_cache.py +2 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/cluster_helpers.py +46 -23
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/constants.py +8 -10
- codeboarding-0.10.3/static_analyzer/csharp_config_scanner.py +96 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/adapters/__init__.py +4 -0
- codeboarding-0.10.3/static_analyzer/engine/adapters/csharp_adapter.py +222 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/adapters/go_adapter.py +15 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/adapters/java_adapter.py +14 -9
- codeboarding-0.10.3/static_analyzer/engine/adapters/rust_adapter.py +189 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/call_graph_builder.py +50 -40
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/language_adapter.py +79 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/lsp_client.py +125 -18
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/result_converter.py +2 -1
- codeboarding-0.10.3/static_analyzer/engine/utils.py +68 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/graph.py +68 -8
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/incremental_orchestrator.py +1 -1
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/java_utils.py +18 -1
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/node.py +2 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/tests/test_install.py +67 -0
- codeboarding-0.10.3/tests/test_registry_coverage.py +396 -0
- codeboarding-0.10.3/tests/test_tool_registry.py +1647 -0
- codeboarding-0.10.3/tests/test_windows_compatibility.py +61 -0
- codeboarding-0.10.3/tool_registry/__init__.py +72 -0
- codeboarding-0.10.3/tool_registry/installers.py +628 -0
- codeboarding-0.10.3/tool_registry/manifest.py +347 -0
- codeboarding-0.10.3/tool_registry/paths.py +264 -0
- codeboarding-0.10.3/tool_registry/registry.py +274 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/vscode_constants.py +19 -0
- codeboarding-0.10.1/diagram_analysis/manifest.py +0 -153
- codeboarding-0.10.1/static_analyzer/engine/utils.py +0 -22
- codeboarding-0.10.1/tests/test_tool_registry.py +0 -94
- codeboarding-0.10.1/tests/test_windows_compatibility.py +0 -53
- codeboarding-0.10.1/tool_registry.py +0 -577
- {codeboarding-0.10.1 → codeboarding-0.10.3}/LICENSE +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/PYPI.md +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/abstraction_agent.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/change_status.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/constants.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/dependency_discovery.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/details_agent.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/planner_agent.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/prompts/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/prompts/abstract_prompt_factory.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/prompts/claude_prompts.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/prompts/deepseek_prompts.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/prompts/gemini_flash_prompts.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/prompts/glm_prompts.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/prompts/gpt_prompts.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/prompts/kimi_prompts.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/prompts/prompt_factory.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/base.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/get_external_deps.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/get_method_invocations.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/read_cfg.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/read_docs.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/read_file.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/read_file_structure.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/read_git_diff.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/read_packages.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/read_source.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/read_structure.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/tools/toolkit.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/agents/validation.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/caching/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/caching/cache.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/caching/details_cache.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/caching/meta_cache.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/codeboarding.egg-info/dependency_links.txt +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/codeboarding.egg-info/entry_points.txt +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/codeboarding.egg-info/top_level.txt +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/constants.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/core/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/core/plugin_loader.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/core/protocols.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/core/registry.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/diagram_analysis/analysis_json.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/diagram_analysis/file_coverage.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/diagram_analysis/incremental_types.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/diagram_analysis/io_utils.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/diagram_analysis/run_context.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/diagram_analysis/version.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/duckdb_crud.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/github_action.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/checks/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/checks/circular_deps.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/checks/cohesion.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/checks/coupling.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/checks/function_size.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/checks/god_class.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/checks/inheritance.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/checks/instability.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/config.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/constants.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/models.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health/runner.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/health_main.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/logging_config.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/monitoring/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/monitoring/callbacks.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/monitoring/context.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/monitoring/mixin.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/monitoring/paths.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/monitoring/stats.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/monitoring/writers.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/output_generators/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/output_generators/html.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/output_generators/html_template.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/output_generators/markdown.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/output_generators/mdx.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/output_generators/sphinx.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/repo_utils/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/repo_utils/change_detector.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/repo_utils/errors.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/repo_utils/git_diff.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/repo_utils/method_diff.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/setup.cfg +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/analysis_result.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/cluster_change_analyzer.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/cluster_relations.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/adapters/php_adapter.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/adapters/python_adapter.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/adapters/typescript_adapter.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/edge_build_context.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/edge_builder.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/hierarchy_builder.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/lsp_constants.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/models.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/progress.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/protocols.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/source_inspector.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/engine/symbol_table.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/git_diff_analyzer.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/java_config_scanner.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/lsp_client/__init__.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/lsp_client/diagnostics.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/programming_language.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/reference_resolve_mixin.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/scanner.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/static_analyzer/typescript_config_scanner.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/tests/test_github_action.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/tests/test_logging_config.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/tests/test_main.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/tests/test_pyproject_packages.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/tests/test_user_config.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/tests/test_vscode_constants.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/tests/test_windows_encoding.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/user_config.py +0 -0
- {codeboarding-0.10.1 → codeboarding-0.10.3}/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeboarding
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.3
|
|
4
4
|
Summary: Interactive Diagrams for Code
|
|
5
5
|
Author: CodeBoarding Team
|
|
6
6
|
License-Expression: MIT
|
|
@@ -37,6 +37,7 @@ Requires-Dist: markdown>=3.8
|
|
|
37
37
|
Requires-Dist: markdown-it-py>=3.0
|
|
38
38
|
Requires-Dist: markitdown>=0.1
|
|
39
39
|
Requires-Dist: networkx>=3.4
|
|
40
|
+
Requires-Dist: nodeenv>=1.10.0
|
|
40
41
|
Requires-Dist: pathspec>=0.12
|
|
41
42
|
Requires-Dist: pyyaml>=6.0
|
|
42
43
|
Requires-Dist: regex>=2024.11
|
|
@@ -16,6 +16,8 @@ Install the extension from Open VSX.
|
|
|
16
16
|
[](https://www.python.org/)
|
|
17
17
|
[](https://go.dev/)
|
|
18
18
|
[](https://www.php.net/)
|
|
19
|
+
[](https://www.rust-lang.org/)
|
|
20
|
+
[](https://learn.microsoft.com/en-us/dotnet/csharp/)
|
|
19
21
|
|
|
20
22
|
## Few use cases:
|
|
21
23
|
|
|
@@ -91,7 +93,7 @@ codeboarding --local /path/to/repo
|
|
|
91
93
|
|
|
92
94
|
Output is written to `/path/to/repo/.codeboarding/`.
|
|
93
95
|
|
|
94
|
-
`python install.py` and `codeboarding-setup` download language server binaries to `~/.codeboarding/servers/`, shared across projects. `npm` is required for Python, TypeScript, JavaScript, and PHP language servers; if
|
|
96
|
+
`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.
|
|
95
97
|
|
|
96
98
|
## Configuration
|
|
97
99
|
|
|
@@ -141,7 +143,7 @@ python main.py https://github.com/pytorch/pytorch
|
|
|
141
143
|
|
|
142
144
|
## Supported stack
|
|
143
145
|
|
|
144
|
-
- Languages: Python, TypeScript, JavaScript, Java, Go, PHP.
|
|
146
|
+
- Languages: Python, TypeScript, JavaScript, Java, Go, PHP, Rust.
|
|
145
147
|
- LLM providers: OpenAI, Anthropic, Google, Vercel AI Gateway, AWS Bedrock, Ollama, OpenRouter, and more.
|
|
146
148
|
|
|
147
149
|
## Examples
|
|
@@ -160,6 +160,11 @@ class CodeBoardingAgent(ReferenceResolverMixin, MonitoringMixin):
|
|
|
160
160
|
raise
|
|
161
161
|
|
|
162
162
|
except Exception as e:
|
|
163
|
+
# HTTP 404 (e.g. retired model ID) is permanent — retrying won't help.
|
|
164
|
+
if getattr(e, "status_code", None) == 404:
|
|
165
|
+
logger.error(f"Permanent HTTP 404 — not retrying: {type(e).__name__}: {e}")
|
|
166
|
+
raise
|
|
167
|
+
|
|
163
168
|
# Other errors (network, parsing, etc.) get standard exponential backoff
|
|
164
169
|
if attempt < max_retries - 1:
|
|
165
170
|
delay = min(10 * (2**attempt), 120)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
import logging
|
|
3
3
|
from abc import abstractmethod
|
|
4
|
+
from pathlib import PurePosixPath
|
|
4
5
|
from typing import get_origin, Optional
|
|
5
6
|
|
|
6
7
|
from pydantic import BaseModel, Field
|
|
@@ -261,6 +262,10 @@ class AnalysisInsights(LLMBaseModel):
|
|
|
261
262
|
relations = "\n".join(cr.llm_str() for cr in self.components_relations)
|
|
262
263
|
return title + body + relations
|
|
263
264
|
|
|
265
|
+
def file_to_component(self) -> dict[str, str]:
|
|
266
|
+
"""Build file path -> component_id mapping from root components."""
|
|
267
|
+
return {str(PurePosixPath(fg.file_path)): c.component_id for c in self.components for fg in c.file_methods}
|
|
268
|
+
|
|
264
269
|
|
|
265
270
|
def assign_component_ids(analysis: AnalysisInsights, parent_id: str = "") -> None:
|
|
266
271
|
"""Assign hierarchical component IDs based on sibling index.
|
|
@@ -16,8 +16,11 @@ from agents.agent_responses import (
|
|
|
16
16
|
from constants import MIN_CLUSTERS_THRESHOLD
|
|
17
17
|
from static_analyzer.analysis_result import StaticAnalysisResults
|
|
18
18
|
from static_analyzer.cluster_helpers import (
|
|
19
|
+
MAX_LLM_CLUSTERS,
|
|
20
|
+
enforce_cross_language_budget,
|
|
19
21
|
get_all_cluster_ids,
|
|
20
22
|
get_files_for_cluster_ids,
|
|
23
|
+
merge_clusters,
|
|
21
24
|
)
|
|
22
25
|
from static_analyzer.cluster_relations import (
|
|
23
26
|
build_component_relations,
|
|
@@ -250,7 +253,6 @@ class ClusterMethodsMixin:
|
|
|
250
253
|
abs_path = os.path.join(self.repo_dir, f) if not os.path.isabs(f) else f
|
|
251
254
|
assigned_file_set.add(abs_path)
|
|
252
255
|
|
|
253
|
-
result_parts = []
|
|
254
256
|
cluster_results: dict[str, ClusterResult] = {}
|
|
255
257
|
subgraph_cfgs: dict[str, CallGraph] = {}
|
|
256
258
|
|
|
@@ -266,15 +268,33 @@ class ClusterMethodsMixin:
|
|
|
266
268
|
# Calculate clusters for the subgraph
|
|
267
269
|
sub_cluster_result = sub_cfg.cluster()
|
|
268
270
|
|
|
271
|
+
# Merge into super-clusters if too many (same limit as AbstractionAgent)
|
|
272
|
+
if len(sub_cluster_result.clusters) > MAX_LLM_CLUSTERS:
|
|
273
|
+
n_before = len(sub_cluster_result.clusters)
|
|
274
|
+
sub_cluster_result = merge_clusters(sub_cluster_result, sub_cfg.to_networkx(), MAX_LLM_CLUSTERS)
|
|
275
|
+
logger.info(
|
|
276
|
+
f"[DetailsAgent] Subgraph for '{component.name}': "
|
|
277
|
+
f"merged {n_before} -> {len(sub_cluster_result.clusters)} super-clusters"
|
|
278
|
+
)
|
|
279
|
+
|
|
269
280
|
# Expand to method-level if insufficient clusters
|
|
270
281
|
sub_cluster_result = self._expand_to_method_level_clusters(sub_cfg, sub_cluster_result)
|
|
271
282
|
cluster_results[lang] = sub_cluster_result
|
|
272
283
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
284
|
+
# Cross-language: enforce combined budget and unique IDs
|
|
285
|
+
if len(cluster_results) > 1:
|
|
286
|
+
cfg_nx = {lang: subgraph_cfgs[lang].to_networkx() for lang in cluster_results}
|
|
287
|
+
enforce_cross_language_budget(cluster_results, cfg_nx)
|
|
288
|
+
|
|
289
|
+
result_parts = []
|
|
290
|
+
for lang in self.static_analysis.get_languages():
|
|
291
|
+
if lang not in cluster_results:
|
|
292
|
+
continue
|
|
293
|
+
cluster_str = subgraph_cfgs[lang].to_cluster_string(cluster_result=cluster_results[lang])
|
|
294
|
+
if cluster_str.strip() and cluster_str not in ("empty", "none", "No clusters found."):
|
|
295
|
+
result_parts.append(f"\n## {lang.capitalize()} - Component CFG\n")
|
|
296
|
+
result_parts.append(cluster_str)
|
|
297
|
+
result_parts.append("\n")
|
|
278
298
|
|
|
279
299
|
result = "".join(result_parts)
|
|
280
300
|
|
|
@@ -136,7 +136,7 @@ LLM_PROVIDERS = {
|
|
|
136
136
|
"anthropic": LLMConfig(
|
|
137
137
|
chat_class=ChatAnthropic,
|
|
138
138
|
api_key_env="ANTHROPIC_API_KEY",
|
|
139
|
-
agent_model="claude-
|
|
139
|
+
agent_model="claude-sonnet-4-5-20250929",
|
|
140
140
|
parsing_model="claude-3-haiku-20240307",
|
|
141
141
|
llm_type=LLMType.CLAUDE,
|
|
142
142
|
extra_args={
|
|
@@ -160,7 +160,7 @@ LLM_PROVIDERS = {
|
|
|
160
160
|
"aws": LLMConfig(
|
|
161
161
|
chat_class=ChatBedrockConverse,
|
|
162
162
|
api_key_env="AWS_BEARER_TOKEN_BEDROCK", # Used for existence check
|
|
163
|
-
agent_model="us.anthropic.claude-
|
|
163
|
+
agent_model="us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
|
164
164
|
parsing_model="us.anthropic.claude-3-haiku-20240307-v1:0",
|
|
165
165
|
llm_type=LLMType.CLAUDE,
|
|
166
166
|
extra_args={
|
|
@@ -46,7 +46,6 @@ class MetaAgent(CodeBoardingAgent):
|
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
self._meta_cache = MetaCache(repo_dir=repo_dir, ignore_manager=self.ignore_manager)
|
|
49
|
-
self._cache = self._meta_cache # Backward-compatible alias for tests/callers.
|
|
50
49
|
|
|
51
50
|
@trace
|
|
52
51
|
def analyze_project_metadata(self, skip_cache: bool = False) -> MetaAnalysisInsights:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeboarding
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.3
|
|
4
4
|
Summary: Interactive Diagrams for Code
|
|
5
5
|
Author: CodeBoarding Team
|
|
6
6
|
License-Expression: MIT
|
|
@@ -37,6 +37,7 @@ Requires-Dist: markdown>=3.8
|
|
|
37
37
|
Requires-Dist: markdown-it-py>=3.0
|
|
38
38
|
Requires-Dist: markitdown>=0.1
|
|
39
39
|
Requires-Dist: networkx>=3.4
|
|
40
|
+
Requires-Dist: nodeenv>=1.10.0
|
|
40
41
|
Requires-Dist: pathspec>=0.12
|
|
41
42
|
Requires-Dist: pyyaml>=6.0
|
|
42
43
|
Requires-Dist: regex>=2024.11
|
|
@@ -9,7 +9,6 @@ install.py
|
|
|
9
9
|
logging_config.py
|
|
10
10
|
main.py
|
|
11
11
|
pyproject.toml
|
|
12
|
-
tool_registry.py
|
|
13
12
|
user_config.py
|
|
14
13
|
utils.py
|
|
15
14
|
vscode_constants.py
|
|
@@ -69,7 +68,6 @@ diagram_analysis/file_coverage.py
|
|
|
69
68
|
diagram_analysis/incremental_types.py
|
|
70
69
|
diagram_analysis/incremental_updater.py
|
|
71
70
|
diagram_analysis/io_utils.py
|
|
72
|
-
diagram_analysis/manifest.py
|
|
73
71
|
diagram_analysis/run_context.py
|
|
74
72
|
diagram_analysis/version.py
|
|
75
73
|
health/__init__.py
|
|
@@ -112,6 +110,7 @@ static_analyzer/cluster_change_analyzer.py
|
|
|
112
110
|
static_analyzer/cluster_helpers.py
|
|
113
111
|
static_analyzer/cluster_relations.py
|
|
114
112
|
static_analyzer/constants.py
|
|
113
|
+
static_analyzer/csharp_config_scanner.py
|
|
115
114
|
static_analyzer/git_diff_analyzer.py
|
|
116
115
|
static_analyzer/graph.py
|
|
117
116
|
static_analyzer/incremental_orchestrator.py
|
|
@@ -138,10 +137,12 @@ static_analyzer/engine/source_inspector.py
|
|
|
138
137
|
static_analyzer/engine/symbol_table.py
|
|
139
138
|
static_analyzer/engine/utils.py
|
|
140
139
|
static_analyzer/engine/adapters/__init__.py
|
|
140
|
+
static_analyzer/engine/adapters/csharp_adapter.py
|
|
141
141
|
static_analyzer/engine/adapters/go_adapter.py
|
|
142
142
|
static_analyzer/engine/adapters/java_adapter.py
|
|
143
143
|
static_analyzer/engine/adapters/php_adapter.py
|
|
144
144
|
static_analyzer/engine/adapters/python_adapter.py
|
|
145
|
+
static_analyzer/engine/adapters/rust_adapter.py
|
|
145
146
|
static_analyzer/engine/adapters/typescript_adapter.py
|
|
146
147
|
static_analyzer/lsp_client/__init__.py
|
|
147
148
|
static_analyzer/lsp_client/diagnostics.py
|
|
@@ -150,8 +151,14 @@ tests/test_install.py
|
|
|
150
151
|
tests/test_logging_config.py
|
|
151
152
|
tests/test_main.py
|
|
152
153
|
tests/test_pyproject_packages.py
|
|
154
|
+
tests/test_registry_coverage.py
|
|
153
155
|
tests/test_tool_registry.py
|
|
154
156
|
tests/test_user_config.py
|
|
155
157
|
tests/test_vscode_constants.py
|
|
156
158
|
tests/test_windows_compatibility.py
|
|
157
|
-
tests/test_windows_encoding.py
|
|
159
|
+
tests/test_windows_encoding.py
|
|
160
|
+
tool_registry/__init__.py
|
|
161
|
+
tool_registry/installers.py
|
|
162
|
+
tool_registry/manifest.py
|
|
163
|
+
tool_registry/paths.py
|
|
164
|
+
tool_registry/registry.py
|
|
@@ -21,10 +21,6 @@ from diagram_analysis.analysis_json import (
|
|
|
21
21
|
)
|
|
22
22
|
from diagram_analysis.file_coverage import FileCoverage
|
|
23
23
|
from diagram_analysis.io_utils import save_analysis
|
|
24
|
-
from diagram_analysis.manifest import (
|
|
25
|
-
build_manifest_from_analysis,
|
|
26
|
-
save_manifest,
|
|
27
|
-
)
|
|
28
24
|
from diagram_analysis.version import Version
|
|
29
25
|
from health.config import initialize_health_dir, load_health_config
|
|
30
26
|
from health.runner import run_health_checks
|
|
@@ -452,31 +448,8 @@ class DiagramGenerator:
|
|
|
452
448
|
# Write file_coverage.json
|
|
453
449
|
self._write_file_coverage()
|
|
454
450
|
|
|
455
|
-
# Save manifest for incremental updates
|
|
456
|
-
self._save_manifest(analysis, expanded_components)
|
|
457
|
-
|
|
458
451
|
return analysis_path
|
|
459
452
|
|
|
460
|
-
def _save_manifest(self, analysis: AnalysisInsights, expanded_components: list) -> None:
|
|
461
|
-
"""Save the analysis manifest for incremental updates."""
|
|
462
|
-
try:
|
|
463
|
-
repo_state_hash = get_repo_state_hash(self.repo_location)
|
|
464
|
-
base_commit = get_git_commit_hash(self.repo_location)
|
|
465
|
-
|
|
466
|
-
expanded_names = [c.component_id for c in expanded_components]
|
|
467
|
-
|
|
468
|
-
manifest = build_manifest_from_analysis(
|
|
469
|
-
analysis=analysis,
|
|
470
|
-
repo_state_hash=repo_state_hash,
|
|
471
|
-
base_commit=base_commit,
|
|
472
|
-
expanded_components=expanded_names,
|
|
473
|
-
)
|
|
474
|
-
|
|
475
|
-
save_manifest(manifest, self.output_dir)
|
|
476
|
-
logger.info(f"Saved manifest with {len(manifest.file_to_component)} file mappings")
|
|
477
|
-
except Exception as e:
|
|
478
|
-
logger.warning(f"Failed to save manifest: {e}")
|
|
479
|
-
|
|
480
453
|
def generate_analysis_smart(self) -> Path:
|
|
481
454
|
"""Run full analysis."""
|
|
482
455
|
return self.generate_analysis()
|
|
@@ -18,7 +18,6 @@ from typing import Callable
|
|
|
18
18
|
from agents.agent_responses import AnalysisInsights, Component, FileEntry, FileMethodGroup, MethodEntry
|
|
19
19
|
from agents.change_status import ChangeStatus
|
|
20
20
|
from diagram_analysis.incremental_types import FileDelta, IncrementalDelta, MethodChange
|
|
21
|
-
from diagram_analysis.manifest import AnalysisManifest
|
|
22
21
|
from repo_utils.change_detector import ChangeSet
|
|
23
22
|
from repo_utils.method_diff import get_method_statuses_for_file
|
|
24
23
|
|
|
@@ -35,17 +34,22 @@ class IncrementalUpdater:
|
|
|
35
34
|
to ensure consistent behavior with the main analysis pipeline.
|
|
36
35
|
"""
|
|
37
36
|
|
|
37
|
+
# Callable that resolves a new file path to a component_id using
|
|
38
|
+
# the current file_to_component mapping.
|
|
39
|
+
ComponentResolver = Callable[[str, dict[str, str]], str]
|
|
40
|
+
|
|
38
41
|
def __init__(
|
|
39
42
|
self,
|
|
40
43
|
analysis: AnalysisInsights,
|
|
41
|
-
manifest: AnalysisManifest,
|
|
42
44
|
symbol_resolver: SymbolResolver,
|
|
43
45
|
repo_dir: Path,
|
|
46
|
+
component_resolver: ComponentResolver | None = None,
|
|
44
47
|
):
|
|
45
48
|
self.analysis = analysis
|
|
46
|
-
self.manifest = manifest
|
|
47
49
|
self._symbol_resolver = symbol_resolver
|
|
48
50
|
self._repo_dir = repo_dir
|
|
51
|
+
self._component_resolver = component_resolver
|
|
52
|
+
self._file_to_component = analysis.file_to_component()
|
|
49
53
|
|
|
50
54
|
def _get_current_methods(self, file_path: str) -> list[MethodEntry]:
|
|
51
55
|
return self._symbol_resolver(file_path)
|
|
@@ -59,14 +63,6 @@ class IncrementalUpdater:
|
|
|
59
63
|
def _get_previous_active_methods(self, file_path: str) -> dict[str, MethodEntry]:
|
|
60
64
|
return {qn: m for qn, m in self._get_previous_methods(file_path).items() if m.status != ChangeStatus.DELETED}
|
|
61
65
|
|
|
62
|
-
def _resolve_component(self, file_path: str, *, register_file: bool = False) -> tuple[str | None, bool]:
|
|
63
|
-
component_id = self.manifest.get_component_for_file(file_path)
|
|
64
|
-
if component_id is None:
|
|
65
|
-
return None, True
|
|
66
|
-
if register_file:
|
|
67
|
-
self.manifest.add_file(file_path, component_id)
|
|
68
|
-
return component_id, False
|
|
69
|
-
|
|
70
66
|
def _apply_method_diff_statuses(
|
|
71
67
|
self, file_path: str, current_methods: list[MethodEntry], changes: ChangeSet
|
|
72
68
|
) -> None:
|
|
@@ -95,7 +91,12 @@ class IncrementalUpdater:
|
|
|
95
91
|
register_file: bool,
|
|
96
92
|
changes: ChangeSet,
|
|
97
93
|
) -> tuple[FileDelta, bool]:
|
|
98
|
-
component_id
|
|
94
|
+
component_id = self._file_to_component.get(file_path)
|
|
95
|
+
if component_id is None and register_file and self._component_resolver is not None:
|
|
96
|
+
component_id = self._component_resolver(file_path, self._file_to_component)
|
|
97
|
+
if component_id is not None and register_file:
|
|
98
|
+
self._file_to_component[file_path] = component_id
|
|
99
|
+
missing = component_id is None
|
|
99
100
|
|
|
100
101
|
if file_status == ChangeStatus.ADDED:
|
|
101
102
|
current = self._get_current_methods(file_path)
|
|
@@ -105,7 +106,9 @@ class IncrementalUpdater:
|
|
|
105
106
|
file_path=file_path,
|
|
106
107
|
file_status=ChangeStatus.ADDED,
|
|
107
108
|
component_id=component_id,
|
|
108
|
-
added_methods=[
|
|
109
|
+
added_methods=[
|
|
110
|
+
self._to_method_change(file_path, m, change_type=ChangeStatus.ADDED) for m in current
|
|
111
|
+
],
|
|
109
112
|
),
|
|
110
113
|
missing,
|
|
111
114
|
)
|
|
@@ -186,7 +189,8 @@ class IncrementalUpdater:
|
|
|
186
189
|
Replaces the stored file state with the current unchanged snapshot,
|
|
187
190
|
removing stale added/deleted/modified statuses from prior incremental updates.
|
|
188
191
|
"""
|
|
189
|
-
component_id
|
|
192
|
+
component_id = self._file_to_component.get(file_path)
|
|
193
|
+
missing = component_id is None
|
|
190
194
|
current = self._get_current_methods(file_path)
|
|
191
195
|
for m in current:
|
|
192
196
|
m.status = ChangeStatus.UNCHANGED
|
|
@@ -304,12 +308,66 @@ def _apply_file_delta_to_index(files: dict[str, FileEntry], file_delta: FileDelt
|
|
|
304
308
|
existing.methods = _sorted_methods(methods_by_name)
|
|
305
309
|
|
|
306
310
|
|
|
307
|
-
def _sync_component_methods(
|
|
311
|
+
def _sync_component_methods(
|
|
312
|
+
component: Component,
|
|
313
|
+
files: dict[str, FileEntry],
|
|
314
|
+
deltas_by_path: dict[str, FileDelta],
|
|
315
|
+
parent_ids: set[str],
|
|
316
|
+
) -> None:
|
|
317
|
+
"""Rebuild component's file_methods, preserving method boundaries.
|
|
318
|
+
|
|
319
|
+
Strategy:
|
|
320
|
+
1. Collect the qualified names this component originally owned.
|
|
321
|
+
2. Remove deleted methods from ownership.
|
|
322
|
+
3. Absorb newly added methods when the component is the primary owner
|
|
323
|
+
(``delta.component_id``) OR is an intermediate ancestor of the
|
|
324
|
+
primary (its ID is a descendant of the primary AND it has its own
|
|
325
|
+
children in ``parent_ids``). Leaf components and siblings that
|
|
326
|
+
don't own the file are unaffected.
|
|
327
|
+
4. Filter the global files index to only include owned methods.
|
|
328
|
+
"""
|
|
329
|
+
owned_qnames: set[str] = set()
|
|
330
|
+
|
|
331
|
+
for group in component.file_methods:
|
|
332
|
+
for method in group.methods:
|
|
333
|
+
owned_qnames.add(method.qualified_name)
|
|
334
|
+
|
|
335
|
+
for file_path, delta in deltas_by_path.items():
|
|
336
|
+
if not component.file_methods:
|
|
337
|
+
continue
|
|
338
|
+
if not any(group.file_path == file_path for group in component.file_methods):
|
|
339
|
+
continue
|
|
340
|
+
|
|
341
|
+
for method in delta.deleted_methods:
|
|
342
|
+
owned_qnames.discard(method.qualified_name)
|
|
343
|
+
|
|
344
|
+
primary_id = delta.component_id or ""
|
|
345
|
+
should_absorb = primary_id == component.component_id or (
|
|
346
|
+
component.component_id.startswith(primary_id + ".") and component.component_id in parent_ids
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
# A component that owned every pre-existing method in the file is a
|
|
350
|
+
# superset owner (e.g. a root component whose children partition its
|
|
351
|
+
# methods). It must absorb new methods so it stays a superset.
|
|
352
|
+
if not should_absorb and delta.added_methods:
|
|
353
|
+
file_entry = files.get(file_path)
|
|
354
|
+
if file_entry is not None:
|
|
355
|
+
added_qnames = {m.qualified_name for m in delta.added_methods}
|
|
356
|
+
pre_existing = {m.qualified_name for m in file_entry.methods} - added_qnames
|
|
357
|
+
if pre_existing and pre_existing <= owned_qnames:
|
|
358
|
+
should_absorb = True
|
|
359
|
+
|
|
360
|
+
if should_absorb:
|
|
361
|
+
for method in delta.added_methods:
|
|
362
|
+
owned_qnames.add(method.qualified_name)
|
|
363
|
+
|
|
308
364
|
component.file_methods = [
|
|
309
365
|
FileMethodGroup(
|
|
310
366
|
file_path=fp,
|
|
311
|
-
file_status=entry.file_status,
|
|
312
|
-
methods=[
|
|
367
|
+
file_status=entry.file_status if entry else ChangeStatus.UNCHANGED,
|
|
368
|
+
methods=[
|
|
369
|
+
m.model_copy(deep=True) for m in (entry.methods if entry else []) if m.qualified_name in owned_qnames
|
|
370
|
+
],
|
|
313
371
|
)
|
|
314
372
|
for fp in sorted({g.file_path for g in component.file_methods})
|
|
315
373
|
if (entry := files.get(fp)) is not None
|
|
@@ -327,8 +385,11 @@ def apply_delta(
|
|
|
327
385
|
|
|
328
386
|
files = dict(root.files)
|
|
329
387
|
component_lookup = _component_lookup(root, sub_analyses)
|
|
388
|
+
parent_ids = set(sub_analyses.keys())
|
|
330
389
|
|
|
390
|
+
deltas_by_path: dict[str, FileDelta] = {}
|
|
331
391
|
for file_delta in delta.file_deltas:
|
|
392
|
+
deltas_by_path[file_delta.file_path] = file_delta
|
|
332
393
|
_apply_file_delta_to_index(files, file_delta)
|
|
333
394
|
|
|
334
395
|
component = component_lookup.get(file_delta.component_id or "")
|
|
@@ -342,9 +403,9 @@ def apply_delta(
|
|
|
342
403
|
|
|
343
404
|
root.files = files
|
|
344
405
|
for component in root.components:
|
|
345
|
-
_sync_component_methods(component, files)
|
|
406
|
+
_sync_component_methods(component, files, deltas_by_path, parent_ids)
|
|
346
407
|
|
|
347
408
|
for sub in sub_analyses.values():
|
|
348
409
|
sub.files = files
|
|
349
410
|
for component in sub.components:
|
|
350
|
-
_sync_component_methods(component, files)
|
|
411
|
+
_sync_component_methods(component, files, deltas_by_path, parent_ids)
|
|
@@ -95,6 +95,19 @@ DIAGNOSTIC_CODE_MAPPINGS: dict[str, DeadCodeCategory] = {
|
|
|
95
95
|
"no-unused-vars": DeadCodeCategory.UNUSED_VARIABLE,
|
|
96
96
|
"unused-imports/no-unused-imports": DeadCodeCategory.UNUSED_IMPORT,
|
|
97
97
|
"@typescript-eslint/no-unused-vars": DeadCodeCategory.UNUSED_VARIABLE,
|
|
98
|
+
# csharp-ls / Roslyn (C#)
|
|
99
|
+
"CS8019": DeadCodeCategory.UNUSED_IMPORT, # Unnecessary using directive
|
|
100
|
+
"CS0168": DeadCodeCategory.UNUSED_VARIABLE, # Variable declared but never used
|
|
101
|
+
"CS0219": DeadCodeCategory.UNUSED_VARIABLE, # Variable assigned but its value is never used
|
|
102
|
+
"CS0169": DeadCodeCategory.DEAD_CODE, # Field is never used
|
|
103
|
+
"CS0414": DeadCodeCategory.DEAD_CODE, # Field is assigned but its value is never used
|
|
104
|
+
"CS0649": DeadCodeCategory.DEAD_CODE, # Field is never assigned and will always have its default value
|
|
105
|
+
"CS0162": DeadCodeCategory.UNREACHABLE_CODE, # Unreachable code detected
|
|
106
|
+
"CS8321": DeadCodeCategory.UNUSED_FUNCTION, # Local function is declared but never used
|
|
107
|
+
"IDE0051": DeadCodeCategory.UNUSED_FUNCTION, # Private member is unused
|
|
108
|
+
"IDE0052": DeadCodeCategory.DEAD_CODE, # Private member can be removed
|
|
109
|
+
"IDE0059": DeadCodeCategory.UNUSED_VARIABLE, # Unnecessary value assignment
|
|
110
|
+
"IDE0060": DeadCodeCategory.UNUSED_PARAMETER, # Remove unused parameter
|
|
98
111
|
}
|
|
99
112
|
|
|
100
113
|
# Keywords that indicate unused/dead code in diagnostic messages
|