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.
Files changed (345) hide show
  1. attocode_code_intel-0.1.0.dist-info/METADATA +221 -0
  2. attocode_code_intel-0.1.0.dist-info/RECORD +345 -0
  3. attocode_code_intel-0.1.0.dist-info/WHEEL +4 -0
  4. attocode_code_intel-0.1.0.dist-info/entry_points.txt +2 -0
  5. attocode_code_intel-0.1.0.dist-info/licenses/LICENSE +21 -0
  6. attocode_intel/GUIDELINES.md +432 -0
  7. attocode_intel/__init__.py +52 -0
  8. attocode_intel/_internal/__init__.py +1 -0
  9. attocode_intel/_internal/errors/__init__.py +126 -0
  10. attocode_intel/_internal/integrations/__init__.py +1 -0
  11. attocode_intel/_internal/integrations/context/__init__.py +1 -0
  12. attocode_intel/_internal/integrations/context/architecture_drift.py +354 -0
  13. attocode_intel/_internal/integrations/context/ast_chunker.py +202 -0
  14. attocode_intel/_internal/integrations/context/ast_service.py +1483 -0
  15. attocode_intel/_internal/integrations/context/blob_oid.py +423 -0
  16. attocode_intel/_internal/integrations/context/cache_manifest.py +221 -0
  17. attocode_intel/_internal/integrations/context/cas.py +466 -0
  18. attocode_intel/_internal/integrations/context/code_analyzer.py +528 -0
  19. attocode_intel/_internal/integrations/context/codebase_ast.py +1461 -0
  20. attocode_intel/_internal/integrations/context/codebase_context.py +1736 -0
  21. attocode_intel/_internal/integrations/context/cross_mode.py +263 -0
  22. attocode_intel/_internal/integrations/context/cross_references.py +616 -0
  23. attocode_intel/_internal/integrations/context/embedding_rotation.py +597 -0
  24. attocode_intel/_internal/integrations/context/embeddings.py +282 -0
  25. attocode_intel/_internal/integrations/context/frecency.py +427 -0
  26. attocode_intel/_internal/integrations/context/fuzzy.py +320 -0
  27. attocode_intel/_internal/integrations/context/hierarchical_explorer.py +331 -0
  28. attocode_intel/_internal/integrations/context/hydration.py +90 -0
  29. attocode_intel/_internal/integrations/context/index_repair.py +87 -0
  30. attocode_intel/_internal/integrations/context/index_store.py +586 -0
  31. attocode_intel/_internal/integrations/context/memory_store.py +602 -0
  32. attocode_intel/_internal/integrations/context/module_resolution.py +52 -0
  33. attocode_intel/_internal/integrations/context/query_constraints.py +361 -0
  34. attocode_intel/_internal/integrations/context/query_history.py +417 -0
  35. attocode_intel/_internal/integrations/context/reranker.py +351 -0
  36. attocode_intel/_internal/integrations/context/semantic_search.py +2931 -0
  37. attocode_intel/_internal/integrations/context/syntax_evidence.py +94 -0
  38. attocode_intel/_internal/integrations/context/systemone_ranker.py +245 -0
  39. attocode_intel/_internal/integrations/context/temporal_coupling.py +411 -0
  40. attocode_intel/_internal/integrations/context/trigram_index.py +820 -0
  41. attocode_intel/_internal/integrations/context/trigram_regex.py +171 -0
  42. attocode_intel/_internal/integrations/context/ts_parser.py +2199 -0
  43. attocode_intel/_internal/integrations/context/vector_store.py +795 -0
  44. attocode_intel/_internal/integrations/feature_flags/__init__.py +357 -0
  45. attocode_intel/_internal/integrations/lsp/__init__.py +1 -0
  46. attocode_intel/_internal/integrations/lsp/client.py +1140 -0
  47. attocode_intel/_internal/integrations/mcp/__init__.py +1 -0
  48. attocode_intel/_internal/integrations/mcp/client.py +253 -0
  49. attocode_intel/_internal/integrations/security/__init__.py +1 -0
  50. attocode_intel/_internal/integrations/security/custom_rules.py +176 -0
  51. attocode_intel/_internal/integrations/security/dataflow.py +522 -0
  52. attocode_intel/_internal/integrations/security/dependency_audit.py +303 -0
  53. attocode_intel/_internal/integrations/security/matcher.py +44 -0
  54. attocode_intel/_internal/integrations/security/patterns.py +724 -0
  55. attocode_intel/_internal/integrations/security/scanner.py +351 -0
  56. attocode_intel/_internal/integrations/utilities/__init__.py +1 -0
  57. attocode_intel/_internal/integrations/utilities/ignore.py +64 -0
  58. attocode_intel/_internal/integrations/utilities/token_estimate.py +51 -0
  59. attocode_intel/_internal/tricks/__init__.py +1 -0
  60. attocode_intel/_internal/tricks/recursive_context.py +357 -0
  61. attocode_intel/_internal/types/__init__.py +1 -0
  62. attocode_intel/_internal/types/events.py +289 -0
  63. attocode_intel/_internal/types/severity.py +15 -0
  64. attocode_intel/_shared.py +341 -0
  65. attocode_intel/analysis_coverage.py +56 -0
  66. attocode_intel/api/__init__.py +1 -0
  67. attocode_intel/api/access.py +32 -0
  68. attocode_intel/api/app.py +247 -0
  69. attocode_intel/api/auth/__init__.py +128 -0
  70. attocode_intel/api/auth/api_keys.py +61 -0
  71. attocode_intel/api/auth/context.py +34 -0
  72. attocode_intel/api/auth/jwt.py +66 -0
  73. attocode_intel/api/auth/oauth.py +146 -0
  74. attocode_intel/api/auth/passwords.py +15 -0
  75. attocode_intel/api/deps.py +351 -0
  76. attocode_intel/api/knowledge_bridge.py +13 -0
  77. attocode_intel/api/mcp_transport.py +51 -0
  78. attocode_intel/api/middleware.py +411 -0
  79. attocode_intel/api/models.py +698 -0
  80. attocode_intel/api/providers/__init__.py +1 -0
  81. attocode_intel/api/providers/db_provider.py +1106 -0
  82. attocode_intel/api/providers/local_provider.py +476 -0
  83. attocode_intel/api/providers/remote_provider.py +740 -0
  84. attocode_intel/api/repository_source.py +21 -0
  85. attocode_intel/api/routes/__init__.py +1 -0
  86. attocode_intel/api/routes/_pin_helper.py +158 -0
  87. attocode_intel/api/routes/activity.py +148 -0
  88. attocode_intel/api/routes/adr.py +102 -0
  89. attocode_intel/api/routes/analysis.py +515 -0
  90. attocode_intel/api/routes/api_keys.py +170 -0
  91. attocode_intel/api/routes/auth.py +428 -0
  92. attocode_intel/api/routes/branches.py +262 -0
  93. attocode_intel/api/routes/cross_repo_search.py +198 -0
  94. attocode_intel/api/routes/embeddings.py +386 -0
  95. attocode_intel/api/routes/files.py +132 -0
  96. attocode_intel/api/routes/files_v2.py +388 -0
  97. attocode_intel/api/routes/gc.py +322 -0
  98. attocode_intel/api/routes/git_v2.py +433 -0
  99. attocode_intel/api/routes/graph.py +174 -0
  100. attocode_intel/api/routes/graph_viz.py +160 -0
  101. attocode_intel/api/routes/health.py +62 -0
  102. attocode_intel/api/routes/history.py +175 -0
  103. attocode_intel/api/routes/jobs.py +84 -0
  104. attocode_intel/api/routes/learning.py +205 -0
  105. attocode_intel/api/routes/lsp.py +272 -0
  106. attocode_intel/api/routes/notify.py +623 -0
  107. attocode_intel/api/routes/operations.py +27 -0
  108. attocode_intel/api/routes/orgs.py +924 -0
  109. attocode_intel/api/routes/preferences.py +100 -0
  110. attocode_intel/api/routes/presence.py +42 -0
  111. attocode_intel/api/routes/projects.py +116 -0
  112. attocode_intel/api/routes/repos.py +47 -0
  113. attocode_intel/api/routes/search.py +180 -0
  114. attocode_intel/api/routes/snapshots.py +614 -0
  115. attocode_intel/api/routes/webhooks.py +313 -0
  116. attocode_intel/api/routes/websocket.py +116 -0
  117. attocode_intel/api/static/graph.html +239 -0
  118. attocode_intel/api/utils.py +96 -0
  119. attocode_intel/artifacts/__init__.py +45 -0
  120. attocode_intel/artifacts/hashing.py +230 -0
  121. attocode_intel/artifacts/provenance.py +190 -0
  122. attocode_intel/artifacts/retrieval_pin.py +159 -0
  123. attocode_intel/audit.py +59 -0
  124. attocode_intel/bug_finder.py +206 -0
  125. attocode_intel/bundle.py +80 -0
  126. attocode_intel/catalog.py +242 -0
  127. attocode_intel/change_review.py +75 -0
  128. attocode_intel/cli.py +3062 -0
  129. attocode_intel/community.py +63 -0
  130. attocode_intel/confidence/__init__.py +144 -0
  131. attocode_intel/confidence/jev.py +234 -0
  132. attocode_intel/confidence/llm.py +330 -0
  133. attocode_intel/confidence/redact.py +44 -0
  134. attocode_intel/confidence/settings.py +74 -0
  135. attocode_intel/config.py +256 -0
  136. attocode_intel/crypto.py +31 -0
  137. attocode_intel/db/__init__.py +7 -0
  138. attocode_intel/db/base.py +33 -0
  139. attocode_intel/db/engine.py +61 -0
  140. attocode_intel/db/models.py +529 -0
  141. attocode_intel/entrypoint.py +185 -0
  142. attocode_intel/focused_evidence.py +130 -0
  143. attocode_intel/freshness.py +154 -0
  144. attocode_intel/gateway.py +734 -0
  145. attocode_intel/git/__init__.py +7 -0
  146. attocode_intel/git/credentials.py +75 -0
  147. attocode_intel/git/manager.py +493 -0
  148. attocode_intel/git/models.py +96 -0
  149. attocode_intel/git/storage.py +98 -0
  150. attocode_intel/graph_query_parser.py +761 -0
  151. attocode_intel/helpers.py +712 -0
  152. attocode_intel/indexing/__init__.py +29 -0
  153. attocode_intel/indexing/debouncer.py +136 -0
  154. attocode_intel/indexing/delta_indexer.py +151 -0
  155. attocode_intel/indexing/full_indexer.py +323 -0
  156. attocode_intel/indexing/incremental.py +240 -0
  157. attocode_intel/indexing/parser.py +403 -0
  158. attocode_intel/indexing/summarizer.py +264 -0
  159. attocode_intel/installer.py +1896 -0
  160. attocode_intel/knowledge.py +269 -0
  161. attocode_intel/local_knowledge.py +77 -0
  162. attocode_intel/migrations/alembic.ini +36 -0
  163. attocode_intel/migrations/env.py +71 -0
  164. attocode_intel/migrations/script.py.mako +27 -0
  165. attocode_intel/migrations/versions/001_initial_schema.py +219 -0
  166. attocode_intel/migrations/versions/002_branch_version_and_embeddings.py +61 -0
  167. attocode_intel/migrations/versions/003_embedding_uniqueness_and_cascade.py +51 -0
  168. attocode_intel/migrations/versions/004_audit_events.py +38 -0
  169. attocode_intel/migrations/versions/005_user_preferences.py +30 -0
  170. attocode_intel/migrations/versions/006_google_oauth.py +27 -0
  171. attocode_intel/migrations/versions/007_pgvector_embeddings.py +28 -0
  172. attocode_intel/migrations/versions/008_symbol_references.py +37 -0
  173. attocode_intel/migrations/versions/009_webhook_secret_encryption.py +25 -0
  174. attocode_intel/migrations/versions/010_add_commits_table.py +40 -0
  175. attocode_intel/migrations/versions/011_commit_changed_files.py +25 -0
  176. attocode_intel/migrations/versions/012_branch_merged_at.py +25 -0
  177. attocode_intel/migrations/versions/013_revoked_tokens.py +32 -0
  178. attocode_intel/migrations/versions/014_blame_hunks.py +40 -0
  179. attocode_intel/migrations/versions/015_commit_file_stats.py +40 -0
  180. attocode_intel/migrations/versions/016_embedding_provenance_columns.py +179 -0
  181. attocode_intel/migrations/versions/017_provenance_table.py +102 -0
  182. attocode_intel/migrations/versions/018_repo_snapshots.py +178 -0
  183. attocode_intel/migrations/versions/019_symref_caller.py +42 -0
  184. attocode_intel/migrations/versions/020_shared_knowledge.py +29 -0
  185. attocode_intel/onboarding.py +258 -0
  186. attocode_intel/output.py +178 -0
  187. attocode_intel/precision.py +133 -0
  188. attocode_intel/presence.py +160 -0
  189. attocode_intel/probe.py +110 -0
  190. attocode_intel/project_dir.py +97 -0
  191. attocode_intel/pubsub.py +113 -0
  192. attocode_intel/query_ranking.py +242 -0
  193. attocode_intel/readiness.py +972 -0
  194. attocode_intel/redis.py +51 -0
  195. attocode_intel/reference_pages.py +60 -0
  196. attocode_intel/remote.py +131 -0
  197. attocode_intel/repo_ranker.py +246 -0
  198. attocode_intel/request_context.py +82 -0
  199. attocode_intel/rules/__init__.py +28 -0
  200. attocode_intel/rules/ci.py +320 -0
  201. attocode_intel/rules/combinators.py +293 -0
  202. attocode_intel/rules/enricher.py +127 -0
  203. attocode_intel/rules/evolution.py +452 -0
  204. attocode_intel/rules/executor.py +531 -0
  205. attocode_intel/rules/filters/__init__.py +5 -0
  206. attocode_intel/rules/filters/pipeline.py +151 -0
  207. attocode_intel/rules/formatter.py +198 -0
  208. attocode_intel/rules/hygiene.py +242 -0
  209. attocode_intel/rules/importers/__init__.py +1 -0
  210. attocode_intel/rules/importers/semgrep.py +382 -0
  211. attocode_intel/rules/loader.py +292 -0
  212. attocode_intel/rules/marketplace.py +375 -0
  213. attocode_intel/rules/metavar.py +181 -0
  214. attocode_intel/rules/model.py +317 -0
  215. attocode_intel/rules/packs/__init__.py +1 -0
  216. attocode_intel/rules/packs/community/_license_templates/Apache-2.0.txt +176 -0
  217. attocode_intel/rules/packs/community/_license_templates/MIT.txt +21 -0
  218. attocode_intel/rules/packs/community/bandit-python/LICENSE +176 -0
  219. attocode_intel/rules/packs/community/bandit-python/NOTICE +13 -0
  220. attocode_intel/rules/packs/community/bandit-python/PORTING.md +23 -0
  221. attocode_intel/rules/packs/community/bandit-python/manifest.yaml +14 -0
  222. attocode_intel/rules/packs/community/bandit-python/rules/B105-hardcoded-password.yaml +23 -0
  223. attocode_intel/rules/packs/community/bandit-python/rules/B303-weak-md5.yaml +21 -0
  224. attocode_intel/rules/packs/community/bandit-python/rules/B304-weak-des.yaml +20 -0
  225. attocode_intel/rules/packs/community/bandit-python/rules/B307-use-of-eval.yaml +22 -0
  226. attocode_intel/rules/packs/community/bandit-python/rules/B324-weak-sha1.yaml +21 -0
  227. attocode_intel/rules/packs/community/bandit-python/rules/B501-no-cert-validation.yaml +23 -0
  228. attocode_intel/rules/packs/community/bandit-python/rules/B602-shell-true.yaml +22 -0
  229. attocode_intel/rules/packs/community/bandit-python/rules/B608-sqli.yaml +22 -0
  230. attocode_intel/rules/packs/community/eslint-typescript/LICENSE +21 -0
  231. attocode_intel/rules/packs/community/eslint-typescript/NOTICE +13 -0
  232. attocode_intel/rules/packs/community/eslint-typescript/PORTING.md +23 -0
  233. attocode_intel/rules/packs/community/eslint-typescript/manifest.yaml +14 -0
  234. attocode_intel/rules/packs/community/eslint-typescript/rules/eqeqeq.yaml +20 -0
  235. attocode_intel/rules/packs/community/eslint-typescript/rules/no-eval.yaml +22 -0
  236. attocode_intel/rules/packs/community/eslint-typescript/rules/no-implied-eval.yaml +20 -0
  237. attocode_intel/rules/packs/community/eslint-typescript/rules/no-new-func.yaml +21 -0
  238. attocode_intel/rules/packs/community/eslint-typescript/rules/no-throw-literal.yaml +19 -0
  239. attocode_intel/rules/packs/community/eslint-typescript/rules/no-var.yaml +20 -0
  240. attocode_intel/rules/packs/community/eslint-typescript/rules/no-with.yaml +18 -0
  241. attocode_intel/rules/packs/community/gosec-go/LICENSE +176 -0
  242. attocode_intel/rules/packs/community/gosec-go/NOTICE +13 -0
  243. attocode_intel/rules/packs/community/gosec-go/PORTING.md +23 -0
  244. attocode_intel/rules/packs/community/gosec-go/manifest.yaml +14 -0
  245. attocode_intel/rules/packs/community/gosec-go/rules/G101-hardcoded-credentials.yaml +22 -0
  246. attocode_intel/rules/packs/community/gosec-go/rules/G102-bind-all-interfaces.yaml +21 -0
  247. attocode_intel/rules/packs/community/gosec-go/rules/G103-unsafe-block.yaml +21 -0
  248. attocode_intel/rules/packs/community/gosec-go/rules/G201-sql-format.yaml +21 -0
  249. attocode_intel/rules/packs/community/gosec-go/rules/G304-file-inclusion.yaml +23 -0
  250. attocode_intel/rules/packs/community/gosec-go/rules/G401-weak-cipher.yaml +20 -0
  251. attocode_intel/rules/packs/community/gosec-go/rules/G402-tls-min-version.yaml +20 -0
  252. attocode_intel/rules/packs/community/gosec-go/rules/G501-md5-import.yaml +21 -0
  253. attocode_intel/rules/packs/examples/cpp/manifest.yaml +4 -0
  254. attocode_intel/rules/packs/examples/cpp/rules/security.yaml +90 -0
  255. attocode_intel/rules/packs/examples/cpp/rules/structural.yaml +42 -0
  256. attocode_intel/rules/packs/examples/csharp/manifest.yaml +4 -0
  257. attocode_intel/rules/packs/examples/csharp/rules/security.yaml +69 -0
  258. attocode_intel/rules/packs/examples/csharp/rules/structural.yaml +42 -0
  259. attocode_intel/rules/packs/examples/go/manifest.yaml +4 -0
  260. attocode_intel/rules/packs/examples/go/rules/performance.yaml +136 -0
  261. attocode_intel/rules/packs/examples/go/rules/security.yaml +48 -0
  262. attocode_intel/rules/packs/examples/go/rules/structural.yaml +58 -0
  263. attocode_intel/rules/packs/examples/go/taint/sanitizers.yaml +24 -0
  264. attocode_intel/rules/packs/examples/go/taint/sinks.yaml +51 -0
  265. attocode_intel/rules/packs/examples/go/taint/sources.yaml +26 -0
  266. attocode_intel/rules/packs/examples/java/manifest.yaml +4 -0
  267. attocode_intel/rules/packs/examples/java/rules/correctness.yaml +55 -0
  268. attocode_intel/rules/packs/examples/java/rules/structural.yaml +48 -0
  269. attocode_intel/rules/packs/examples/java/taint/sinks.yaml +37 -0
  270. attocode_intel/rules/packs/examples/java/taint/sources.yaml +21 -0
  271. attocode_intel/rules/packs/examples/kotlin/manifest.yaml +4 -0
  272. attocode_intel/rules/packs/examples/kotlin/rules/correctness.yaml +50 -0
  273. attocode_intel/rules/packs/examples/kotlin/rules/structural.yaml +38 -0
  274. attocode_intel/rules/packs/examples/php/manifest.yaml +4 -0
  275. attocode_intel/rules/packs/examples/php/rules/security.yaml +66 -0
  276. attocode_intel/rules/packs/examples/php/rules/structural.yaml +41 -0
  277. attocode_intel/rules/packs/examples/python/manifest.yaml +4 -0
  278. attocode_intel/rules/packs/examples/python/rules/performance.yaml +90 -0
  279. attocode_intel/rules/packs/examples/python/rules/structural.yaml +55 -0
  280. attocode_intel/rules/packs/examples/ruby/manifest.yaml +4 -0
  281. attocode_intel/rules/packs/examples/ruby/rules/security.yaml +73 -0
  282. attocode_intel/rules/packs/examples/ruby/rules/structural.yaml +41 -0
  283. attocode_intel/rules/packs/examples/rust/manifest.yaml +4 -0
  284. attocode_intel/rules/packs/examples/rust/rules/correctness.yaml +51 -0
  285. attocode_intel/rules/packs/examples/rust/rules/structural.yaml +49 -0
  286. attocode_intel/rules/packs/examples/typescript/manifest.yaml +4 -0
  287. attocode_intel/rules/packs/examples/typescript/rules/performance.yaml +70 -0
  288. attocode_intel/rules/packs/examples/typescript/rules/structural.yaml +48 -0
  289. attocode_intel/rules/packs/pack_loader.py +244 -0
  290. attocode_intel/rules/plugins/__init__.py +1 -0
  291. attocode_intel/rules/plugins/plugin_loader.py +132 -0
  292. attocode_intel/rules/profiling.py +332 -0
  293. attocode_intel/rules/registry.py +213 -0
  294. attocode_intel/rules/sarif.py +187 -0
  295. attocode_intel/rules/synthesis.py +420 -0
  296. attocode_intel/rules/testing.py +326 -0
  297. attocode_intel/server.py +734 -0
  298. attocode_intel/service.py +3416 -0
  299. attocode_intel/sharing.py +57 -0
  300. attocode_intel/storage/__init__.py +6 -0
  301. attocode_intel/storage/branch_overlay.py +352 -0
  302. attocode_intel/storage/content_store.py +220 -0
  303. attocode_intel/storage/dependency_store.py +143 -0
  304. attocode_intel/storage/diff_engine.py +187 -0
  305. attocode_intel/storage/embedding_store.py +594 -0
  306. attocode_intel/storage/provenance_store.py +137 -0
  307. attocode_intel/storage/security_scanner_db.py +164 -0
  308. attocode_intel/storage/symbol_store.py +160 -0
  309. attocode_intel/structural_evidence.py +144 -0
  310. attocode_intel/symbol_inspection.py +141 -0
  311. attocode_intel/symbol_links.py +167 -0
  312. attocode_intel/telemetry.py +42 -0
  313. attocode_intel/test_ranking.py +73 -0
  314. attocode_intel/testing/__init__.py +43 -0
  315. attocode_intel/testing/fixtures.py +122 -0
  316. attocode_intel/testing/helpers.py +75 -0
  317. attocode_intel/testing/mocks.py +99 -0
  318. attocode_intel/tools/__init__.py +2 -0
  319. attocode_intel/tools/adr_tools.py +628 -0
  320. attocode_intel/tools/analysis_tools.py +382 -0
  321. attocode_intel/tools/composite_tools.py +695 -0
  322. attocode_intel/tools/cross_mode_tools.py +173 -0
  323. attocode_intel/tools/dead_code_tools.py +582 -0
  324. attocode_intel/tools/distill_tools.py +353 -0
  325. attocode_intel/tools/frecency_tools.py +220 -0
  326. attocode_intel/tools/fuzzy_tools.py +255 -0
  327. attocode_intel/tools/history_tools.py +486 -0
  328. attocode_intel/tools/learning_tools.py +222 -0
  329. attocode_intel/tools/lsp_tools.py +218 -0
  330. attocode_intel/tools/maintenance_tools.py +1662 -0
  331. attocode_intel/tools/navigation_tools.py +220 -0
  332. attocode_intel/tools/overlay_tools.py +540 -0
  333. attocode_intel/tools/pin_store.py +432 -0
  334. attocode_intel/tools/pin_tools.py +266 -0
  335. attocode_intel/tools/query_constraints_tools.py +262 -0
  336. attocode_intel/tools/query_history_tools.py +158 -0
  337. attocode_intel/tools/readiness_tools.py +44 -0
  338. attocode_intel/tools/rule_tools.py +992 -0
  339. attocode_intel/tools/search_tools.py +770 -0
  340. attocode_intel/tools/snapshot_tools.py +624 -0
  341. attocode_intel/workers/__init__.py +1 -0
  342. attocode_intel/workers/job_utils.py +111 -0
  343. attocode_intel/workers/jobs.py +573 -0
  344. attocode_intel/workers/run.py +30 -0
  345. attocode_intel/workers/settings.py +61 -0
@@ -0,0 +1,143 @@
1
+ """Dependency storage — file-level dependency graph."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from sqlalchemy.ext.asyncio import AsyncSession
10
+
11
+
12
+ class DependencyStore:
13
+ """Content-addressed dependency storage.
14
+
15
+ Dependencies are between content SHAs, enabling deduplication.
16
+ Branch-aware queries resolve through BranchOverlay.
17
+ """
18
+
19
+ def __init__(self, session: AsyncSession) -> None:
20
+ self._session = session
21
+
22
+ async def has_dependencies(self, source_sha: str) -> bool:
23
+ """Check if dependencies already exist for a source SHA."""
24
+ from sqlalchemy import func, select
25
+
26
+ from attocode_intel.db.models import Dependency
27
+
28
+ result = await self._session.execute(
29
+ select(func.count()).where(Dependency.source_sha == source_sha)
30
+ )
31
+ return (result.scalar() or 0) > 0
32
+
33
+ async def upsert_dependencies(
34
+ self,
35
+ source_sha: str,
36
+ dependencies: list[dict],
37
+ ) -> int:
38
+ """Store dependencies from a source file.
39
+
40
+ Each dependency dict: {target_sha, dep_type, weight?, metadata?}
41
+ """
42
+ from sqlalchemy import delete
43
+
44
+ from attocode_intel.db.models import Dependency
45
+ await self._session.execute(
46
+ delete(Dependency).where(Dependency.source_sha == source_sha)
47
+ )
48
+
49
+ # Insert new
50
+ for d in dependencies:
51
+ dep = Dependency(
52
+ source_sha=source_sha,
53
+ target_sha=d["target_sha"],
54
+ dep_type=d.get("dep_type", "imports"),
55
+ weight=d.get("weight", 1.0),
56
+ metadata_=d.get("metadata", {}),
57
+ )
58
+ self._session.add(dep)
59
+
60
+ await self._session.flush()
61
+ return len(dependencies)
62
+
63
+ async def get_forward(
64
+ self,
65
+ content_sha: str,
66
+ ) -> list[dict]:
67
+ """Get dependencies FROM a file (what it imports)."""
68
+ from sqlalchemy import select
69
+
70
+ from attocode_intel.db.models import Dependency
71
+
72
+ result = await self._session.execute(
73
+ select(Dependency).where(Dependency.source_sha == content_sha)
74
+ )
75
+ return [
76
+ {
77
+ "target_sha": d.target_sha,
78
+ "dep_type": d.dep_type,
79
+ "weight": d.weight,
80
+ }
81
+ for d in result.scalars()
82
+ ]
83
+
84
+ async def get_reverse(
85
+ self,
86
+ content_sha: str,
87
+ ) -> list[dict]:
88
+ """Get reverse dependencies TO a file (what imports it)."""
89
+ from sqlalchemy import select
90
+
91
+ from attocode_intel.db.models import Dependency
92
+
93
+ result = await self._session.execute(
94
+ select(Dependency).where(Dependency.target_sha == content_sha)
95
+ )
96
+ return [
97
+ {
98
+ "source_sha": d.source_sha,
99
+ "dep_type": d.dep_type,
100
+ "weight": d.weight,
101
+ }
102
+ for d in result.scalars()
103
+ ]
104
+
105
+ async def get_graph_for_branch(
106
+ self,
107
+ branch_id: uuid.UUID,
108
+ ) -> dict:
109
+ """Build the full dependency graph for a branch.
110
+
111
+ Returns {nodes: [...], edges: [...]} resolved through overlay.
112
+ """
113
+ from sqlalchemy import select
114
+
115
+ from attocode_intel.db.models import Dependency
116
+ from attocode_intel.storage.branch_overlay import BranchOverlay
117
+
118
+ overlay = BranchOverlay(self._session)
119
+ manifest = await overlay.resolve_manifest(branch_id)
120
+ content_shas = set(manifest.values())
121
+ sha_to_path = {sha: path for path, sha in manifest.items()}
122
+
123
+ if not content_shas:
124
+ return {"nodes": [], "edges": []}
125
+
126
+ result = await self._session.execute(
127
+ select(Dependency).where(
128
+ Dependency.source_sha.in_(content_shas),
129
+ Dependency.target_sha.in_(content_shas),
130
+ )
131
+ )
132
+
133
+ nodes = [{"path": path, "sha": sha} for path, sha in manifest.items()]
134
+ edges = []
135
+ for dep in result.scalars():
136
+ edges.append({
137
+ "source": sha_to_path.get(dep.source_sha, dep.source_sha),
138
+ "target": sha_to_path.get(dep.target_sha, dep.target_sha),
139
+ "type": dep.dep_type,
140
+ "weight": dep.weight,
141
+ })
142
+
143
+ return {"nodes": nodes, "edges": edges}
@@ -0,0 +1,187 @@
1
+ """Unified diff computation from DB-stored content.
2
+
3
+ Computes line-level diffs between two branch manifests using
4
+ BranchOverlay.diff_branches() for file-level changes and
5
+ difflib.unified_diff() for line-level hunks.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import difflib
11
+ import logging
12
+ import uuid
13
+ from typing import TYPE_CHECKING
14
+
15
+ # Canonical diff models live alongside the git manager; re-exported here for
16
+ # backward compatibility with consumers that import from this module.
17
+ from attocode_intel.git.models import DiffHunk, DiffLine, PatchEntry
18
+
19
+ if TYPE_CHECKING:
20
+ from sqlalchemy.ext.asyncio import AsyncSession
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ __all__ = [
25
+ "DiffHunk",
26
+ "DiffLine",
27
+ "PatchEntry",
28
+ "compute_branch_diff",
29
+ ]
30
+
31
+
32
+ def _compute_hunks(old_text: str, new_text: str, path: str) -> list[DiffHunk]:
33
+ """Compute unified diff hunks between two text contents."""
34
+ old_lines = old_text.splitlines(keepends=True)
35
+ new_lines = new_text.splitlines(keepends=True)
36
+
37
+ diff_lines = list(difflib.unified_diff(
38
+ old_lines, new_lines,
39
+ fromfile=f"a/{path}", tofile=f"b/{path}",
40
+ lineterm="",
41
+ ))
42
+
43
+ hunks: list[DiffHunk] = []
44
+ current_hunk: DiffHunk | None = None
45
+
46
+ for line in diff_lines:
47
+ if line.startswith("@@"):
48
+ # Parse hunk header: @@ -old_start,old_lines +new_start,new_lines @@
49
+ parts = line.split("@@")
50
+ header = line.strip()
51
+ ranges = parts[1].strip().split()
52
+ old_range = ranges[0][1:] # remove '-'
53
+ new_range = ranges[1][1:] # remove '+'
54
+
55
+ old_start = int(old_range.split(",")[0]) if "," in old_range else int(old_range)
56
+ old_count = int(old_range.split(",")[1]) if "," in old_range else 1
57
+ new_start = int(new_range.split(",")[0]) if "," in new_range else int(new_range)
58
+ new_count = int(new_range.split(",")[1]) if "," in new_range else 1
59
+
60
+ current_hunk = DiffHunk(
61
+ old_start=old_start, old_lines=old_count,
62
+ new_start=new_start, new_lines=new_count,
63
+ header=header,
64
+ )
65
+ hunks.append(current_hunk)
66
+ elif current_hunk is not None:
67
+ if line.startswith("---") or line.startswith("+++"):
68
+ continue
69
+ if line.startswith("+"):
70
+ current_hunk.lines.append(DiffLine(
71
+ origin="+", content=line[1:],
72
+ ))
73
+ elif line.startswith("-"):
74
+ current_hunk.lines.append(DiffLine(
75
+ origin="-", content=line[1:],
76
+ ))
77
+ else:
78
+ current_hunk.lines.append(DiffLine(
79
+ origin=" ", content=line[1:] if line.startswith(" ") else line,
80
+ ))
81
+
82
+ # Assign line numbers
83
+ for hunk in hunks:
84
+ old_ln = hunk.old_start
85
+ new_ln = hunk.new_start
86
+ for dl in hunk.lines:
87
+ if dl.origin == "-":
88
+ dl.old_lineno = old_ln
89
+ dl.new_lineno = None
90
+ old_ln += 1
91
+ elif dl.origin == "+":
92
+ dl.old_lineno = None
93
+ dl.new_lineno = new_ln
94
+ new_ln += 1
95
+ else:
96
+ dl.old_lineno = old_ln
97
+ dl.new_lineno = new_ln
98
+ old_ln += 1
99
+ new_ln += 1
100
+
101
+ return hunks
102
+
103
+
104
+ async def compute_branch_diff(
105
+ session: AsyncSession,
106
+ branch_a_id: uuid.UUID,
107
+ branch_b_id: uuid.UUID,
108
+ path_filter: str = "",
109
+ max_files: int = 1000,
110
+ ) -> list[PatchEntry]:
111
+ """Compute line-level diff between two branches using DB-stored content.
112
+
113
+ Args:
114
+ session: Async DB session.
115
+ branch_a_id: Base branch UUID.
116
+ branch_b_id: Target branch UUID.
117
+ path_filter: Optional path prefix to filter files.
118
+ max_files: Maximum number of files to diff (prevents OOM on huge repos).
119
+
120
+ Returns:
121
+ List of PatchEntry with file-level status and line-level hunks.
122
+ """
123
+ from attocode_intel.storage.branch_overlay import BranchOverlay
124
+ from attocode_intel.storage.content_store import ContentStore
125
+
126
+ overlay = BranchOverlay(session)
127
+ content_store = ContentStore(session)
128
+
129
+ # Get file-level diff
130
+ file_diff = await overlay.diff_branches(branch_a_id, branch_b_id)
131
+
132
+ # Apply path filter
133
+ if path_filter:
134
+ file_diff = {p: s for p, s in file_diff.items() if p.startswith(path_filter)}
135
+
136
+ # Limit to max_files
137
+ paths = sorted(file_diff.keys())[:max_files]
138
+
139
+ # Resolve both manifests for content lookup
140
+ manifest_a = await overlay.resolve_manifest(branch_a_id)
141
+ manifest_b = await overlay.resolve_manifest(branch_b_id)
142
+
143
+ patches: list[PatchEntry] = []
144
+
145
+ for path in paths:
146
+ status = file_diff[path]
147
+ sha_a = manifest_a.get(path)
148
+ sha_b = manifest_b.get(path)
149
+
150
+ old_text = ""
151
+ new_text = ""
152
+
153
+ if sha_a:
154
+ data = await content_store.get(sha_a)
155
+ if data:
156
+ try:
157
+ old_text = data.decode("utf-8", errors="replace")
158
+ except Exception:
159
+ old_text = ""
160
+
161
+ if sha_b:
162
+ data = await content_store.get(sha_b)
163
+ if data:
164
+ try:
165
+ new_text = data.decode("utf-8", errors="replace")
166
+ except Exception:
167
+ new_text = ""
168
+
169
+ # Compute hunks
170
+ hunks = _compute_hunks(old_text, new_text, path)
171
+
172
+ additions = sum(
173
+ 1 for h in hunks for dl in h.lines if dl.origin == "+"
174
+ )
175
+ deletions = sum(
176
+ 1 for h in hunks for dl in h.lines if dl.origin == "-"
177
+ )
178
+
179
+ patches.append(PatchEntry(
180
+ path=path,
181
+ status=status,
182
+ additions=additions,
183
+ deletions=deletions,
184
+ hunks=hunks,
185
+ ))
186
+
187
+ return patches