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,94 @@
1
+ """Syntax evidence shared by navigation and optional precise lookup.
2
+
3
+ These candidates describe source syntax, not type-resolved relationships.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ from pathlib import Path
8
+
9
+
10
+ def rust_imports(node, source: bytes) -> list[dict]:
11
+ def text(n):
12
+ return source[n.start_byte:n.end_byte].decode()
13
+
14
+ line = node.start_point[0] + 1
15
+ if node.type == "mod_item":
16
+ name = node.child_by_field_name("name")
17
+ return ([{"module": "mod:" + text(name), "start_line": line}]
18
+ if name and not node.child_by_field_name("body") else [])
19
+ result = []
20
+
21
+ def visit(n, prefix=""):
22
+ if n.type == "scoped_use_list":
23
+ path = n.child_by_field_name("path")
24
+ visit(n.child_by_field_name("list"), prefix + (text(path) + "::" if path else ""))
25
+ elif n.type == "use_list":
26
+ for child in n.named_children:
27
+ visit(child, prefix)
28
+ else:
29
+ path = n.child_by_field_name("path") if n.type == "use_as_clause" else n
30
+ alias = n.child_by_field_name("alias") if n.type == "use_as_clause" else None
31
+ module = prefix + text(path)
32
+ module = module.removesuffix("::self")
33
+ name = module.rsplit("::", 1)[-1]
34
+ result.append({"module": module, "names": [] if name == "*" else [name],
35
+ "alias": text(alias) if alias else "", "start_line": line})
36
+
37
+ argument = node.child_by_field_name("argument")
38
+ if argument:
39
+ visit(argument)
40
+ return result
41
+
42
+
43
+ def syntax_tree(path: str, content: str, language: str):
44
+ from .ts_parser import _get_parser
45
+ parser = _get_parser("tsx" if Path(path).suffix == ".tsx" else language)
46
+ return parser.parse(content.encode()) if parser else None
47
+
48
+
49
+ def reference_candidates(path: str, content: str, language: str):
50
+ """Return call/type candidates, or None when syntax parsing is unavailable."""
51
+ tree = syntax_tree(path, content, language)
52
+ if tree is None:
53
+ return None
54
+ source = content.encode()
55
+ result = []
56
+ stack = [tree.root_node]
57
+ while stack:
58
+ node = stack.pop()
59
+ if node.type in {"comment", "line_comment", "block_comment", "string", "string_literal"}:
60
+ continue
61
+ if node.type in {"call", "call_expression", "method_invocation", "object_creation_expression", "new_expression"}:
62
+ target = (node.child_by_field_name("function") or node.child_by_field_name("name")
63
+ or node.child_by_field_name("constructor"))
64
+ if target:
65
+ # Generic Rust calls have a wrapper around their function path.
66
+ target = target.child_by_field_name("function") or target
67
+ name = source[target.start_byte:target.end_byte].decode().replace("::", ".")
68
+ if all(part.isidentifier() for part in name.split(".")):
69
+ result.append((name, "call", target.start_point[0] + 1))
70
+ if language == "rust" and "." in name:
71
+ result.append((name.rsplit(".", 1)[0], "attribute", target.start_point[0] + 1))
72
+ stack.extend(reversed(node.named_children))
73
+ return result
74
+
75
+
76
+ def symbol_position(path: str, name: str, start_line: int, end_line: int, language: str):
77
+ """Locate the identifier token, returning LSP's UTF-16 position."""
78
+ content = Path(path).read_text(encoding="utf-8")
79
+ tree = syntax_tree(path, content, language)
80
+ if tree is None:
81
+ return None
82
+ source = content.encode()
83
+ stack = [tree.root_node]
84
+ while stack:
85
+ node = stack.pop()
86
+ line = node.start_point[0] + 1
87
+ if node.end_point[0] + 1 < start_line or line > end_line:
88
+ continue
89
+ if (node.type in {"identifier", "type_identifier", "property_identifier", "field_identifier"}
90
+ and source[node.start_byte:node.end_byte].decode() == name):
91
+ prefix = source[:node.start_byte].rsplit(b"\n", 1)[-1].decode()
92
+ return line - 1, len(prefix.encode("utf-16-le")) // 2
93
+ stack.extend(reversed(node.named_children))
94
+ return None
@@ -0,0 +1,245 @@
1
+ """Bounded, opt-in SystemOne shortlist ranking over an explicit HTTP endpoint.
2
+
3
+ This is a wire-protocol adapter, not a model recommendation. In particular,
4
+ being compatible with ``POST /v1/systemone`` says nothing about code-search
5
+ quality. No request is made during construction or for a disabled provider.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import ipaddress
11
+ import json
12
+ import math
13
+ import os
14
+ import re
15
+ import threading
16
+ from urllib.parse import urlsplit
17
+
18
+ import httpx
19
+
20
+ from attocode_intel._internal.integrations.context.reranker import RankingOutcome
21
+ from attocode_intel.confidence.redact import redact
22
+
23
+ _MAX_RESPONSE_BYTES = 64 * 1024
24
+ _REMOTE_BLOCKED = {"1", "true", "yes", "on"}
25
+
26
+
27
+ class SystemOneChoiceReranker:
28
+ """One ``choice`` request for a bounded page of distinct files.
29
+
30
+ The timeout is a whole-call deadline. A timed-out worker retains the one
31
+ in-flight slot until it exits, so a stalled endpoint cannot create an
32
+ unbounded queue. Responses must contain a complete probability distribution.
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ endpoint: str,
38
+ *,
39
+ model: str = "",
40
+ auth_env: str = "",
41
+ allow_remote: bool = False,
42
+ service_mode: bool = False,
43
+ max_candidates: int = 24,
44
+ timeout_seconds: float | None = None,
45
+ max_query_chars: int = 512,
46
+ max_excerpt_chars: int = 1350,
47
+ transport: httpx.BaseTransport | None = None,
48
+ ) -> None:
49
+ parsed = urlsplit(endpoint)
50
+ try:
51
+ host = parsed.hostname
52
+ _ = parsed.port
53
+ except ValueError as exc:
54
+ raise ValueError("invalid ranking endpoint") from exc
55
+ if (
56
+ parsed.scheme not in {"http", "https"}
57
+ or not host
58
+ or not parsed.path
59
+ or parsed.username
60
+ or parsed.password
61
+ or parsed.query
62
+ or parsed.fragment
63
+ ):
64
+ raise ValueError(
65
+ "ranking endpoint must be an absolute HTTP(S) URL without credentials or query"
66
+ )
67
+ try:
68
+ loopback = ipaddress.ip_address(host).is_loopback
69
+ except ValueError:
70
+ # A hostname can resolve differently between validation and use.
71
+ # Local source access requires an explicit loopback IP literal.
72
+ loopback = False
73
+ if not loopback and parsed.scheme != "https":
74
+ raise ValueError("non-loopback ranking endpoints require HTTPS")
75
+ if not loopback and (
76
+ not allow_remote
77
+ or service_mode
78
+ or os.environ.get("ATTOCODE_LOCAL_ONLY", "").lower() in _REMOTE_BLOCKED
79
+ ):
80
+ raise ValueError("remote source ranking is not permitted")
81
+ if auth_env and re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", auth_env) is None:
82
+ raise ValueError("ranking credential must be an environment-variable name")
83
+ if timeout_seconds is None:
84
+ timeout_seconds = 5.0 if loopback else 0.8
85
+ if not 1 <= max_candidates <= 64 or not 0 < timeout_seconds <= 30:
86
+ raise ValueError("invalid ranking limits")
87
+ if min(max_query_chars, max_excerpt_chars) < 1:
88
+ raise ValueError("ranking text limits must be positive")
89
+ self.endpoint = endpoint
90
+ self.model = model
91
+ self.auth_env = auth_env
92
+ self.remote = not loopback
93
+ self.max_candidates = max_candidates
94
+ self.timeout_seconds = timeout_seconds
95
+ self.max_query_chars = max_query_chars
96
+ self.max_excerpt_chars = max_excerpt_chars
97
+ self._transport = transport
98
+ self._inflight = threading.Lock()
99
+
100
+ @property
101
+ def status(self) -> str:
102
+ return "configured"
103
+
104
+ @property
105
+ def is_available(self) -> bool:
106
+ return True
107
+
108
+ def _post(self, body: dict, headers: dict[str, str]) -> dict:
109
+ # Do not inherit proxy settings or follow a redirect to a different
110
+ # origin; both could silently send source to an unapproved host.
111
+ with (
112
+ httpx.Client(
113
+ timeout=self.timeout_seconds,
114
+ trust_env=False,
115
+ follow_redirects=False,
116
+ transport=self._transport,
117
+ ) as client,
118
+ client.stream("POST", self.endpoint, json=body, headers=headers) as response,
119
+ ):
120
+ response.raise_for_status()
121
+ chunks: list[bytes] = []
122
+ size = 0
123
+ for chunk in response.iter_bytes():
124
+ size += len(chunk)
125
+ if size > _MAX_RESPONSE_BYTES:
126
+ raise ValueError("ranking response too large")
127
+ chunks.append(chunk)
128
+ result = json.loads(b"".join(chunks))
129
+ if not isinstance(result, dict):
130
+ raise ValueError("invalid ranking response")
131
+ # Workers AI wraps every answer as {"result": {...}, "success": true, "errors": []}.
132
+ inner = result.get("result")
133
+ if "answers" not in result and isinstance(inner, dict):
134
+ if result.get("success") is not True or result.get("errors"):
135
+ raise ValueError("ranking provider reported a failure")
136
+ result = {"model": result["model"], **inner} if "model" in result else inner
137
+ return result
138
+
139
+ @staticmethod
140
+ def _scores(response: dict, count: int) -> list[float]:
141
+ answers = response.get("answers")
142
+ answer = answers.get("best") if isinstance(answers, dict) else None
143
+ probabilities = answer.get("probabilities") if isinstance(answer, dict) else None
144
+ choice = answer.get("choice") if isinstance(answer, dict) else None
145
+ expected = {str(index) for index in range(count)}
146
+ if (
147
+ not isinstance(probabilities, dict)
148
+ or set(probabilities) != expected
149
+ or not isinstance(choice, str)
150
+ or choice not in expected
151
+ ):
152
+ raise ValueError("incomplete ranking probabilities")
153
+ scores = [probabilities[str(index)] for index in range(count)]
154
+ if any(
155
+ isinstance(score, bool)
156
+ or not isinstance(score, int | float)
157
+ or not math.isfinite(score)
158
+ or not 0 <= score <= 1
159
+ for score in scores
160
+ ):
161
+ raise ValueError("invalid ranking probability")
162
+ numeric = [float(score) for score in scores]
163
+ if not 0.95 <= sum(numeric) <= 1.05:
164
+ raise ValueError("ranking probabilities do not sum to one")
165
+ if numeric[int(choice)] < max(numeric) - 1e-6:
166
+ raise ValueError("choice disagrees with ranking probabilities")
167
+ return numeric
168
+
169
+ def rerank_result(
170
+ self,
171
+ query: str,
172
+ candidates: list[tuple[str, str, float]],
173
+ top_k: int = 10,
174
+ ) -> RankingOutcome:
175
+ fallback = candidates[: max(0, top_k)]
176
+ if top_k <= 0 or not candidates:
177
+ return RankingOutcome(fallback, False, "empty")
178
+ if not query.strip():
179
+ return RankingOutcome(fallback, False, "empty_query")
180
+ if self.remote and os.environ.get("ATTOCODE_LOCAL_ONLY", "").lower() in _REMOTE_BLOCKED:
181
+ return RankingOutcome(fallback, False, "remote_disabled")
182
+ token = os.environ.get(self.auth_env) if self.auth_env else None
183
+ if self.auth_env and not token:
184
+ return RankingOutcome(fallback, False, "missing_credential")
185
+ bounded = candidates[: self.max_candidates]
186
+ question = {
187
+ "best": {
188
+ "type": "choice",
189
+ "instructions": "Which source file most directly implements the behavior in the query?",
190
+ "criteria": {
191
+ str(index): excerpt[: self.max_excerpt_chars]
192
+ for index, (_id, excerpt, _score) in enumerate(bounded)
193
+ },
194
+ },
195
+ }
196
+ state = {
197
+ "query": query[: self.max_query_chars],
198
+ "task": "Find the primary implementation file, not an incidental match.",
199
+ }
200
+ if self.remote:
201
+ state["query"] = redact(state["query"])
202
+ question["best"]["criteria"] = {
203
+ key: redact(value) for key, value in question["best"]["criteria"].items()
204
+ }
205
+ body = {"state": state, "questions": question}
206
+ if self.model:
207
+ body["model"] = self.model
208
+ headers = {"Authorization": f"Bearer {token}"} if token else {}
209
+ if not self._inflight.acquire(blocking=False):
210
+ return RankingOutcome(fallback, False, "busy")
211
+ done = threading.Event()
212
+ output: list[tuple[str, list[float] | None]] = []
213
+
214
+ def predict() -> None:
215
+ try:
216
+ response = self._post(body, headers)
217
+ if self.model and response.get("model") not in {None, self.model}:
218
+ raise ValueError("unexpected ranking model")
219
+ output.append(("ok", self._scores(response, len(bounded))))
220
+ except ValueError:
221
+ output.append(("invalid_response", None))
222
+ except (httpx.HTTPError, json.JSONDecodeError, OSError):
223
+ output.append(("transport_error", None))
224
+ except Exception:
225
+ output.append(("provider_error", None))
226
+ finally:
227
+ self._inflight.release()
228
+ done.set()
229
+
230
+ try:
231
+ threading.Thread(target=predict, name="systemone-ranker", daemon=True).start()
232
+ except RuntimeError:
233
+ self._inflight.release()
234
+ return RankingOutcome(fallback, False, "provider_error")
235
+ if not done.wait(self.timeout_seconds):
236
+ return RankingOutcome(fallback, False, "timeout")
237
+ status, scores = output[0]
238
+ if scores is None:
239
+ return RankingOutcome(fallback, False, status)
240
+ scored = [
241
+ (candidate_id, excerpt, score)
242
+ for (candidate_id, excerpt, _original), score in zip(bounded, scores, strict=True)
243
+ ]
244
+ scored.sort(key=lambda item: item[2], reverse=True)
245
+ return RankingOutcome((scored + candidates[self.max_candidates :])[:top_k], True)