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,244 @@
1
+ """Language pack loader — discovers and loads user-activated analysis packs.
2
+
3
+ Packs provide language-specific rules and few-shot examples. Example packs ship with attocode under ``packs/examples/``
4
+ but are NOT auto-loaded. Users activate packs by copying them to
5
+ ``.attocode/packs/<name>/`` in their project.
6
+
7
+ Each pack directory contains:
8
+ - ``manifest.yaml`` — metadata (name, version, languages, description)
9
+ - ``rules/*.yaml`` — YAML rule definitions
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import logging
15
+ import os
16
+ import shutil
17
+ from dataclasses import dataclass, field
18
+ from pathlib import Path
19
+
20
+ from attocode_intel.rules.loader import load_yaml_rules
21
+ from attocode_intel.rules.model import RuleSource, UnifiedRule
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ # Example packs ship here — NOT auto-loaded
26
+ _EXAMPLES_DIR = Path(__file__).parent / "examples"
27
+
28
+ # Community packs (imported from upstream sources like semgrep-rules, bandit,
29
+ # gosec) ship under ``community/`` with their own LICENSE + NOTICE files.
30
+ # They are NOT auto-loaded — the rule-bench harness loads them explicitly.
31
+ _COMMUNITY_DIR = Path(__file__).parent / "community"
32
+
33
+
34
+ @dataclass(slots=True)
35
+ class PackManifest:
36
+ """Parsed pack manifest."""
37
+
38
+ name: str
39
+ version: str = "1.0.0"
40
+ languages: list[str] = field(default_factory=list)
41
+ description: str = ""
42
+ pack_dir: str = ""
43
+
44
+ # Provenance fields — populated by the community pack importer.
45
+ # Kept additive so older manifests (without these keys) continue to load.
46
+ source: str = "" # "community" | "example" | "user"
47
+ source_url: str = ""
48
+ source_commit: str = ""
49
+ source_license: str = "" # SPDX identifier
50
+ attribution: str = "" # human-readable attribution string
51
+ imported_at: str = "" # ISO-8601 timestamp
52
+ upstream_rule_count: int = 0
53
+ imported_rule_count: int = 0
54
+
55
+
56
+ def _load_manifest(pack_dir: Path) -> PackManifest | None:
57
+ """Load manifest.yaml from a pack directory."""
58
+ manifest_path = pack_dir / "manifest.yaml"
59
+ if not manifest_path.is_file():
60
+ return PackManifest(
61
+ name=pack_dir.name,
62
+ languages=[pack_dir.name],
63
+ pack_dir=str(pack_dir),
64
+ )
65
+
66
+ try:
67
+ import yaml # type: ignore[import-untyped]
68
+ except ImportError:
69
+ return PackManifest(
70
+ name=pack_dir.name,
71
+ languages=[pack_dir.name],
72
+ pack_dir=str(pack_dir),
73
+ )
74
+
75
+ try:
76
+ data = yaml.safe_load(manifest_path.read_text(encoding="utf-8")) or {}
77
+ except Exception as exc:
78
+ logger.warning("Failed to parse manifest %s: %s", manifest_path, exc)
79
+ return None
80
+
81
+ return PackManifest(
82
+ name=str(data.get("name", pack_dir.name)),
83
+ version=str(data.get("version", "1.0.0")),
84
+ languages=data.get("languages", [pack_dir.name]),
85
+ description=str(data.get("description", "")),
86
+ pack_dir=str(pack_dir),
87
+ source=str(data.get("source", "")),
88
+ source_url=str(data.get("source_url", "")),
89
+ source_commit=str(data.get("source_commit", "")),
90
+ source_license=str(data.get("source_license", "")),
91
+ attribution=str(data.get("attribution", "")),
92
+ imported_at=str(data.get("imported_at", "")),
93
+ upstream_rule_count=int(data.get("upstream_rule_count", 0) or 0),
94
+ imported_rule_count=int(data.get("imported_rule_count", 0) or 0),
95
+ )
96
+
97
+
98
+ def _load_pack_rules(pack_dir: Path, manifest: PackManifest) -> list[UnifiedRule]:
99
+ """Load all rules from a pack's rules/ directory."""
100
+ rules_dir = pack_dir / "rules"
101
+ if not rules_dir.is_dir():
102
+ rules_dir = pack_dir
103
+
104
+ return load_yaml_rules(
105
+ rules_dir,
106
+ source=RuleSource.PACK,
107
+ pack=manifest.name,
108
+ )
109
+
110
+
111
+ def discover_packs(project_dir: str = "") -> list[PackManifest]:
112
+ """Discover user-activated packs from ``.attocode/packs/``.
113
+
114
+ Only loads packs the user has explicitly placed in their project.
115
+ Example packs under ``packs/examples/`` are NOT auto-loaded.
116
+
117
+ Returns:
118
+ List of pack manifests sorted by name.
119
+ """
120
+ manifests: list[PackManifest] = []
121
+
122
+ if project_dir:
123
+ user_packs = Path(project_dir) / ".attocode" / "packs"
124
+ if user_packs.is_dir():
125
+ for entry in sorted(user_packs.iterdir()):
126
+ if entry.is_dir() and not entry.name.startswith("_"):
127
+ m = _load_manifest(entry)
128
+ if m:
129
+ manifests.append(m)
130
+
131
+ return manifests
132
+
133
+
134
+ def list_example_packs() -> list[PackManifest]:
135
+ """List available example packs (shipped but not auto-loaded).
136
+
137
+ These can be installed into a project via ``install_pack()``.
138
+ """
139
+ manifests: list[PackManifest] = []
140
+ if _EXAMPLES_DIR.is_dir():
141
+ for entry in sorted(_EXAMPLES_DIR.iterdir()):
142
+ if entry.is_dir() and not entry.name.startswith("_"):
143
+ m = _load_manifest(entry)
144
+ if m:
145
+ manifests.append(m)
146
+ return manifests
147
+
148
+
149
+ def list_community_packs() -> list[PackManifest]:
150
+ """List community packs imported from upstream sources.
151
+
152
+ Community packs live under ``packs/community/<name>/`` with their own
153
+ ``LICENSE`` and ``NOTICE`` files. They are NOT auto-loaded — the
154
+ rule-bench harness loads them explicitly when running evaluations.
155
+ """
156
+ manifests: list[PackManifest] = []
157
+ if _COMMUNITY_DIR.is_dir():
158
+ for entry in sorted(_COMMUNITY_DIR.iterdir()):
159
+ if entry.is_dir() and not entry.name.startswith("_"):
160
+ m = _load_manifest(entry)
161
+ if m:
162
+ manifests.append(m)
163
+ return manifests
164
+
165
+
166
+ def get_community_pack_dir() -> Path:
167
+ """Return the directory where community packs are stored."""
168
+ return _COMMUNITY_DIR
169
+
170
+
171
+ def install_pack(pack_name: str, project_dir: str) -> str:
172
+ """Copy an example pack into ``.attocode/packs/<name>/``.
173
+
174
+ Args:
175
+ pack_name: Name of the example pack (go, python, typescript, rust, java).
176
+ project_dir: Project root directory.
177
+
178
+ Returns:
179
+ Status message.
180
+ """
181
+ source = _EXAMPLES_DIR / pack_name
182
+ if not source.is_dir():
183
+ available = [d.name for d in _EXAMPLES_DIR.iterdir() if d.is_dir() and not d.name.startswith("_")]
184
+ return f"Pack '{pack_name}' not found. Available: {', '.join(available)}"
185
+
186
+ dest = Path(project_dir) / ".attocode" / "packs" / pack_name
187
+ if dest.is_dir():
188
+ return f"Pack '{pack_name}' already installed at {dest}. Delete it first to reinstall."
189
+
190
+ dest.parent.mkdir(parents=True, exist_ok=True)
191
+ shutil.copytree(str(source), str(dest))
192
+
193
+ manifest = _load_manifest(dest)
194
+ rule_count = len(_load_pack_rules(dest, manifest)) if manifest else 0
195
+
196
+ return (
197
+ f"Installed pack '{pack_name}' to {dest}\n"
198
+ f" Rules: {rule_count}\n"
199
+ f" Languages: {', '.join(manifest.languages) if manifest else pack_name}\n"
200
+ f" Customize rules in {dest}/rules/*.yaml"
201
+ )
202
+
203
+
204
+ def load_pack(manifest: PackManifest) -> list[UnifiedRule]:
205
+ """Load all rules from a single pack."""
206
+ pack_dir = Path(manifest.pack_dir)
207
+ rules = _load_pack_rules(pack_dir, manifest)
208
+ if rules:
209
+ logger.info(
210
+ "Pack '%s': loaded %d rules for %s",
211
+ manifest.name, len(rules), ", ".join(manifest.languages),
212
+ )
213
+ return rules
214
+
215
+
216
+ def load_all_packs(
217
+ project_dir: str = "", *, include_shipped: bool | None = None,
218
+ ) -> tuple[list[PackManifest], list[UnifiedRule]]:
219
+ """Discover and load packs.
220
+
221
+ Loads user-activated packs from ``.attocode/packs/`` and, by default, the
222
+ shipped example packs (the language packs that carry the ast-grep
223
+ structural rules) — otherwise the engine would ship with only the builtin
224
+ regex rules. A user-installed pack shadows the shipped pack of the same
225
+ name. Set ``ATTOCODE_NO_SHIPPED_PACKS=1`` (or ``include_shipped=False``)
226
+ to load only user packs.
227
+ """
228
+ if include_shipped is None:
229
+ include_shipped = os.environ.get("ATTOCODE_NO_SHIPPED_PACKS", "") not in (
230
+ "1", "true", "True",
231
+ )
232
+
233
+ manifests = discover_packs(project_dir)
234
+ if include_shipped:
235
+ seen = {m.name for m in manifests}
236
+ for m in list_example_packs():
237
+ if m.name not in seen:
238
+ manifests.append(m)
239
+ seen.add(m.name)
240
+
241
+ all_rules: list[UnifiedRule] = []
242
+ for m in manifests:
243
+ all_rules.extend(load_pack(m))
244
+ return manifests, all_rules
@@ -0,0 +1 @@
1
+ """User plugin system for custom analysis rules."""
@@ -0,0 +1,132 @@
1
+ """Plugin loader — discovers and loads user analysis plugins.
2
+
3
+ Plugins live in ``.attocode/plugins/<name>/`` and contain:
4
+ - ``plugin.yaml`` — manifest with name, version, description, rule paths
5
+ - ``rules/*.yaml`` — YAML rule definitions (same format as pack rules)
6
+
7
+ Example plugin structure::
8
+
9
+ .attocode/plugins/my-company-rules/
10
+ ├── plugin.yaml
11
+ └── rules/
12
+ ├── no-direct-db.yaml
13
+ └── require-logging.yaml
14
+
15
+ Example plugin.yaml::
16
+
17
+ name: my-company-rules
18
+ version: 1.0.0
19
+ description: "Internal coding standards"
20
+ rules:
21
+ - rules/*.yaml
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import logging
27
+ from dataclasses import dataclass, field
28
+ from pathlib import Path
29
+
30
+ from attocode_intel.rules.loader import load_yaml_rules
31
+ from attocode_intel.rules.model import RuleSource, UnifiedRule
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ @dataclass(slots=True)
37
+ class PluginManifest:
38
+ """Parsed plugin manifest."""
39
+
40
+ name: str
41
+ version: str = "1.0.0"
42
+ description: str = ""
43
+ plugin_dir: str = ""
44
+ rule_globs: list[str] = field(default_factory=list)
45
+
46
+
47
+ def _load_plugin_manifest(plugin_dir: Path) -> PluginManifest | None:
48
+ """Load plugin.yaml from a plugin directory."""
49
+ manifest_path = plugin_dir / "plugin.yaml"
50
+ if not manifest_path.is_file():
51
+ # No manifest — try to load rules directly
52
+ return PluginManifest(
53
+ name=plugin_dir.name,
54
+ plugin_dir=str(plugin_dir),
55
+ rule_globs=["rules/*.yaml"],
56
+ )
57
+
58
+ try:
59
+ import yaml # type: ignore[import-untyped]
60
+ except ImportError:
61
+ return PluginManifest(
62
+ name=plugin_dir.name,
63
+ plugin_dir=str(plugin_dir),
64
+ rule_globs=["rules/*.yaml"],
65
+ )
66
+
67
+ try:
68
+ data = yaml.safe_load(manifest_path.read_text(encoding="utf-8")) or {}
69
+ except Exception as exc:
70
+ logger.warning("Failed to parse plugin manifest %s: %s", manifest_path, exc)
71
+ return None
72
+
73
+ return PluginManifest(
74
+ name=str(data.get("name", plugin_dir.name)),
75
+ version=str(data.get("version", "1.0.0")),
76
+ description=str(data.get("description", "")),
77
+ plugin_dir=str(plugin_dir),
78
+ rule_globs=data.get("rules", ["rules/*.yaml"]),
79
+ )
80
+
81
+
82
+ def discover_plugins(project_dir: str) -> list[PluginManifest]:
83
+ """Discover all plugins in .attocode/plugins/."""
84
+ plugins_dir = Path(project_dir) / ".attocode" / "plugins"
85
+ if not plugins_dir.is_dir():
86
+ return []
87
+
88
+ manifests: list[PluginManifest] = []
89
+ for entry in sorted(plugins_dir.iterdir()):
90
+ if entry.is_dir() and not entry.name.startswith("_"):
91
+ m = _load_plugin_manifest(entry)
92
+ if m:
93
+ manifests.append(m)
94
+
95
+ return manifests
96
+
97
+
98
+ def load_plugin(manifest: PluginManifest) -> list[UnifiedRule]:
99
+ """Load all rules from a plugin."""
100
+ plugin_dir = Path(manifest.plugin_dir)
101
+ rules: list[UnifiedRule] = []
102
+
103
+ # Load rules from each glob pattern
104
+ for glob_pattern in manifest.rule_globs:
105
+ # Resolve the glob relative to plugin dir
106
+ parts = glob_pattern.rsplit("/", 1)
107
+ if len(parts) == 2:
108
+ sub_dir = plugin_dir / parts[0]
109
+ else:
110
+ sub_dir = plugin_dir
111
+
112
+ if sub_dir.is_dir():
113
+ loaded = load_yaml_rules(
114
+ sub_dir,
115
+ source=RuleSource.USER,
116
+ pack=f"plugin:{manifest.name}",
117
+ )
118
+ rules.extend(loaded)
119
+
120
+ if rules:
121
+ logger.info("Plugin '%s': loaded %d rules", manifest.name, len(rules))
122
+
123
+ return rules
124
+
125
+
126
+ def load_all_plugins(project_dir: str) -> tuple[list[PluginManifest], list[UnifiedRule]]:
127
+ """Discover and load all plugins. Returns (manifests, all_rules)."""
128
+ manifests = discover_plugins(project_dir)
129
+ all_rules: list[UnifiedRule] = []
130
+ for m in manifests:
131
+ all_rules.extend(load_plugin(m))
132
+ return manifests, all_rules