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,256 @@
1
+ """Configuration for the code intelligence service."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ipaddress
6
+ import os
7
+ from dataclasses import dataclass, field
8
+ from pathlib import Path
9
+
10
+
11
+ def is_loopback(host: str) -> bool:
12
+ """True for a host that only this computer can reach."""
13
+ if host == "localhost":
14
+ return True
15
+ try:
16
+ return ipaddress.ip_address(host).is_loopback
17
+ except ValueError:
18
+ return False
19
+
20
+
21
+ @dataclass(slots=True)
22
+ class CodeIntelConfig:
23
+ """Configuration for the CodeIntelService."""
24
+
25
+ # Core settings (Phase 1)
26
+ project_dir: str = ""
27
+ host: str = "127.0.0.1"
28
+ port: int = 8080
29
+ api_key: str = ""
30
+ # No other web origin can call the API unless ATTOCODE_CORS_ORIGINS names it.
31
+ cors_origins: list[str] = field(default_factory=list)
32
+ log_level: str = "info"
33
+
34
+ # Indexing settings
35
+ file_cap: int = 5000 # Max files to index; higher = better coverage, slower bootstrap
36
+
37
+ # Service mode (multi-user)
38
+ database_url: str = ""
39
+ secret_key: str = ""
40
+ redis_url: str = ""
41
+
42
+ # Git clone settings
43
+ git_clone_dir: str = "/var/lib/code-intel/repos"
44
+ git_clone_max_gb: float = 50.0
45
+ git_ssh_key_path: str = ""
46
+
47
+ # Embedding settings
48
+ embedding_model: str = "" # auto-detect or explicit: all-MiniLM-L6-v2 | nomic-embed-text | openai
49
+ embedding_dimension: int = 0 # 0 = auto from model
50
+ embedding_nl_mode: str = "none" # "none" = embed raw code, "heuristic" = code-to-NL before embedding
51
+
52
+ # Optional local-only reranker. Both values must be supplied; a model is
53
+ # never downloaded or loaded synchronously by a search request.
54
+ local_reranker_path: str = ""
55
+ local_reranker_sha256: str = ""
56
+
57
+ # Optional shortlist ranking. Empty provider keeps the legacy local
58
+ # cross-encoder opt-in; "off" disables every model-based ranker.
59
+ ranking_provider: str = ""
60
+ ranking_endpoint: str = ""
61
+ ranking_model: str = ""
62
+ ranking_auth_env: str = ""
63
+ ranking_allow_remote: bool = False
64
+ ranking_remote_workspace: str = ""
65
+ ranking_timeout_ms: int = 0 # auto: 5s loopback, 800ms remote
66
+ ranking_max_candidates: int = 24
67
+
68
+ # Remote connection (CLI → server bridge)
69
+ remote_url: str = "" # e.g. "https://code.example.com"
70
+ remote_token: str = "" # JWT or API key for remote server
71
+ remote_repo_id: str = "" # UUID of the repo on the remote server
72
+
73
+ # GC settings
74
+ gc_merged_branch_retention_days: int = 7
75
+ gc_inactive_branch_retention_days: int = 30
76
+ gc_content_min_age_minutes: int = 60
77
+
78
+ # Auth settings
79
+ jwt_expiry_minutes: int = 60
80
+ refresh_expiry_days: int = 30
81
+ github_client_id: str = ""
82
+ github_client_secret: str = ""
83
+ google_client_id: str = ""
84
+ google_client_secret: str = ""
85
+ base_url: str = "" # e.g. "https://code.example.com" — for OAuth redirect_uri
86
+ registration_key: str = "" # When set, required in register request to prevent open signup
87
+
88
+ @property
89
+ def is_service_mode(self) -> bool:
90
+ """True when DATABASE_URL is set — enables multi-user service features."""
91
+ return bool(self.database_url)
92
+
93
+ @property
94
+ def effective_base_url(self) -> str:
95
+ """Base URL for OAuth redirect URIs. Falls back to http://host:port."""
96
+ if self.base_url:
97
+ return self.base_url.rstrip("/")
98
+ return f"http://{self.host}:{self.port}"
99
+
100
+ @classmethod
101
+ def from_env(cls) -> CodeIntelConfig:
102
+ """Build config from environment variables."""
103
+ return cls(
104
+ project_dir=os.environ.get("ATTOCODE_PROJECT_DIR", ""),
105
+ host=os.environ.get("ATTOCODE_HOST", "127.0.0.1"),
106
+ port=int(os.environ.get("ATTOCODE_PORT", "8080")),
107
+ api_key=os.environ.get("ATTOCODE_API_KEY", ""),
108
+ cors_origins=[o for o in os.environ.get("ATTOCODE_CORS_ORIGINS", "").split(",") if o],
109
+ log_level=os.environ.get("ATTOCODE_LOG_LEVEL", "info"),
110
+ file_cap=int(os.environ.get("ATTOCODE_FILE_CAP", "5000")),
111
+ database_url=os.environ.get("DATABASE_URL", ""),
112
+ secret_key=os.environ.get("SECRET_KEY", ""),
113
+ redis_url=os.environ.get("REDIS_URL", ""),
114
+ git_clone_dir=os.environ.get("GIT_CLONE_DIR", "/var/lib/code-intel/repos"),
115
+ git_clone_max_gb=float(os.environ.get("GIT_CLONE_MAX_GB", "50")),
116
+ git_ssh_key_path=os.environ.get("GIT_SSH_KEY_PATH", ""),
117
+ embedding_model=os.environ.get("ATTOCODE_EMBEDDING_MODEL", ""),
118
+ embedding_dimension=int(os.environ.get("ATTOCODE_EMBEDDING_DIMENSION", "0")),
119
+ embedding_nl_mode=os.environ.get("ATTOCODE_NL_EMBEDDING_MODE", "none"),
120
+ local_reranker_path=os.environ.get("ATTOCODE_INTEL_RERANKER_PATH", ""),
121
+ local_reranker_sha256=os.environ.get("ATTOCODE_INTEL_RERANKER_SHA256", ""),
122
+ ranking_provider=os.environ.get("ATTOCODE_INTEL_RANKING_PROVIDER", ""),
123
+ ranking_endpoint=os.environ.get("ATTOCODE_INTEL_RANKING_ENDPOINT", ""),
124
+ ranking_model=os.environ.get("ATTOCODE_INTEL_RANKING_MODEL", ""),
125
+ ranking_auth_env=os.environ.get("ATTOCODE_INTEL_RANKING_AUTH_ENV", ""),
126
+ ranking_allow_remote=os.environ.get("ATTOCODE_INTEL_RANKING_ALLOW_REMOTE", "").lower()
127
+ in {"1", "true", "yes", "on"},
128
+ ranking_remote_workspace=os.environ.get("ATTOCODE_INTEL_RANKING_REMOTE_WORKSPACE", ""),
129
+ ranking_timeout_ms=int(os.environ.get("ATTOCODE_INTEL_RANKING_TIMEOUT_MS", "0")),
130
+ ranking_max_candidates=int(os.environ.get("ATTOCODE_INTEL_RANKING_MAX_CANDIDATES", "24")),
131
+ gc_merged_branch_retention_days=int(os.environ.get("GC_MERGED_BRANCH_RETENTION_DAYS", "7")),
132
+ gc_inactive_branch_retention_days=int(os.environ.get("GC_INACTIVE_BRANCH_RETENTION_DAYS", "30")),
133
+ gc_content_min_age_minutes=int(os.environ.get("GC_CONTENT_MIN_AGE_MINUTES", "60")),
134
+ jwt_expiry_minutes=int(os.environ.get("JWT_EXPIRY_MINUTES", "60")),
135
+ refresh_expiry_days=int(os.environ.get("REFRESH_EXPIRY_DAYS", "30")),
136
+ github_client_id=os.environ.get("GITHUB_CLIENT_ID", ""),
137
+ github_client_secret=os.environ.get("GITHUB_CLIENT_SECRET", ""),
138
+ google_client_id=os.environ.get("GOOGLE_CLIENT_ID", ""),
139
+ google_client_secret=os.environ.get("GOOGLE_CLIENT_SECRET", ""),
140
+ base_url=os.environ.get("ATTOCODE_BASE_URL", ""),
141
+ registration_key=os.environ.get("REGISTRATION_KEY", ""),
142
+ remote_url=os.environ.get("ATTOCODE_REMOTE_URL", ""),
143
+ remote_token=os.environ.get("ATTOCODE_REMOTE_TOKEN", ""),
144
+ remote_repo_id=os.environ.get("ATTOCODE_REMOTE_REPO_ID", ""),
145
+ )
146
+
147
+
148
+ @dataclass(slots=True)
149
+ class RemoteConfig:
150
+ """Remote server connection configuration, persisted to .attocode/config.toml."""
151
+
152
+ server: str = ""
153
+ token: str = ""
154
+ repo_id: str = ""
155
+ branch_auto_detect: bool = True
156
+
157
+ @property
158
+ def is_configured(self) -> bool:
159
+ return bool(self.server and self.token)
160
+
161
+
162
+ def token_is_expired(token: str, *, leeway_seconds: int = 30) -> bool:
163
+ """Best-effort check whether a JWT's ``exp`` claim is in the past.
164
+
165
+ Decodes the token payload WITHOUT verifying the signature — we don't hold
166
+ the remote server's signing key, we only need the expiry. Returns ``False``
167
+ when the token has no ``exp`` claim or can't be parsed (we can't prove it's
168
+ expired, so let the reachability probe decide). ``leeway_seconds`` treats a
169
+ token as expired slightly early so we don't start a session on a token
170
+ about to lapse.
171
+ """
172
+ import base64
173
+ import json
174
+ import time
175
+
176
+ parts = token.split(".")
177
+ if len(parts) != 3:
178
+ return False
179
+ try:
180
+ payload_b64 = parts[1] + "=" * (-len(parts[1]) % 4)
181
+ payload = json.loads(base64.urlsafe_b64decode(payload_b64))
182
+ except Exception:
183
+ return False
184
+ exp = payload.get("exp")
185
+ if not isinstance(exp, (int, float)):
186
+ return False
187
+ return time.time() >= (float(exp) - leeway_seconds)
188
+
189
+
190
+ def load_remote_config(project_dir: str) -> RemoteConfig:
191
+ """Load remote config from .attocode/config.toml, falling back to env vars."""
192
+ config_path = Path(project_dir) / ".attocode" / "config.toml"
193
+
194
+ rc = RemoteConfig()
195
+
196
+ if config_path.exists():
197
+ try:
198
+ import tomllib
199
+ data = tomllib.loads(config_path.read_text(encoding="utf-8"))
200
+ remote = data.get("remote", {})
201
+ rc.server = remote.get("server", "")
202
+ rc.token = remote.get("token", "")
203
+ rc.repo_id = remote.get("repo_id", "")
204
+ rc.branch_auto_detect = remote.get("branch_auto_detect", True)
205
+ except Exception:
206
+ pass
207
+
208
+ # Env vars override file config
209
+ if os.environ.get("ATTOCODE_REMOTE_URL"):
210
+ rc.server = os.environ["ATTOCODE_REMOTE_URL"]
211
+ if os.environ.get("ATTOCODE_REMOTE_TOKEN"):
212
+ rc.token = os.environ["ATTOCODE_REMOTE_TOKEN"]
213
+ if os.environ.get("ATTOCODE_REMOTE_REPO_ID"):
214
+ rc.repo_id = os.environ["ATTOCODE_REMOTE_REPO_ID"]
215
+
216
+ return rc
217
+
218
+
219
+ def save_remote_config(project_dir: str, rc: RemoteConfig) -> Path:
220
+ """Save remote config to .attocode/config.toml. Returns the config path."""
221
+ config_path = Path(project_dir) / ".attocode" / "config.toml"
222
+ config_path.parent.mkdir(parents=True, exist_ok=True)
223
+
224
+ # Preserve existing config sections
225
+ existing: dict = {}
226
+ if config_path.exists():
227
+ try:
228
+ import tomllib
229
+ existing = tomllib.loads(config_path.read_text(encoding="utf-8"))
230
+ except Exception:
231
+ pass
232
+
233
+ existing["remote"] = {
234
+ "server": rc.server,
235
+ "token": rc.token,
236
+ "repo_id": rc.repo_id,
237
+ "branch_auto_detect": rc.branch_auto_detect,
238
+ }
239
+
240
+ # Write TOML manually (tomllib is read-only, avoid tomli_w dependency)
241
+ lines: list[str] = []
242
+ for section, values in existing.items():
243
+ if isinstance(values, dict):
244
+ lines.append(f"[{section}]")
245
+ for k, v in values.items():
246
+ if isinstance(v, bool):
247
+ lines.append(f"{k} = {'true' if v else 'false'}")
248
+ elif isinstance(v, str):
249
+ esc = v.replace("\\", "\\\\").replace('"', '\\"')
250
+ lines.append(f'{k} = "{esc}"')
251
+ else:
252
+ lines.append(f"{k} = {v}")
253
+ lines.append("")
254
+
255
+ config_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
256
+ return config_path
@@ -0,0 +1,31 @@
1
+ """Encryption utilities for credential storage using Fernet."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import base64
6
+ import hashlib
7
+ from typing import TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from cryptography.fernet import Fernet
11
+
12
+
13
+ def _get_fernet() -> Fernet:
14
+ """Get Fernet instance using SECRET_KEY from config."""
15
+ from cryptography.fernet import Fernet
16
+
17
+ from attocode_intel.api.deps import get_config
18
+
19
+ config = get_config()
20
+ key = hashlib.sha256(config.secret_key.encode()).digest()
21
+ return Fernet(base64.urlsafe_b64encode(key))
22
+
23
+
24
+ def encrypt_credential(plaintext: str) -> bytes:
25
+ """Encrypt a credential value for storage."""
26
+ return _get_fernet().encrypt(plaintext.encode())
27
+
28
+
29
+ def decrypt_credential(encrypted: bytes) -> str:
30
+ """Decrypt a stored credential value."""
31
+ return _get_fernet().decrypt(encrypted).decode()
@@ -0,0 +1,7 @@
1
+ """Database layer for service mode (PostgreSQL + SQLAlchemy async).
2
+
3
+ These modules require SQLAlchemy/asyncpg (service mode dependencies).
4
+ Import them directly when needed:
5
+ from attocode_intel.db.engine import init_engine, dispose_engine, get_session
6
+ from attocode_intel.db.models import Organization, User, ...
7
+ """
@@ -0,0 +1,33 @@
1
+ """SQLAlchemy declarative base and common mixins."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+ from datetime import datetime
7
+
8
+ from sqlalchemy import DateTime, func
9
+ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
10
+
11
+
12
+ class Base(DeclarativeBase):
13
+ """Base class for all ORM models."""
14
+
15
+
16
+ class TimestampMixin:
17
+ """Adds created_at and updated_at columns."""
18
+
19
+ created_at: Mapped[datetime] = mapped_column(
20
+ DateTime(timezone=True),
21
+ server_default=func.now(),
22
+ nullable=False,
23
+ )
24
+ updated_at: Mapped[datetime] = mapped_column(
25
+ DateTime(timezone=True),
26
+ server_default=func.now(),
27
+ onupdate=func.now(),
28
+ nullable=False,
29
+ )
30
+
31
+
32
+ def generate_uuid() -> uuid.UUID:
33
+ return uuid.uuid4()
@@ -0,0 +1,61 @@
1
+ """Async SQLAlchemy engine and session management."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from typing import TYPE_CHECKING, AsyncGenerator
7
+
8
+ from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
9
+
10
+ if TYPE_CHECKING:
11
+ from sqlalchemy.ext.asyncio import AsyncEngine
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ _engine: AsyncEngine | None = None
16
+ _session_factory: async_sessionmaker[AsyncSession] | None = None
17
+
18
+
19
+ def init_engine(database_url: str) -> None:
20
+ """Create the async engine and session factory.
21
+
22
+ Args:
23
+ database_url: PostgreSQL connection string (postgresql+asyncpg://...).
24
+ """
25
+ global _engine, _session_factory
26
+
27
+ if _engine is not None:
28
+ logger.warning("init_engine() called more than once; disposing previous engine")
29
+
30
+ _engine = create_async_engine(
31
+ database_url,
32
+ pool_size=10,
33
+ max_overflow=20,
34
+ pool_pre_ping=True,
35
+ echo=False,
36
+ )
37
+ _session_factory = async_sessionmaker(_engine, expire_on_commit=False)
38
+ logger.info("Database engine initialized")
39
+
40
+
41
+ async def dispose_engine() -> None:
42
+ """Dispose the async engine, closing all connections."""
43
+ global _engine, _session_factory
44
+ if _engine is not None:
45
+ await _engine.dispose()
46
+ _engine = None
47
+ _session_factory = None
48
+ logger.info("Database engine disposed")
49
+
50
+
51
+ async def get_session() -> AsyncGenerator[AsyncSession, None]:
52
+ """Yield an async session. For use as a FastAPI dependency."""
53
+ if _session_factory is None:
54
+ raise RuntimeError("Database not initialized. Call init_engine() first.")
55
+ async with _session_factory() as session:
56
+ yield session
57
+
58
+
59
+ def get_engine() -> AsyncEngine | None:
60
+ """Return the current engine (or None if not initialized)."""
61
+ return _engine