attocode-code-intel 0.1.0__py3-none-any.whl
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.
- attocode_code_intel-0.1.0.dist-info/METADATA +221 -0
- attocode_code_intel-0.1.0.dist-info/RECORD +345 -0
- attocode_code_intel-0.1.0.dist-info/WHEEL +4 -0
- attocode_code_intel-0.1.0.dist-info/entry_points.txt +2 -0
- attocode_code_intel-0.1.0.dist-info/licenses/LICENSE +21 -0
- attocode_intel/GUIDELINES.md +432 -0
- attocode_intel/__init__.py +52 -0
- attocode_intel/_internal/__init__.py +1 -0
- attocode_intel/_internal/errors/__init__.py +126 -0
- attocode_intel/_internal/integrations/__init__.py +1 -0
- attocode_intel/_internal/integrations/context/__init__.py +1 -0
- attocode_intel/_internal/integrations/context/architecture_drift.py +354 -0
- attocode_intel/_internal/integrations/context/ast_chunker.py +202 -0
- attocode_intel/_internal/integrations/context/ast_service.py +1483 -0
- attocode_intel/_internal/integrations/context/blob_oid.py +423 -0
- attocode_intel/_internal/integrations/context/cache_manifest.py +221 -0
- attocode_intel/_internal/integrations/context/cas.py +466 -0
- attocode_intel/_internal/integrations/context/code_analyzer.py +528 -0
- attocode_intel/_internal/integrations/context/codebase_ast.py +1461 -0
- attocode_intel/_internal/integrations/context/codebase_context.py +1736 -0
- attocode_intel/_internal/integrations/context/cross_mode.py +263 -0
- attocode_intel/_internal/integrations/context/cross_references.py +616 -0
- attocode_intel/_internal/integrations/context/embedding_rotation.py +597 -0
- attocode_intel/_internal/integrations/context/embeddings.py +282 -0
- attocode_intel/_internal/integrations/context/frecency.py +427 -0
- attocode_intel/_internal/integrations/context/fuzzy.py +320 -0
- attocode_intel/_internal/integrations/context/hierarchical_explorer.py +331 -0
- attocode_intel/_internal/integrations/context/hydration.py +90 -0
- attocode_intel/_internal/integrations/context/index_repair.py +87 -0
- attocode_intel/_internal/integrations/context/index_store.py +586 -0
- attocode_intel/_internal/integrations/context/memory_store.py +602 -0
- attocode_intel/_internal/integrations/context/module_resolution.py +52 -0
- attocode_intel/_internal/integrations/context/query_constraints.py +361 -0
- attocode_intel/_internal/integrations/context/query_history.py +417 -0
- attocode_intel/_internal/integrations/context/reranker.py +351 -0
- attocode_intel/_internal/integrations/context/semantic_search.py +2931 -0
- attocode_intel/_internal/integrations/context/syntax_evidence.py +94 -0
- attocode_intel/_internal/integrations/context/systemone_ranker.py +245 -0
- attocode_intel/_internal/integrations/context/temporal_coupling.py +411 -0
- attocode_intel/_internal/integrations/context/trigram_index.py +820 -0
- attocode_intel/_internal/integrations/context/trigram_regex.py +171 -0
- attocode_intel/_internal/integrations/context/ts_parser.py +2199 -0
- attocode_intel/_internal/integrations/context/vector_store.py +795 -0
- attocode_intel/_internal/integrations/feature_flags/__init__.py +357 -0
- attocode_intel/_internal/integrations/lsp/__init__.py +1 -0
- attocode_intel/_internal/integrations/lsp/client.py +1140 -0
- attocode_intel/_internal/integrations/mcp/__init__.py +1 -0
- attocode_intel/_internal/integrations/mcp/client.py +253 -0
- attocode_intel/_internal/integrations/security/__init__.py +1 -0
- attocode_intel/_internal/integrations/security/custom_rules.py +176 -0
- attocode_intel/_internal/integrations/security/dataflow.py +522 -0
- attocode_intel/_internal/integrations/security/dependency_audit.py +303 -0
- attocode_intel/_internal/integrations/security/matcher.py +44 -0
- attocode_intel/_internal/integrations/security/patterns.py +724 -0
- attocode_intel/_internal/integrations/security/scanner.py +351 -0
- attocode_intel/_internal/integrations/utilities/__init__.py +1 -0
- attocode_intel/_internal/integrations/utilities/ignore.py +64 -0
- attocode_intel/_internal/integrations/utilities/token_estimate.py +51 -0
- attocode_intel/_internal/tricks/__init__.py +1 -0
- attocode_intel/_internal/tricks/recursive_context.py +357 -0
- attocode_intel/_internal/types/__init__.py +1 -0
- attocode_intel/_internal/types/events.py +289 -0
- attocode_intel/_internal/types/severity.py +15 -0
- attocode_intel/_shared.py +341 -0
- attocode_intel/analysis_coverage.py +56 -0
- attocode_intel/api/__init__.py +1 -0
- attocode_intel/api/access.py +32 -0
- attocode_intel/api/app.py +247 -0
- attocode_intel/api/auth/__init__.py +128 -0
- attocode_intel/api/auth/api_keys.py +61 -0
- attocode_intel/api/auth/context.py +34 -0
- attocode_intel/api/auth/jwt.py +66 -0
- attocode_intel/api/auth/oauth.py +146 -0
- attocode_intel/api/auth/passwords.py +15 -0
- attocode_intel/api/deps.py +351 -0
- attocode_intel/api/knowledge_bridge.py +13 -0
- attocode_intel/api/mcp_transport.py +51 -0
- attocode_intel/api/middleware.py +411 -0
- attocode_intel/api/models.py +698 -0
- attocode_intel/api/providers/__init__.py +1 -0
- attocode_intel/api/providers/db_provider.py +1106 -0
- attocode_intel/api/providers/local_provider.py +476 -0
- attocode_intel/api/providers/remote_provider.py +740 -0
- attocode_intel/api/repository_source.py +21 -0
- attocode_intel/api/routes/__init__.py +1 -0
- attocode_intel/api/routes/_pin_helper.py +158 -0
- attocode_intel/api/routes/activity.py +148 -0
- attocode_intel/api/routes/adr.py +102 -0
- attocode_intel/api/routes/analysis.py +515 -0
- attocode_intel/api/routes/api_keys.py +170 -0
- attocode_intel/api/routes/auth.py +428 -0
- attocode_intel/api/routes/branches.py +262 -0
- attocode_intel/api/routes/cross_repo_search.py +198 -0
- attocode_intel/api/routes/embeddings.py +386 -0
- attocode_intel/api/routes/files.py +132 -0
- attocode_intel/api/routes/files_v2.py +388 -0
- attocode_intel/api/routes/gc.py +322 -0
- attocode_intel/api/routes/git_v2.py +433 -0
- attocode_intel/api/routes/graph.py +174 -0
- attocode_intel/api/routes/graph_viz.py +160 -0
- attocode_intel/api/routes/health.py +62 -0
- attocode_intel/api/routes/history.py +175 -0
- attocode_intel/api/routes/jobs.py +84 -0
- attocode_intel/api/routes/learning.py +205 -0
- attocode_intel/api/routes/lsp.py +272 -0
- attocode_intel/api/routes/notify.py +623 -0
- attocode_intel/api/routes/operations.py +27 -0
- attocode_intel/api/routes/orgs.py +924 -0
- attocode_intel/api/routes/preferences.py +100 -0
- attocode_intel/api/routes/presence.py +42 -0
- attocode_intel/api/routes/projects.py +116 -0
- attocode_intel/api/routes/repos.py +47 -0
- attocode_intel/api/routes/search.py +180 -0
- attocode_intel/api/routes/snapshots.py +614 -0
- attocode_intel/api/routes/webhooks.py +313 -0
- attocode_intel/api/routes/websocket.py +116 -0
- attocode_intel/api/static/graph.html +239 -0
- attocode_intel/api/utils.py +96 -0
- attocode_intel/artifacts/__init__.py +45 -0
- attocode_intel/artifacts/hashing.py +230 -0
- attocode_intel/artifacts/provenance.py +190 -0
- attocode_intel/artifacts/retrieval_pin.py +159 -0
- attocode_intel/audit.py +59 -0
- attocode_intel/bug_finder.py +206 -0
- attocode_intel/bundle.py +80 -0
- attocode_intel/catalog.py +242 -0
- attocode_intel/change_review.py +75 -0
- attocode_intel/cli.py +3062 -0
- attocode_intel/community.py +63 -0
- attocode_intel/confidence/__init__.py +144 -0
- attocode_intel/confidence/jev.py +234 -0
- attocode_intel/confidence/llm.py +330 -0
- attocode_intel/confidence/redact.py +44 -0
- attocode_intel/confidence/settings.py +74 -0
- attocode_intel/config.py +256 -0
- attocode_intel/crypto.py +31 -0
- attocode_intel/db/__init__.py +7 -0
- attocode_intel/db/base.py +33 -0
- attocode_intel/db/engine.py +61 -0
- attocode_intel/db/models.py +529 -0
- attocode_intel/entrypoint.py +185 -0
- attocode_intel/focused_evidence.py +130 -0
- attocode_intel/freshness.py +154 -0
- attocode_intel/gateway.py +734 -0
- attocode_intel/git/__init__.py +7 -0
- attocode_intel/git/credentials.py +75 -0
- attocode_intel/git/manager.py +493 -0
- attocode_intel/git/models.py +96 -0
- attocode_intel/git/storage.py +98 -0
- attocode_intel/graph_query_parser.py +761 -0
- attocode_intel/helpers.py +712 -0
- attocode_intel/indexing/__init__.py +29 -0
- attocode_intel/indexing/debouncer.py +136 -0
- attocode_intel/indexing/delta_indexer.py +151 -0
- attocode_intel/indexing/full_indexer.py +323 -0
- attocode_intel/indexing/incremental.py +240 -0
- attocode_intel/indexing/parser.py +403 -0
- attocode_intel/indexing/summarizer.py +264 -0
- attocode_intel/installer.py +1896 -0
- attocode_intel/knowledge.py +269 -0
- attocode_intel/local_knowledge.py +77 -0
- attocode_intel/migrations/alembic.ini +36 -0
- attocode_intel/migrations/env.py +71 -0
- attocode_intel/migrations/script.py.mako +27 -0
- attocode_intel/migrations/versions/001_initial_schema.py +219 -0
- attocode_intel/migrations/versions/002_branch_version_and_embeddings.py +61 -0
- attocode_intel/migrations/versions/003_embedding_uniqueness_and_cascade.py +51 -0
- attocode_intel/migrations/versions/004_audit_events.py +38 -0
- attocode_intel/migrations/versions/005_user_preferences.py +30 -0
- attocode_intel/migrations/versions/006_google_oauth.py +27 -0
- attocode_intel/migrations/versions/007_pgvector_embeddings.py +28 -0
- attocode_intel/migrations/versions/008_symbol_references.py +37 -0
- attocode_intel/migrations/versions/009_webhook_secret_encryption.py +25 -0
- attocode_intel/migrations/versions/010_add_commits_table.py +40 -0
- attocode_intel/migrations/versions/011_commit_changed_files.py +25 -0
- attocode_intel/migrations/versions/012_branch_merged_at.py +25 -0
- attocode_intel/migrations/versions/013_revoked_tokens.py +32 -0
- attocode_intel/migrations/versions/014_blame_hunks.py +40 -0
- attocode_intel/migrations/versions/015_commit_file_stats.py +40 -0
- attocode_intel/migrations/versions/016_embedding_provenance_columns.py +179 -0
- attocode_intel/migrations/versions/017_provenance_table.py +102 -0
- attocode_intel/migrations/versions/018_repo_snapshots.py +178 -0
- attocode_intel/migrations/versions/019_symref_caller.py +42 -0
- attocode_intel/migrations/versions/020_shared_knowledge.py +29 -0
- attocode_intel/onboarding.py +258 -0
- attocode_intel/output.py +178 -0
- attocode_intel/precision.py +133 -0
- attocode_intel/presence.py +160 -0
- attocode_intel/probe.py +110 -0
- attocode_intel/project_dir.py +97 -0
- attocode_intel/pubsub.py +113 -0
- attocode_intel/query_ranking.py +242 -0
- attocode_intel/readiness.py +972 -0
- attocode_intel/redis.py +51 -0
- attocode_intel/reference_pages.py +60 -0
- attocode_intel/remote.py +131 -0
- attocode_intel/repo_ranker.py +246 -0
- attocode_intel/request_context.py +82 -0
- attocode_intel/rules/__init__.py +28 -0
- attocode_intel/rules/ci.py +320 -0
- attocode_intel/rules/combinators.py +293 -0
- attocode_intel/rules/enricher.py +127 -0
- attocode_intel/rules/evolution.py +452 -0
- attocode_intel/rules/executor.py +531 -0
- attocode_intel/rules/filters/__init__.py +5 -0
- attocode_intel/rules/filters/pipeline.py +151 -0
- attocode_intel/rules/formatter.py +198 -0
- attocode_intel/rules/hygiene.py +242 -0
- attocode_intel/rules/importers/__init__.py +1 -0
- attocode_intel/rules/importers/semgrep.py +382 -0
- attocode_intel/rules/loader.py +292 -0
- attocode_intel/rules/marketplace.py +375 -0
- attocode_intel/rules/metavar.py +181 -0
- attocode_intel/rules/model.py +317 -0
- attocode_intel/rules/packs/__init__.py +1 -0
- attocode_intel/rules/packs/community/_license_templates/Apache-2.0.txt +176 -0
- attocode_intel/rules/packs/community/_license_templates/MIT.txt +21 -0
- attocode_intel/rules/packs/community/bandit-python/LICENSE +176 -0
- attocode_intel/rules/packs/community/bandit-python/NOTICE +13 -0
- attocode_intel/rules/packs/community/bandit-python/PORTING.md +23 -0
- attocode_intel/rules/packs/community/bandit-python/manifest.yaml +14 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B105-hardcoded-password.yaml +23 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B303-weak-md5.yaml +21 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B304-weak-des.yaml +20 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B307-use-of-eval.yaml +22 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B324-weak-sha1.yaml +21 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B501-no-cert-validation.yaml +23 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B602-shell-true.yaml +22 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B608-sqli.yaml +22 -0
- attocode_intel/rules/packs/community/eslint-typescript/LICENSE +21 -0
- attocode_intel/rules/packs/community/eslint-typescript/NOTICE +13 -0
- attocode_intel/rules/packs/community/eslint-typescript/PORTING.md +23 -0
- attocode_intel/rules/packs/community/eslint-typescript/manifest.yaml +14 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/eqeqeq.yaml +20 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-eval.yaml +22 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-implied-eval.yaml +20 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-new-func.yaml +21 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-throw-literal.yaml +19 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-var.yaml +20 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-with.yaml +18 -0
- attocode_intel/rules/packs/community/gosec-go/LICENSE +176 -0
- attocode_intel/rules/packs/community/gosec-go/NOTICE +13 -0
- attocode_intel/rules/packs/community/gosec-go/PORTING.md +23 -0
- attocode_intel/rules/packs/community/gosec-go/manifest.yaml +14 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G101-hardcoded-credentials.yaml +22 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G102-bind-all-interfaces.yaml +21 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G103-unsafe-block.yaml +21 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G201-sql-format.yaml +21 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G304-file-inclusion.yaml +23 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G401-weak-cipher.yaml +20 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G402-tls-min-version.yaml +20 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G501-md5-import.yaml +21 -0
- attocode_intel/rules/packs/examples/cpp/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/cpp/rules/security.yaml +90 -0
- attocode_intel/rules/packs/examples/cpp/rules/structural.yaml +42 -0
- attocode_intel/rules/packs/examples/csharp/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/csharp/rules/security.yaml +69 -0
- attocode_intel/rules/packs/examples/csharp/rules/structural.yaml +42 -0
- attocode_intel/rules/packs/examples/go/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/go/rules/performance.yaml +136 -0
- attocode_intel/rules/packs/examples/go/rules/security.yaml +48 -0
- attocode_intel/rules/packs/examples/go/rules/structural.yaml +58 -0
- attocode_intel/rules/packs/examples/go/taint/sanitizers.yaml +24 -0
- attocode_intel/rules/packs/examples/go/taint/sinks.yaml +51 -0
- attocode_intel/rules/packs/examples/go/taint/sources.yaml +26 -0
- attocode_intel/rules/packs/examples/java/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/java/rules/correctness.yaml +55 -0
- attocode_intel/rules/packs/examples/java/rules/structural.yaml +48 -0
- attocode_intel/rules/packs/examples/java/taint/sinks.yaml +37 -0
- attocode_intel/rules/packs/examples/java/taint/sources.yaml +21 -0
- attocode_intel/rules/packs/examples/kotlin/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/kotlin/rules/correctness.yaml +50 -0
- attocode_intel/rules/packs/examples/kotlin/rules/structural.yaml +38 -0
- attocode_intel/rules/packs/examples/php/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/php/rules/security.yaml +66 -0
- attocode_intel/rules/packs/examples/php/rules/structural.yaml +41 -0
- attocode_intel/rules/packs/examples/python/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/python/rules/performance.yaml +90 -0
- attocode_intel/rules/packs/examples/python/rules/structural.yaml +55 -0
- attocode_intel/rules/packs/examples/ruby/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/ruby/rules/security.yaml +73 -0
- attocode_intel/rules/packs/examples/ruby/rules/structural.yaml +41 -0
- attocode_intel/rules/packs/examples/rust/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/rust/rules/correctness.yaml +51 -0
- attocode_intel/rules/packs/examples/rust/rules/structural.yaml +49 -0
- attocode_intel/rules/packs/examples/typescript/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/typescript/rules/performance.yaml +70 -0
- attocode_intel/rules/packs/examples/typescript/rules/structural.yaml +48 -0
- attocode_intel/rules/packs/pack_loader.py +244 -0
- attocode_intel/rules/plugins/__init__.py +1 -0
- attocode_intel/rules/plugins/plugin_loader.py +132 -0
- attocode_intel/rules/profiling.py +332 -0
- attocode_intel/rules/registry.py +213 -0
- attocode_intel/rules/sarif.py +187 -0
- attocode_intel/rules/synthesis.py +420 -0
- attocode_intel/rules/testing.py +326 -0
- attocode_intel/server.py +734 -0
- attocode_intel/service.py +3416 -0
- attocode_intel/sharing.py +57 -0
- attocode_intel/storage/__init__.py +6 -0
- attocode_intel/storage/branch_overlay.py +352 -0
- attocode_intel/storage/content_store.py +220 -0
- attocode_intel/storage/dependency_store.py +143 -0
- attocode_intel/storage/diff_engine.py +187 -0
- attocode_intel/storage/embedding_store.py +594 -0
- attocode_intel/storage/provenance_store.py +137 -0
- attocode_intel/storage/security_scanner_db.py +164 -0
- attocode_intel/storage/symbol_store.py +160 -0
- attocode_intel/structural_evidence.py +144 -0
- attocode_intel/symbol_inspection.py +141 -0
- attocode_intel/symbol_links.py +167 -0
- attocode_intel/telemetry.py +42 -0
- attocode_intel/test_ranking.py +73 -0
- attocode_intel/testing/__init__.py +43 -0
- attocode_intel/testing/fixtures.py +122 -0
- attocode_intel/testing/helpers.py +75 -0
- attocode_intel/testing/mocks.py +99 -0
- attocode_intel/tools/__init__.py +2 -0
- attocode_intel/tools/adr_tools.py +628 -0
- attocode_intel/tools/analysis_tools.py +382 -0
- attocode_intel/tools/composite_tools.py +695 -0
- attocode_intel/tools/cross_mode_tools.py +173 -0
- attocode_intel/tools/dead_code_tools.py +582 -0
- attocode_intel/tools/distill_tools.py +353 -0
- attocode_intel/tools/frecency_tools.py +220 -0
- attocode_intel/tools/fuzzy_tools.py +255 -0
- attocode_intel/tools/history_tools.py +486 -0
- attocode_intel/tools/learning_tools.py +222 -0
- attocode_intel/tools/lsp_tools.py +218 -0
- attocode_intel/tools/maintenance_tools.py +1662 -0
- attocode_intel/tools/navigation_tools.py +220 -0
- attocode_intel/tools/overlay_tools.py +540 -0
- attocode_intel/tools/pin_store.py +432 -0
- attocode_intel/tools/pin_tools.py +266 -0
- attocode_intel/tools/query_constraints_tools.py +262 -0
- attocode_intel/tools/query_history_tools.py +158 -0
- attocode_intel/tools/readiness_tools.py +44 -0
- attocode_intel/tools/rule_tools.py +992 -0
- attocode_intel/tools/search_tools.py +770 -0
- attocode_intel/tools/snapshot_tools.py +624 -0
- attocode_intel/workers/__init__.py +1 -0
- attocode_intel/workers/job_utils.py +111 -0
- attocode_intel/workers/jobs.py +573 -0
- attocode_intel/workers/run.py +30 -0
- attocode_intel/workers/settings.py +61 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
"""Analysis tools for the code-intel MCP server.
|
|
2
|
+
|
|
3
|
+
Tools: file_analysis, impact_analysis, dependency_graph, hotspots,
|
|
4
|
+
cross_references, dependencies, graph_query, graph_dsl, find_related,
|
|
5
|
+
community_detection, repo_map_ranked, bug_scan.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from attocode_intel._shared import (
|
|
11
|
+
_get_code_analyzer,
|
|
12
|
+
_get_context_mgr,
|
|
13
|
+
_get_local_service,
|
|
14
|
+
_get_project_dir,
|
|
15
|
+
_get_remote_service,
|
|
16
|
+
_get_service,
|
|
17
|
+
mcp,
|
|
18
|
+
)
|
|
19
|
+
from attocode_intel.tools.pin_tools import pin_stamped
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@mcp.tool()
|
|
23
|
+
def file_analysis(path: str) -> str:
|
|
24
|
+
"""Get detailed analysis of a single file including code chunks, imports, and exports.
|
|
25
|
+
|
|
26
|
+
Extracts structured information about functions, classes, methods,
|
|
27
|
+
imports, and exports using AST parsing (tree-sitter or regex fallback).
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
path: File path (relative to project root or absolute).
|
|
31
|
+
"""
|
|
32
|
+
return _get_service().file_analysis(path)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@mcp.tool()
|
|
36
|
+
def impact_analysis(changed_files: list[str]) -> str:
|
|
37
|
+
"""List the files that a change to the given files can affect: the files that import them, directly or through other files."""
|
|
38
|
+
return _get_service().impact_analysis(changed_files)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@mcp.tool()
|
|
42
|
+
def dependency_graph(start_file: str, depth: int = 2) -> str:
|
|
43
|
+
"""Get the dependency graph starting from a file.
|
|
44
|
+
|
|
45
|
+
Shows the import tree radiating outward from the given file,
|
|
46
|
+
including both forward dependencies (what it imports) and
|
|
47
|
+
reverse dependencies (what imports it).
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
start_file: File path to start from.
|
|
51
|
+
depth: How many hops to traverse (default 2).
|
|
52
|
+
"""
|
|
53
|
+
return _get_service().dependency_graph(start_file, depth=depth)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@mcp.tool()
|
|
57
|
+
def hotspots(top_n: int = 15) -> str:
|
|
58
|
+
"""Identify files with highest complexity, coupling, and risk.
|
|
59
|
+
|
|
60
|
+
Ranks files by a composite score combining size, symbol count,
|
|
61
|
+
fan-in (dependents), fan-out (dependencies), and symbol density.
|
|
62
|
+
Also categorizes files as god-files, hubs, coupling magnets, or orphans.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
top_n: Number of top hotspots to show (default 15).
|
|
66
|
+
"""
|
|
67
|
+
return _get_service().hotspots(top_n=top_n)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@mcp.tool()
|
|
71
|
+
def cross_references(
|
|
72
|
+
symbol_name: str, file_path: str | None = None, line: int | None = None,
|
|
73
|
+
cursor: str | None = None, page_size: int | None = None,
|
|
74
|
+
) -> str:
|
|
75
|
+
"""Find where a symbol is defined and each place that references it: calls, imports and attribute accesses.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
file_path: When names collide, select the definition in this repository-relative file.
|
|
79
|
+
line: Select the definition by its start line.
|
|
80
|
+
cursor: Continue a paged result.
|
|
81
|
+
page_size: References per page, 1 to 100 (default 20).
|
|
82
|
+
"""
|
|
83
|
+
if cursor or file_path is not None or line is not None or page_size is not None:
|
|
84
|
+
# Pagination belongs to the authenticated operation gateway.
|
|
85
|
+
raise ValueError("Use the operation gateway for scoped or paginated references")
|
|
86
|
+
return _get_service().cross_references(symbol_name)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@mcp.tool()
|
|
90
|
+
def call_graph(
|
|
91
|
+
symbol: str,
|
|
92
|
+
direction: str = "callees",
|
|
93
|
+
depth: int = 1,
|
|
94
|
+
) -> str:
|
|
95
|
+
"""Follow the calls of a function or method.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
symbol: Function or method name, qualified or bare.
|
|
99
|
+
direction: "callees" (what it calls) or "callers" (what calls it).
|
|
100
|
+
depth: Maximum number of hops (default 1).
|
|
101
|
+
"""
|
|
102
|
+
# call_graph has no server-side HTTP route, so it runs locally even when a
|
|
103
|
+
# remote is configured (the local symbol index carries the call edges).
|
|
104
|
+
return _get_local_service().call_graph(symbol, direction=direction, depth=depth)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@mcp.tool()
|
|
108
|
+
def dependencies(path: str) -> str:
|
|
109
|
+
"""Show what a file imports and which files import it."""
|
|
110
|
+
return _get_service().dependencies(path)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@mcp.tool()
|
|
114
|
+
def graph_query(
|
|
115
|
+
file: str,
|
|
116
|
+
edge_type: str = "IMPORTS",
|
|
117
|
+
direction: str = "outbound",
|
|
118
|
+
depth: int = 2,
|
|
119
|
+
) -> str:
|
|
120
|
+
"""BFS traversal over typed dependency edges.
|
|
121
|
+
|
|
122
|
+
Walks the import graph from a starting file, following edges of the
|
|
123
|
+
specified type and direction.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
file: Starting file path (relative to project root or absolute).
|
|
127
|
+
edge_type: Edge type to follow. One of: IMPORTS, IMPORTED_BY.
|
|
128
|
+
direction: "outbound" follows imports, "inbound" follows importers.
|
|
129
|
+
depth: Maximum BFS hops (default 2, max 5).
|
|
130
|
+
"""
|
|
131
|
+
return _get_service().graph_query(
|
|
132
|
+
file=file,
|
|
133
|
+
edge_type=edge_type,
|
|
134
|
+
direction=direction,
|
|
135
|
+
depth=depth,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@mcp.tool()
|
|
140
|
+
def graph_dsl(query: str) -> str:
|
|
141
|
+
"""Query the dependency graph with a simple graph query language.
|
|
142
|
+
|
|
143
|
+
Supports a Cypher-inspired syntax for traversing import relationships
|
|
144
|
+
with depth constraints, filters, and multi-hop chains.
|
|
145
|
+
|
|
146
|
+
Example queries:
|
|
147
|
+
MATCH "src/api/app.py" -[IMPORTS*1..3]-> target RETURN target
|
|
148
|
+
MATCH file <-[IMPORTED_BY]- caller WHERE caller.language = "python" RETURN caller
|
|
149
|
+
MATCH a -[IMPORTS]-> b -[IMPORTS]-> c RETURN a, c
|
|
150
|
+
|
|
151
|
+
Syntax:
|
|
152
|
+
MATCH node -[EDGE_TYPE*min..max]-> node [WHERE conditions] RETURN variables
|
|
153
|
+
- Node: variable name (e.g. 'target') or quoted path ("src/app.py")
|
|
154
|
+
- Edge types: IMPORTS, IMPORTED_BY
|
|
155
|
+
- Direction: -> (outbound), <- (inbound with <-[TYPE]-)
|
|
156
|
+
- Depth: *N (exact), *N..M (range), omit for 1
|
|
157
|
+
- WHERE: variable.field op value (AND-separated)
|
|
158
|
+
Fields: language, line_count, importance, path, fan_in, fan_out, is_test, is_config
|
|
159
|
+
Operators: =, !=, >, <, >=, <=, LIKE
|
|
160
|
+
- RETURN: comma-separated variable names, or variable.field, or COUNT
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
query: Graph DSL query string.
|
|
164
|
+
"""
|
|
165
|
+
remote = _get_remote_service()
|
|
166
|
+
if remote is not None:
|
|
167
|
+
return remote.graph_dsl(query)
|
|
168
|
+
|
|
169
|
+
from attocode_intel.graph_query_parser import (
|
|
170
|
+
GraphQueryExecutor,
|
|
171
|
+
GraphQueryParser,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
ctx = _get_context_mgr()
|
|
175
|
+
dep_graph = ctx.dependency_graph
|
|
176
|
+
files = ctx._files
|
|
177
|
+
|
|
178
|
+
parser = GraphQueryParser()
|
|
179
|
+
try:
|
|
180
|
+
ast = parser.parse(query)
|
|
181
|
+
except ValueError as exc:
|
|
182
|
+
return f"Query syntax error: {exc}"
|
|
183
|
+
|
|
184
|
+
executor = GraphQueryExecutor()
|
|
185
|
+
try:
|
|
186
|
+
results = executor.execute(ast, dep_graph, files)
|
|
187
|
+
except Exception as exc:
|
|
188
|
+
return f"Execution error: {exc}"
|
|
189
|
+
|
|
190
|
+
if not results:
|
|
191
|
+
return f"No results for query: {query}"
|
|
192
|
+
|
|
193
|
+
lines = [f"Graph DSL results ({len(results)} matches):"]
|
|
194
|
+
|
|
195
|
+
# Format results based on what's returned
|
|
196
|
+
for i, row in enumerate(results, 1):
|
|
197
|
+
parts = []
|
|
198
|
+
for key, value in row.items():
|
|
199
|
+
parts.append(f"{key}={value}")
|
|
200
|
+
lines.append(f" {i:3d}. {', '.join(parts)}")
|
|
201
|
+
|
|
202
|
+
if len(results) >= executor.MAX_RESULTS:
|
|
203
|
+
lines.append(f"\n (results truncated at {executor.MAX_RESULTS})")
|
|
204
|
+
|
|
205
|
+
return "\n".join(lines)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@mcp.tool()
|
|
209
|
+
def find_related(file: str, top_k: int = 10, task_hint: str = "") -> str:
|
|
210
|
+
"""Find structurally related files by import-graph proximity.
|
|
211
|
+
|
|
212
|
+
Combines 2-hop import neighbors with co-importer overlap
|
|
213
|
+
(Jaccard-style) to find the most structurally related files.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
file: File path (relative to project root or absolute).
|
|
217
|
+
top_k: Number of results to return (default 10).
|
|
218
|
+
task_hint: Optional context for ordering the structurally related files.
|
|
219
|
+
"""
|
|
220
|
+
service = _get_service()
|
|
221
|
+
if task_hint and hasattr(service, "_task_file_scores"):
|
|
222
|
+
return service.find_related(file=file, top_k=top_k, task_hint=task_hint)
|
|
223
|
+
return service.find_related(file=file, top_k=top_k)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _louvain_communities(
|
|
227
|
+
all_files: set[str],
|
|
228
|
+
adj: dict[str, set[str]],
|
|
229
|
+
weights: dict[tuple[str, str], float],
|
|
230
|
+
) -> tuple[list[set[str]], float]:
|
|
231
|
+
"""Run Louvain community detection using networkx."""
|
|
232
|
+
from attocode_intel.community import louvain_communities
|
|
233
|
+
return louvain_communities(all_files, adj, weights)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _bfs_connected_components(
|
|
237
|
+
all_files: set[str],
|
|
238
|
+
adj: dict[str, set[str]],
|
|
239
|
+
) -> tuple[list[set[str]], float]:
|
|
240
|
+
"""Fallback: connected components via BFS. Modularity = 0."""
|
|
241
|
+
from attocode_intel.community import bfs_connected_components
|
|
242
|
+
return bfs_connected_components(all_files, adj)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@mcp.tool()
|
|
246
|
+
def community_detection(
|
|
247
|
+
min_community_size: int = 3,
|
|
248
|
+
max_communities: int = 20,
|
|
249
|
+
) -> str:
|
|
250
|
+
"""Detect file communities using Louvain algorithm on the import graph.
|
|
251
|
+
|
|
252
|
+
Groups files into communities based on modularity optimization (Louvain),
|
|
253
|
+
falling back to connected components when networkx is not installed.
|
|
254
|
+
Reports community sizes, modularity, hub files, and directory themes.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
min_community_size: Minimum files per community to report (default 3).
|
|
258
|
+
max_communities: Maximum number of communities to return (default 20).
|
|
259
|
+
"""
|
|
260
|
+
return _get_service().community_detection(
|
|
261
|
+
min_community_size=min_community_size,
|
|
262
|
+
max_communities=max_communities,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@mcp.tool()
|
|
267
|
+
@pin_stamped
|
|
268
|
+
def repo_map_ranked(
|
|
269
|
+
task_context: str = "",
|
|
270
|
+
token_budget: int = 1024,
|
|
271
|
+
exclude_tests: bool = True,
|
|
272
|
+
) -> str:
|
|
273
|
+
"""Generate a graph-ranked repository map using PageRank.
|
|
274
|
+
|
|
275
|
+
Ranks files by their importance in the dependency graph, weighted
|
|
276
|
+
by relevance to the current task. Produces a token-budgeted map
|
|
277
|
+
of the most important files and their key symbols.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
task_context: Description of the current task for relevance scoring.
|
|
281
|
+
token_budget: Maximum tokens for the output (default 1024).
|
|
282
|
+
exclude_tests: Whether to exclude test files from ranking.
|
|
283
|
+
"""
|
|
284
|
+
remote = _get_remote_service()
|
|
285
|
+
if remote is not None:
|
|
286
|
+
return remote.repo_map_ranked(
|
|
287
|
+
task_context=task_context,
|
|
288
|
+
token_budget=token_budget,
|
|
289
|
+
exclude_tests=exclude_tests,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
from attocode_intel.repo_ranker import format_repo_map, rank_repo_files
|
|
293
|
+
|
|
294
|
+
ctx_mgr = _get_context_mgr()
|
|
295
|
+
|
|
296
|
+
# Build adjacency from the dependency graph
|
|
297
|
+
adjacency: dict[str, list[str]] = {}
|
|
298
|
+
symbols_by_file: dict[str, list[str]] = {}
|
|
299
|
+
dep_graph = ctx_mgr._dep_graph
|
|
300
|
+
for fi in ctx_mgr._files:
|
|
301
|
+
rel = fi.relative_path
|
|
302
|
+
if dep_graph is not None:
|
|
303
|
+
deps = dep_graph.get_imports(rel)
|
|
304
|
+
adjacency[rel] = list(deps)
|
|
305
|
+
else:
|
|
306
|
+
adjacency[rel] = []
|
|
307
|
+
|
|
308
|
+
# Extract symbols if available
|
|
309
|
+
try:
|
|
310
|
+
analyzer = _get_code_analyzer()
|
|
311
|
+
result = analyzer.analyze_file(fi.full_path)
|
|
312
|
+
symbols_by_file[rel] = [
|
|
313
|
+
c.name for c in (result.chunks or []) if hasattr(c, "name") and c.name
|
|
314
|
+
][:10]
|
|
315
|
+
except Exception:
|
|
316
|
+
pass
|
|
317
|
+
|
|
318
|
+
if not adjacency:
|
|
319
|
+
return "No files indexed. Run bootstrap first."
|
|
320
|
+
|
|
321
|
+
result = rank_repo_files(
|
|
322
|
+
adjacency,
|
|
323
|
+
task_context=task_context,
|
|
324
|
+
token_budget=token_budget,
|
|
325
|
+
symbols_by_file=symbols_by_file,
|
|
326
|
+
exclude_tests=exclude_tests,
|
|
327
|
+
relevance_by_file=(_get_service()._task_file_scores(task_context)
|
|
328
|
+
if task_context else None),
|
|
329
|
+
)
|
|
330
|
+
return format_repo_map(result)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
@mcp.tool()
|
|
334
|
+
def bug_scan(base_branch: str = "main", min_confidence: float = 0.5) -> str:
|
|
335
|
+
"""Scan the diff between current branch and base for potential bugs.
|
|
336
|
+
|
|
337
|
+
Analyzes added lines for common patterns: bare excepts, eval/exec usage,
|
|
338
|
+
shell injection, swallowed exceptions, and more. Reports findings with
|
|
339
|
+
severity and confidence levels.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
base_branch: Base branch to diff against (default "main").
|
|
343
|
+
min_confidence: Minimum confidence threshold for reported findings (0.0-1.0).
|
|
344
|
+
"""
|
|
345
|
+
remote = _get_remote_service()
|
|
346
|
+
if remote is not None:
|
|
347
|
+
return remote.bug_scan(base_branch=base_branch, min_confidence=min_confidence)
|
|
348
|
+
|
|
349
|
+
import subprocess
|
|
350
|
+
|
|
351
|
+
from attocode_intel.bug_finder import scan_diff
|
|
352
|
+
|
|
353
|
+
project_dir = _get_project_dir()
|
|
354
|
+
|
|
355
|
+
try:
|
|
356
|
+
result = subprocess.run(
|
|
357
|
+
["git", "diff", f"{base_branch}...HEAD"],
|
|
358
|
+
cwd=project_dir,
|
|
359
|
+
capture_output=True,
|
|
360
|
+
text=True,
|
|
361
|
+
timeout=30,
|
|
362
|
+
)
|
|
363
|
+
diff_text = result.stdout
|
|
364
|
+
except FileNotFoundError:
|
|
365
|
+
return "git not found. Install git to use bug_scan."
|
|
366
|
+
except subprocess.TimeoutExpired:
|
|
367
|
+
return "git diff timed out (>30s). Try a smaller diff range."
|
|
368
|
+
except Exception as e:
|
|
369
|
+
return f"Failed to get diff: {e}"
|
|
370
|
+
|
|
371
|
+
if not diff_text.strip():
|
|
372
|
+
return f"No diff found between {base_branch} and HEAD."
|
|
373
|
+
|
|
374
|
+
report = scan_diff(diff_text)
|
|
375
|
+
# Same second opinion as the rule pipeline; a no-op unless ATTOCODE_FLAG_CONFIDENCE is set.
|
|
376
|
+
from attocode_intel import confidence
|
|
377
|
+
from attocode_intel.confidence.settings import workspace
|
|
378
|
+
|
|
379
|
+
with workspace(project_dir):
|
|
380
|
+
confidence.score(report.findings, min_confidence=min_confidence)
|
|
381
|
+
text = report.format_report(min_confidence=min_confidence)
|
|
382
|
+
return text + ("\n\n" + confidence.summary() if confidence.summary() else "")
|