codenib 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 (386) hide show
  1. codenib/__init__.py +62 -0
  2. codenib/__main__.py +7 -0
  3. codenib/_lazy.py +36 -0
  4. codenib/_version.py +26 -0
  5. codenib/agent/__init__.py +159 -0
  6. codenib/agent/agent_types.py +40 -0
  7. codenib/agent/boundary.py +129 -0
  8. codenib/agent/compile.py +219 -0
  9. codenib/agent/extract_agent.py +101 -0
  10. codenib/agent/harness.py +326 -0
  11. codenib/agent/history.py +242 -0
  12. codenib/agent/lsp_graph.py +878 -0
  13. codenib/agent/lsp_provider.py +484 -0
  14. codenib/agent/rerank_agent.py +419 -0
  15. codenib/agent/resource_guard.py +90 -0
  16. codenib/agent/route_context.py +391 -0
  17. codenib/agent/runner.py +2005 -0
  18. codenib/agent/runtime/__init__.py +16 -0
  19. codenib/agent/runtime/context.py +189 -0
  20. codenib/agent/runtime/trace.py +101 -0
  21. codenib/agent/skills/__init__.py +25 -0
  22. codenib/agent/skills/_graphnav.py +235 -0
  23. codenib/agent/skills/bm25_search/__init__.py +0 -0
  24. codenib/agent/skills/bm25_search/config.yaml +63 -0
  25. codenib/agent/skills/bm25_search/executor.py +80 -0
  26. codenib/agent/skills/bm25_search/skill.md +47 -0
  27. codenib/agent/skills/code_to_query/__init__.py +0 -0
  28. codenib/agent/skills/code_to_query/config.yaml +38 -0
  29. codenib/agent/skills/code_to_query/executor.py +69 -0
  30. codenib/agent/skills/code_to_query/skill.md +7 -0
  31. codenib/agent/skills/codenib_context/__init__.py +0 -0
  32. codenib/agent/skills/codenib_context/config.yaml +44 -0
  33. codenib/agent/skills/codenib_context/executor.py +184 -0
  34. codenib/agent/skills/codenib_context/skill.md +21 -0
  35. codenib/agent/skills/context.py +107 -0
  36. codenib/agent/skills/core.py +153 -0
  37. codenib/agent/skills/crossencoder_rerank/__init__.py +3 -0
  38. codenib/agent/skills/crossencoder_rerank/config.yaml +41 -0
  39. codenib/agent/skills/crossencoder_rerank/executor.py +62 -0
  40. codenib/agent/skills/crossencoder_rerank/skill.md +7 -0
  41. codenib/agent/skills/embedding_search/__init__.py +0 -0
  42. codenib/agent/skills/embedding_search/config.yaml +53 -0
  43. codenib/agent/skills/embedding_search/executor.py +57 -0
  44. codenib/agent/skills/embedding_search/skill.md +47 -0
  45. codenib/agent/skills/find_callees/__init__.py +0 -0
  46. codenib/agent/skills/find_callees/config.yaml +22 -0
  47. codenib/agent/skills/find_callees/executor.py +23 -0
  48. codenib/agent/skills/find_callees/skill.md +11 -0
  49. codenib/agent/skills/find_callers/__init__.py +0 -0
  50. codenib/agent/skills/find_callers/config.yaml +22 -0
  51. codenib/agent/skills/find_callers/executor.py +23 -0
  52. codenib/agent/skills/find_callers/skill.md +11 -0
  53. codenib/agent/skills/hybrid_search/__init__.py +0 -0
  54. codenib/agent/skills/hybrid_search/config.yaml +38 -0
  55. codenib/agent/skills/hybrid_search/executor.py +132 -0
  56. codenib/agent/skills/hybrid_search/skill.md +53 -0
  57. codenib/agent/skills/llm_rerank/__init__.py +0 -0
  58. codenib/agent/skills/llm_rerank/config.yaml +33 -0
  59. codenib/agent/skills/llm_rerank/executor.py +37 -0
  60. codenib/agent/skills/llm_rerank/skill.md +7 -0
  61. codenib/agent/skills/loader.py +240 -0
  62. codenib/agent/skills/lsp_definition/config.yaml +35 -0
  63. codenib/agent/skills/lsp_definition/executor.py +32 -0
  64. codenib/agent/skills/lsp_definition/skill.md +18 -0
  65. codenib/agent/skills/lsp_references/config.yaml +40 -0
  66. codenib/agent/skills/lsp_references/executor.py +34 -0
  67. codenib/agent/skills/lsp_references/skill.md +17 -0
  68. codenib/agent/skills/lsp_route/config.yaml +35 -0
  69. codenib/agent/skills/lsp_route/executor.py +34 -0
  70. codenib/agent/skills/lsp_route/skill.md +23 -0
  71. codenib/agent/skills/registry.py +136 -0
  72. codenib/agent/skills/repository_search/config.yaml +49 -0
  73. codenib/agent/skills/repository_search/executor.py +512 -0
  74. codenib/agent/skills/repository_search/skill.md +28 -0
  75. codenib/agent/skills/trace/__init__.py +0 -0
  76. codenib/agent/skills/trace/config.yaml +30 -0
  77. codenib/agent/skills/trace/executor.py +27 -0
  78. codenib/agent/skills/trace/skill.md +12 -0
  79. codenib/agent/skills/typecheck.py +302 -0
  80. codenib/agent/tool_schema.py +158 -0
  81. codenib/agent/tools/__init__.py +41 -0
  82. codenib/agent/tools/defaults.py +1045 -0
  83. codenib/agent/tools/spec.py +103 -0
  84. codenib/agent/utils.py +149 -0
  85. codenib/cli.py +1079 -0
  86. codenib/clients/__init__.py +5 -0
  87. codenib/clients/claude_agent.py +534 -0
  88. codenib/clients/codex_agent.py +314 -0
  89. codenib/code_chunker.py +730 -0
  90. codenib/code_chunking/__init__.py +113 -0
  91. codenib/code_chunking/base.py +592 -0
  92. codenib/code_chunking/cpp_chunker.py +278 -0
  93. codenib/code_chunking/csharp_chunker.py +210 -0
  94. codenib/code_chunking/go_chunker.py +213 -0
  95. codenib/code_chunking/java_chunker.py +188 -0
  96. codenib/code_chunking/js_chunker.py +251 -0
  97. codenib/code_chunking/kotlin_chunker.py +253 -0
  98. codenib/code_chunking/lua_chunker.py +94 -0
  99. codenib/code_chunking/php_chunker.py +204 -0
  100. codenib/code_chunking/python_chunker.py +267 -0
  101. codenib/code_chunking/ruby_chunker.py +198 -0
  102. codenib/code_chunking/rust_chunker.py +195 -0
  103. codenib/code_chunking/scala_chunker.py +182 -0
  104. codenib/code_chunking/swift_chunker.py +182 -0
  105. codenib/compat_pickle.py +48 -0
  106. codenib/compiler/__init__.py +93 -0
  107. codenib/compiler/index_builders.py +868 -0
  108. codenib/compiler/index_compiler.py +488 -0
  109. codenib/compiler/manifest.py +221 -0
  110. codenib/compiler/params.py +126 -0
  111. codenib/compiler/resources.py +267 -0
  112. codenib/compiler/skill_context.py +641 -0
  113. codenib/compiler/snapshot_store.py +311 -0
  114. codenib/compiler/verification.py +131 -0
  115. codenib/dataset/__init__.py +21 -0
  116. codenib/dataset/base.py +78 -0
  117. codenib/dataset/codenib_base.py +374 -0
  118. codenib/dataset/codenib_synthesis.py +540 -0
  119. codenib/dataset/collect/difficulty_classifier.py +511 -0
  120. codenib/dataset/collect/swebench_sample.py +766 -0
  121. codenib/dataset/gt_locate.py +831 -0
  122. codenib/dataset/local_json.py +184 -0
  123. codenib/dataset/locbench.py +254 -0
  124. codenib/dataset/swebench.py +344 -0
  125. codenib/dataset/swebench_multilingual.py +283 -0
  126. codenib/dataset/synthesize/__init__.py +71 -0
  127. codenib/dataset/synthesize/_agent.py +125 -0
  128. codenib/dataset/synthesize/_types.py +146 -0
  129. codenib/dataset/synthesize/context_loader.py +601 -0
  130. codenib/dataset/synthesize/query_curator.py +713 -0
  131. codenib/dataset/synthesize/query_synthesizer.py +546 -0
  132. codenib/dataset/synthesize/verifier.py +425 -0
  133. codenib/dataset/synthesize/vocab_guard.py +264 -0
  134. codenib/dataset/utils.py +380 -0
  135. codenib/eval/agent_runner/__init__.py +296 -0
  136. codenib/eval/agent_runner/baseline.py +299 -0
  137. codenib/eval/agent_runner/batch.py +176 -0
  138. codenib/eval/agent_runner/contexts.py +135 -0
  139. codenib/eval/agent_runner/feedback.py +135 -0
  140. codenib/eval/agent_runner/feedback_summary.py +326 -0
  141. codenib/eval/agent_runner/format_diagnostics.py +115 -0
  142. codenib/eval/agent_runner/live_lsp_provider.py +377 -0
  143. codenib/eval/agent_runner/loc_baseline.py +355 -0
  144. codenib/eval/agent_runner/lsp_agent_ab.py +577 -0
  145. codenib/eval/agent_runner/lsp_agent_study.py +408 -0
  146. codenib/eval/agent_runner/lsp_agent_study_analysis.py +411 -0
  147. codenib/eval/agent_runner/lsp_agent_study_artifacts.py +413 -0
  148. codenib/eval/agent_runner/lsp_agent_study_manifest.py +402 -0
  149. codenib/eval/agent_runner/lsp_agent_study_runner.py +694 -0
  150. codenib/eval/agent_runner/lsp_baseline.py +251 -0
  151. codenib/eval/agent_runner/lsp_latency.py +267 -0
  152. codenib/eval/agent_runner/lsp_provider_cli.py +273 -0
  153. codenib/eval/agent_runner/lsp_provider_validation.py +594 -0
  154. codenib/eval/agent_runner/lsp_readiness.py +167 -0
  155. codenib/eval/agent_runner/lsp_replay_benchmark.py +1072 -0
  156. codenib/eval/agent_runner/metrics.py +80 -0
  157. codenib/eval/agent_runner/orchestrator.py +173 -0
  158. codenib/eval/agent_runner/pareto.py +154 -0
  159. codenib/eval/agent_runner/prebuilt.py +484 -0
  160. codenib/eval/agent_runner/preload.py +219 -0
  161. codenib/eval/agent_runner/promotion.py +172 -0
  162. codenib/eval/agent_runner/query_sweep.py +432 -0
  163. codenib/eval/agent_runner/results.py +69 -0
  164. codenib/eval/agent_runner/scoring.py +134 -0
  165. codenib/eval/agent_runner/sweep.py +619 -0
  166. codenib/eval/agent_runner/sweep_config.py +160 -0
  167. codenib/eval/agent_runner/symbols.py +67 -0
  168. codenib/eval/agent_runner/trace_summary.py +405 -0
  169. codenib/eval/agent_runner/verify_expand.py +219 -0
  170. codenib/eval/artifact_bundle.py +322 -0
  171. codenib/eval/artifact_integrity.py +332 -0
  172. codenib/eval/artifact_manifest.py +236 -0
  173. codenib/eval/experiments/__init__.py +5 -0
  174. codenib/eval/experiments/lsp_agent_study_policy.py +55 -0
  175. codenib/eval/loc_agent_runner.py +37 -0
  176. codenib/eval/reports/__init__.py +5 -0
  177. codenib/eval/reports/cost_arm_report.py +810 -0
  178. codenib/eval/retrieval_eval.py +557 -0
  179. codenib/graph/__init__.py +44 -0
  180. codenib/graph/backend_alignment.py +184 -0
  181. codenib/graph/code_graph.py +1218 -0
  182. codenib/graph/dependency.py +229 -0
  183. codenib/graph/hierarchy.py +828 -0
  184. codenib/graph/incremental/__init__.py +15 -0
  185. codenib/graph/incremental/change_mgr.py +165 -0
  186. codenib/graph/incremental/graph_patcher.py +139 -0
  187. codenib/graph/incremental/lsp_client.py +1271 -0
  188. codenib/graph/incremental/patcher_base.py +1364 -0
  189. codenib/graph/incremental/patcher_cpp.py +796 -0
  190. codenib/graph/incremental/patcher_go.py +56 -0
  191. codenib/graph/incremental/patcher_python.py +43 -0
  192. codenib/graph/incremental/patcher_rust.py +113 -0
  193. codenib/graph/incremental/patcher_ts.py +49 -0
  194. codenib/graph/incremental/subgraph_mgr.py +1028 -0
  195. codenib/graph/layers.py +325 -0
  196. codenib/graph/roi_subgraph.py +394 -0
  197. codenib/graph/setup.py +689 -0
  198. codenib/graph/traverse_graph.py +237 -0
  199. codenib/index/__init__.py +42 -0
  200. codenib/index/embedding/__init__.py +48 -0
  201. codenib/index/embedding/builders.py +190 -0
  202. codenib/index/embedding/model_policy.py +62 -0
  203. codenib/index/embedding/prompt_registry.py +87 -0
  204. codenib/index/embedding/vector_store.py +1458 -0
  205. codenib/index/incremental/__init__.py +30 -0
  206. codenib/index/incremental/chunk_store.py +409 -0
  207. codenib/index/incremental/embeddings_cache.py +196 -0
  208. codenib/index/incremental/git_diff.py +221 -0
  209. codenib/index/incremental/index_updater.py +283 -0
  210. codenib/index/incremental/state.py +92 -0
  211. codenib/index/regex_idx/__init__.py +7 -0
  212. codenib/index/regex_idx/regex_idx.py +150 -0
  213. codenib/index/rerank/__init__.py +23 -0
  214. codenib/index/rerank/cross_encoder.py +356 -0
  215. codenib/index/sparse_idx/__init__.py +9 -0
  216. codenib/index/sparse_idx/bm25_index.py +724 -0
  217. codenib/index/trigram/__init__.py +17 -0
  218. codenib/index/trigram/zoekt_searcher.py +371 -0
  219. codenib/languages.py +1035 -0
  220. codenib/llm/__init__.py +33 -0
  221. codenib/llm/diagnostics.py +170 -0
  222. codenib/llm/litellm_chat.py +422 -0
  223. codenib/llm/options.py +139 -0
  224. codenib/llm/usage.py +182 -0
  225. codenib/log_utils.py +301 -0
  226. codenib/ls_index/__init__.py +17 -0
  227. codenib/ls_index/clangd_decode.py +912 -0
  228. codenib/ls_index/clangd_indexer.py +1400 -0
  229. codenib/ls_index/index_quality.py +442 -0
  230. codenib/ls_index/lsp_graph_decode.py +449 -0
  231. codenib/ls_index/lsp_indexer.py +246 -0
  232. codenib/ls_router.py +507 -0
  233. codenib/mcp/__init__.py +13 -0
  234. codenib/mcp/__main__.py +9 -0
  235. codenib/mcp/context.py +211 -0
  236. codenib/mcp/prompts.py +76 -0
  237. codenib/mcp/server.py +463 -0
  238. codenib/mcp/tools/__init__.py +9 -0
  239. codenib/mcp/tools/dependency.py +56 -0
  240. codenib/mcp/tools/lsp.py +119 -0
  241. codenib/mcp/tools/search.py +224 -0
  242. codenib/model/__init__.py +49 -0
  243. codenib/model/agentless_pipeline.py +484 -0
  244. codenib/model/bm25_retrieve_pipeline.py +100 -0
  245. codenib/model/dense_graph_expand_rerank_pipeline.py +300 -0
  246. codenib/model/embedding_retrieve_pipeline.py +152 -0
  247. codenib/model/graph_augmented_rerank_pipeline.py +19 -0
  248. codenib/model/graph_retrieve_pipeline.py +259 -0
  249. codenib/model/hybrid_retrieve_pipeline.py +256 -0
  250. codenib/model/retrieval_planner.py +377 -0
  251. codenib/model/retrieve_rerank_pipeline.py +1023 -0
  252. codenib/ops/expand.py +299 -0
  253. codenib/ops/filter.py +159 -0
  254. codenib/ops/rerank.py +246 -0
  255. codenib/ops/retrieve.py +293 -0
  256. codenib/ops/transform.py +34 -0
  257. codenib/paths.py +91 -0
  258. codenib/profiler.py +506 -0
  259. codenib/repository_filters.py +103 -0
  260. codenib/repository_summary.py +161 -0
  261. codenib/scip_interface/__init__.py +120 -0
  262. codenib/scip_interface/lsp_occurrence_index.py +327 -0
  263. codenib/scip_interface/rust_analyzer.py +29 -0
  264. codenib/scip_interface/scip-environment.yml +14 -0
  265. codenib/scip_interface/scip.proto +890 -0
  266. codenib/scip_interface/scip_decode_core.py +190 -0
  267. codenib/scip_interface/scip_decode_csharp.py +143 -0
  268. codenib/scip_interface/scip_decode_go.py +433 -0
  269. codenib/scip_interface/scip_decode_java.py +1117 -0
  270. codenib/scip_interface/scip_decode_php.py +194 -0
  271. codenib/scip_interface/scip_decode_python.py +400 -0
  272. codenib/scip_interface/scip_decode_ruby.py +464 -0
  273. codenib/scip_interface/scip_decode_rust.py +584 -0
  274. codenib/scip_interface/scip_decode_ts.py +542 -0
  275. codenib/scip_interface/scip_decode_utils.py +52 -0
  276. codenib/scip_interface/scip_indexer_base.py +728 -0
  277. codenib/scip_interface/scip_indexer_csharp.py +166 -0
  278. codenib/scip_interface/scip_indexer_go.py +164 -0
  279. codenib/scip_interface/scip_indexer_java.py +201 -0
  280. codenib/scip_interface/scip_indexer_php.py +548 -0
  281. codenib/scip_interface/scip_indexer_python.py +500 -0
  282. codenib/scip_interface/scip_indexer_ruby.py +369 -0
  283. codenib/scip_interface/scip_indexer_rust.py +183 -0
  284. codenib/scip_interface/scip_indexer_ts.py +616 -0
  285. codenib/scip_interface/scip_install.sh +8 -0
  286. codenib/scip_interface/scip_pb2.py +80 -0
  287. codenib/search.py +371 -0
  288. codenib/source_fingerprint.py +198 -0
  289. codenib/types.py +105 -0
  290. codenib/utils.py +93 -0
  291. codenib/web/__init__.py +9 -0
  292. codenib/web/app.py +467 -0
  293. codenib/web/codemap.py +753 -0
  294. codenib/web/commit_window.py +296 -0
  295. codenib/web/config.py +331 -0
  296. codenib/web/edge_label.py +332 -0
  297. codenib/web/frontend/assets/AskBar-Q_2zSw_D.js +31 -0
  298. codenib/web/frontend/assets/CodeGraph-C5zIOx4j.js +3 -0
  299. codenib/web/frontend/assets/CodePanel-BE7Wg1wI.js +1 -0
  300. codenib/web/frontend/assets/Codemap-C5Xm7Go_.js +2 -0
  301. codenib/web/frontend/assets/GraphView-CBBbxS9a.js +2 -0
  302. codenib/web/frontend/assets/Header-CUW7gfQl.js +1 -0
  303. codenib/web/frontend/assets/HighlightedBlock-H7FGwbAI.js +1 -0
  304. codenib/web/frontend/assets/HighlightedCode-CTRFPFV9.js +2 -0
  305. codenib/web/frontend/assets/Mermaid-NhydXLyh.js +303 -0
  306. codenib/web/frontend/assets/api-DMyba6Hn.js +1 -0
  307. codenib/web/frontend/assets/arc-Cj6TUG7b.js +1 -0
  308. codenib/web/frontend/assets/architectureDiagram-3BPJPVTR-BXC7SbpZ.js +36 -0
  309. codenib/web/frontend/assets/blockDiagram-GPEHLZMM-BYhhgH_O.js +132 -0
  310. codenib/web/frontend/assets/c4Diagram-AAUBKEIU-BPe9Xb1K.js +10 -0
  311. codenib/web/frontend/assets/channel-DGptmZnr.js +1 -0
  312. codenib/web/frontend/assets/chunk-2J33WTMH-mJuoTx1I.js +1 -0
  313. codenib/web/frontend/assets/chunk-4BX2VUAB-DyIPfnHV.js +1 -0
  314. codenib/web/frontend/assets/chunk-55IACEB6-C8bSn9Qq.js +1 -0
  315. codenib/web/frontend/assets/chunk-727SXJPM-CgiBqZFm.js +206 -0
  316. codenib/web/frontend/assets/chunk-AQP2D5EJ-DOOlLotN.js +231 -0
  317. codenib/web/frontend/assets/chunk-FMBD7UC4-mf47mSz2.js +15 -0
  318. codenib/web/frontend/assets/chunk-ND2GUHAM-D6lobpla.js +1 -0
  319. codenib/web/frontend/assets/chunk-QZHKN3VN-D9a00sWs.js +1 -0
  320. codenib/web/frontend/assets/classDiagram-4FO5ZUOK-wDtvnBsq.js +1 -0
  321. codenib/web/frontend/assets/classDiagram-v2-Q7XG4LA2-wDtvnBsq.js +1 -0
  322. codenib/web/frontend/assets/cose-bilkent-S5V4N54A-JwC1FU9v.js +1 -0
  323. codenib/web/frontend/assets/cytoscape.esm-CkSuTymj.js +321 -0
  324. codenib/web/frontend/assets/dagre-BM42HDAG-BTm6Sb-x.js +4 -0
  325. codenib/web/frontend/assets/defaultLocale-DX6XiGOO.js +1 -0
  326. codenib/web/frontend/assets/diagram-2AECGRRQ-C7XNwfvk.js +43 -0
  327. codenib/web/frontend/assets/diagram-5GNKFQAL-DcLriIgZ.js +10 -0
  328. codenib/web/frontend/assets/diagram-KO2AKTUF-Bo-6Bpfo.js +3 -0
  329. codenib/web/frontend/assets/diagram-LMA3HP47-M4Nh-qq-.js +24 -0
  330. codenib/web/frontend/assets/diagram-OG6HWLK6-BUT1QVEf.js +24 -0
  331. codenib/web/frontend/assets/erDiagram-TEJ5UH35-DViEMoeP.js +85 -0
  332. codenib/web/frontend/assets/flowDiagram-I6XJVG4X-DjBB1gSM.js +162 -0
  333. codenib/web/frontend/assets/ganttDiagram-6RSMTGT7-Drhb89TN.js +292 -0
  334. codenib/web/frontend/assets/gitGraphDiagram-PVQCEYII-CwqblmoY.js +106 -0
  335. codenib/web/frontend/assets/graph--OzhPTMs.js +1 -0
  336. codenib/web/frontend/assets/highlight-CDab0zVI.css +1 -0
  337. codenib/web/frontend/assets/highlight-CnfLc-V2.js +5 -0
  338. codenib/web/frontend/assets/index-BHP8c3Tq.js +9 -0
  339. codenib/web/frontend/assets/index-CKJrqu86.css +1 -0
  340. codenib/web/frontend/assets/infoDiagram-5YYISTIA-BKq62LUG.js +2 -0
  341. codenib/web/frontend/assets/init-Gi6I4Gst.js +1 -0
  342. codenib/web/frontend/assets/ishikawaDiagram-YF4QCWOH-DBAgfp9d.js +70 -0
  343. codenib/web/frontend/assets/journeyDiagram-JHISSGLW-DwHStEV9.js +139 -0
  344. codenib/web/frontend/assets/kanban-definition-UN3LZRKU-CWPLLTQn.js +89 -0
  345. codenib/web/frontend/assets/katex-HP8lGamR.js +257 -0
  346. codenib/web/frontend/assets/layout-SsrduOYp.js +1 -0
  347. codenib/web/frontend/assets/linear-DNcGZFnN.js +1 -0
  348. codenib/web/frontend/assets/mindmap-definition-RKZ34NQL-FZHYTpdO.js +96 -0
  349. codenib/web/frontend/assets/ordinal-Cboi1Yqb.js +1 -0
  350. codenib/web/frontend/assets/page-Bn-Q8MBy.js +6 -0
  351. codenib/web/frontend/assets/page-CESv5Ezw.js +2 -0
  352. codenib/web/frontend/assets/page-CHsElUu2.js +1 -0
  353. codenib/web/frontend/assets/page-D1WhIRzi.js +1 -0
  354. codenib/web/frontend/assets/pieDiagram-4H26LBE5-DKlC7xtb.js +30 -0
  355. codenib/web/frontend/assets/quadrantDiagram-W4KKPZXB-DldkGUZS.js +7 -0
  356. codenib/web/frontend/assets/requirementDiagram-4Y6WPE33-Dndb6w-j.js +84 -0
  357. codenib/web/frontend/assets/sankeyDiagram-5OEKKPKP-B2ewtJAC.js +40 -0
  358. codenib/web/frontend/assets/sequenceDiagram-3UESZ5HK-2N2KbYFt.js +162 -0
  359. codenib/web/frontend/assets/stateDiagram-AJRCARHV-CLwUuVlz.js +1 -0
  360. codenib/web/frontend/assets/stateDiagram-v2-BHNVJYJU-IiZdW_Og.js +1 -0
  361. codenib/web/frontend/assets/timeline-definition-PNZ67QCA-D_IdllIp.js +120 -0
  362. codenib/web/frontend/assets/vennDiagram-CIIHVFJN-CSU7pI9M.js +34 -0
  363. codenib/web/frontend/assets/wardley-L42UT6IY-Bv1Eg1Al.js +161 -0
  364. codenib/web/frontend/assets/wardleyDiagram-YWT4CUSO-Di3bYwLm.js +78 -0
  365. codenib/web/frontend/assets/xychartDiagram-2RQKCTM6-CPHWEBiN.js +7 -0
  366. codenib/web/frontend/codenib-icon.svg +34 -0
  367. codenib/web/frontend/index.html +29 -0
  368. codenib/web/frontend/runtime-config.js +1 -0
  369. codenib/web/launcher.py +252 -0
  370. codenib/web/local.py +196 -0
  371. codenib/web/repo_registry.py +561 -0
  372. codenib/web/schemas.py +329 -0
  373. codenib/web/static_server.py +213 -0
  374. codenib/wiki/__init__.py +15 -0
  375. codenib/wiki/agent_wiki.py +4665 -0
  376. codenib/wiki/builder.py +849 -0
  377. codenib/wiki/evidence.py +905 -0
  378. codenib/wiki/narrator.py +258 -0
  379. codenib/wiki/outline.py +1432 -0
  380. codenib/wiki/quality.py +932 -0
  381. codenib-0.1.0.dist-info/METADATA +293 -0
  382. codenib-0.1.0.dist-info/RECORD +386 -0
  383. codenib-0.1.0.dist-info/WHEEL +5 -0
  384. codenib-0.1.0.dist-info/entry_points.txt +13 -0
  385. codenib-0.1.0.dist-info/licenses/LICENSE +201 -0
  386. codenib-0.1.0.dist-info/top_level.txt +1 -0
codenib/__init__.py ADDED
@@ -0,0 +1,62 @@
1
+ # SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Public CodeNib API.
6
+
7
+ Exports are resolved lazily so importing :mod:`codenib` or starting the CLI
8
+ does not initialize optional graph, embedding, and agent runtimes.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import Any
14
+
15
+ from ._lazy import exported_dir, load_export
16
+ from ._version import __version__
17
+
18
+ _EXPORTS = {
19
+ "LSIndexer": ("codenib.ls_router", "LSIndexer"),
20
+ "CodeGraph": ("codenib.graph.code_graph", "CodeGraph"),
21
+ "BM25CodeIndexer": (
22
+ "codenib.index.sparse_idx.bm25_index",
23
+ "BM25CodeIndexer",
24
+ ),
25
+ "KeywordExtractor": ("codenib.agent.extract_agent", "KeywordExtractor"),
26
+ "CodeSearchEngine": ("codenib.search", "CodeSearchEngine"),
27
+ "RerankAgent": ("codenib.agent.rerank_agent", "RerankAgent"),
28
+ "CodeChunker": ("codenib.code_chunker", "CodeChunker"),
29
+ "RepoChunkingConfig": ("codenib.code_chunker", "RepoChunkingConfig"),
30
+ "RegexNodeIndex": ("codenib.index.regex_idx", "RegexNodeIndex"),
31
+ "CodeVectorStore": (
32
+ "codenib.index.embedding.vector_store",
33
+ "CodeVectorStore",
34
+ ),
35
+ "create_code_vector_store": (
36
+ "codenib.index.embedding.vector_store",
37
+ "create_code_vector_store",
38
+ ),
39
+ }
40
+
41
+ __all__ = [
42
+ "__version__",
43
+ "LSIndexer",
44
+ "CodeGraph",
45
+ "BM25CodeIndexer",
46
+ "KeywordExtractor",
47
+ "CodeSearchEngine",
48
+ "RerankAgent",
49
+ "CodeChunker",
50
+ "RepoChunkingConfig",
51
+ "RegexNodeIndex",
52
+ "CodeVectorStore",
53
+ "create_code_vector_store",
54
+ ]
55
+
56
+
57
+ def __getattr__(name: str) -> Any:
58
+ return load_export(globals(), _EXPORTS, name)
59
+
60
+
61
+ def __dir__() -> list[str]:
62
+ return exported_dir(globals(), _EXPORTS)
codenib/__main__.py ADDED
@@ -0,0 +1,7 @@
1
+ # SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from .cli import main
6
+
7
+ raise SystemExit(main())
codenib/_lazy.py ADDED
@@ -0,0 +1,36 @@
1
+ # SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Small helper for preserving package APIs without eager imports."""
6
+
7
+ from __future__ import annotations
8
+
9
+ from importlib import import_module
10
+ from typing import Any, Mapping, MutableMapping
11
+
12
+ LazyExports = Mapping[str, tuple[str, str]]
13
+
14
+
15
+ def load_export(
16
+ namespace: MutableMapping[str, Any],
17
+ exports: LazyExports,
18
+ name: str,
19
+ ) -> Any:
20
+ """Import, cache, and return one declared package export."""
21
+ target = exports.get(name)
22
+ if target is None:
23
+ module_name = namespace.get("__name__", "module")
24
+ raise AttributeError(f"module {module_name!r} has no attribute {name!r}")
25
+ module_name, attribute = target
26
+ value = getattr(import_module(module_name), attribute)
27
+ namespace[name] = value
28
+ return value
29
+
30
+
31
+ def exported_dir(namespace: Mapping[str, Any], exports: LazyExports) -> list[str]:
32
+ """Include lazy exports in ``dir(package)``."""
33
+ return sorted(set(namespace) | set(exports))
34
+
35
+
36
+ __all__ = ["LazyExports", "exported_dir", "load_export"]
codenib/_version.py ADDED
@@ -0,0 +1,26 @@
1
+ # SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Installed CodeNib version.
6
+
7
+ ``pyproject.toml`` is the only authored version source. Package metadata makes
8
+ that value available at runtime without importing optional CodeNib subsystems.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from importlib import metadata
14
+
15
+
16
+ def package_version() -> str:
17
+ """Return the installed distribution version."""
18
+ try:
19
+ return metadata.version("codenib")
20
+ except metadata.PackageNotFoundError:
21
+ return "0+unknown"
22
+
23
+
24
+ __version__ = package_version()
25
+
26
+ __all__ = ["__version__", "package_version"]
@@ -0,0 +1,159 @@
1
+ # SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Agent package consolidating agent utilities and implementations."""
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+
11
+ from .._lazy import exported_dir, load_export
12
+
13
+ _EXPORTS = {
14
+ "AgentResult": ("codenib.agent.agent_types", "AgentResult"),
15
+ "ToolCallRecord": ("codenib.agent.agent_types", "ToolCallRecord"),
16
+ "KeywordExtraction": ("codenib.agent.extract_agent", "KeywordExtraction"),
17
+ "KeywordExtractor": ("codenib.agent.extract_agent", "KeywordExtractor"),
18
+ "extract_keywords_from_statement": (
19
+ "codenib.agent.extract_agent",
20
+ "extract_keywords_from_statement",
21
+ ),
22
+ "AgentHarnessSpec": ("codenib.agent.harness", "AgentHarnessSpec"),
23
+ "AgentRunAccumulator": ("codenib.agent.harness", "AgentRunAccumulator"),
24
+ "agent_working_directory": (
25
+ "codenib.agent.harness",
26
+ "agent_working_directory",
27
+ ),
28
+ "run_agent_in_directory": (
29
+ "codenib.agent.harness",
30
+ "run_agent_in_directory",
31
+ ),
32
+ "PlainChatHistory": ("codenib.agent.history", "PlainChatHistory"),
33
+ "TokenBudgetedChatHistory": (
34
+ "codenib.agent.history",
35
+ "TokenBudgetedChatHistory",
36
+ ),
37
+ "count_message_tokens": ("codenib.agent.history", "count_message_tokens"),
38
+ "LSPProviderMetadata": (
39
+ "codenib.agent.lsp_provider",
40
+ "LSPProviderMetadata",
41
+ ),
42
+ "LSPProviderNodes": ("codenib.agent.lsp_provider", "LSPProviderNodes"),
43
+ "StaticLSPProvider": ("codenib.agent.lsp_provider", "StaticLSPProvider"),
44
+ "lsp_result_metadata": (
45
+ "codenib.agent.lsp_provider",
46
+ "lsp_result_metadata",
47
+ ),
48
+ "RerankAgent": ("codenib.agent.rerank_agent", "RerankAgent"),
49
+ "RerankResult": ("codenib.agent.rerank_agent", "RerankResult"),
50
+ "rerank_nodes_with_query": (
51
+ "codenib.agent.rerank_agent",
52
+ "rerank_nodes_with_query",
53
+ ),
54
+ "LSPRouteContext": ("codenib.agent.route_context", "LSPRouteContext"),
55
+ "build_lsp_route_context": (
56
+ "codenib.agent.route_context",
57
+ "build_lsp_route_context",
58
+ ),
59
+ "canonical_lsp_route_args": (
60
+ "codenib.agent.route_context",
61
+ "canonical_lsp_route_args",
62
+ ),
63
+ "extract_lsp_symbol_seeds": (
64
+ "codenib.agent.route_context",
65
+ "extract_lsp_symbol_seeds",
66
+ ),
67
+ "filter_lsp_symbol_seeds": (
68
+ "codenib.agent.route_context",
69
+ "filter_lsp_symbol_seeds",
70
+ ),
71
+ "fingerprint_lsp_route_nodes": (
72
+ "codenib.agent.route_context",
73
+ "fingerprint_lsp_route_nodes",
74
+ ),
75
+ "is_specific_lsp_symbol_seed": (
76
+ "codenib.agent.route_context",
77
+ "is_specific_lsp_symbol_seed",
78
+ ),
79
+ "normalize_lsp_route_seed_policy": (
80
+ "codenib.agent.route_context",
81
+ "normalize_lsp_route_seed_policy",
82
+ ),
83
+ "render_lsp_route_context": (
84
+ "codenib.agent.route_context",
85
+ "render_lsp_route_context",
86
+ ),
87
+ "AgentRunner": ("codenib.agent.runner", "AgentRunner"),
88
+ "CodeNibAgentOptions": ("codenib.agent.runner", "CodeNibAgentOptions"),
89
+ "compile_repo": ("codenib.agent.runner", "compile_repo"),
90
+ "has_localization_contract": (
91
+ "codenib.agent.runner",
92
+ "has_localization_contract",
93
+ ),
94
+ "query": ("codenib.agent.runner", "query"),
95
+ "AGENT_TRACE_SCHEMA_VERSION": (
96
+ "codenib.agent.runtime",
97
+ "AGENT_TRACE_SCHEMA_VERSION",
98
+ ),
99
+ "AgentRunTrace": ("codenib.agent.runtime", "AgentRunTrace"),
100
+ "AgentTraceEvent": ("codenib.agent.runtime", "AgentTraceEvent"),
101
+ "ContextLedger": ("codenib.agent.runtime", "ContextLedger"),
102
+ "ContextLedgerEntry": ("codenib.agent.runtime", "ContextLedgerEntry"),
103
+ "registry_to_tools": ("codenib.agent.tool_schema", "registry_to_tools"),
104
+ "skill_to_tool_schema": (
105
+ "codenib.agent.tool_schema",
106
+ "skill_to_tool_schema",
107
+ ),
108
+ }
109
+
110
+ __all__ = [
111
+ "AgentResult",
112
+ "AgentRunTrace",
113
+ "AgentRunAccumulator",
114
+ "AgentTraceEvent",
115
+ "AgentRunner",
116
+ "AGENT_TRACE_SCHEMA_VERSION",
117
+ "AgentHarnessSpec",
118
+ "CodeNibAgentOptions",
119
+ "ContextLedger",
120
+ "ContextLedgerEntry",
121
+ "KeywordExtraction",
122
+ "KeywordExtractor",
123
+ "LSPRouteContext",
124
+ "LSPProviderMetadata",
125
+ "LSPProviderNodes",
126
+ "PlainChatHistory",
127
+ "RerankAgent",
128
+ "RerankResult",
129
+ "TokenBudgetedChatHistory",
130
+ "ToolCallRecord",
131
+ "StaticLSPProvider",
132
+ "agent_working_directory",
133
+ "compile_repo",
134
+ "count_message_tokens",
135
+ "build_lsp_route_context",
136
+ "canonical_lsp_route_args",
137
+ "extract_keywords_from_statement",
138
+ "extract_lsp_symbol_seeds",
139
+ "filter_lsp_symbol_seeds",
140
+ "fingerprint_lsp_route_nodes",
141
+ "has_localization_contract",
142
+ "is_specific_lsp_symbol_seed",
143
+ "lsp_result_metadata",
144
+ "normalize_lsp_route_seed_policy",
145
+ "query",
146
+ "rerank_nodes_with_query",
147
+ "render_lsp_route_context",
148
+ "registry_to_tools",
149
+ "run_agent_in_directory",
150
+ "skill_to_tool_schema",
151
+ ]
152
+
153
+
154
+ def __getattr__(name: str) -> Any:
155
+ return load_export(globals(), _EXPORTS, name)
156
+
157
+
158
+ def __dir__() -> list[str]:
159
+ return exported_dir(globals(), _EXPORTS)
@@ -0,0 +1,40 @@
1
+ # SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Data types for the agent runner."""
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass, field
10
+ from typing import Any, Dict, List, Optional
11
+
12
+ from ..llm.usage import TokenUsage, UsageRecord
13
+ from .runtime.trace import AgentRunTrace
14
+
15
+
16
+ @dataclass
17
+ class ToolCallRecord:
18
+ """Record of a single tool invocation during an agent run."""
19
+
20
+ tool_call_id: str
21
+ skill_id: str
22
+ arguments: Dict[str, Any]
23
+ resolved_arguments: Optional[Dict[str, Any]] = None
24
+ result: Any = None
25
+ duration_ms: float = 0.0
26
+ error: Optional[str] = None
27
+
28
+
29
+ @dataclass
30
+ class AgentResult:
31
+ """Outcome of ``AgentRunner.run()``."""
32
+
33
+ answer: str
34
+ tool_calls: List[ToolCallRecord] = field(default_factory=list)
35
+ messages: List[Dict[str, Any]] = field(default_factory=list)
36
+ total_turns: int = 0
37
+ total_duration_ms: float = 0.0
38
+ usage: Optional[TokenUsage] = None
39
+ usage_records: List[UsageRecord] = field(default_factory=list)
40
+ trace: Optional[AgentRunTrace] = None
@@ -0,0 +1,129 @@
1
+ # SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Agent-boundary line-numbering conversion (issue #153).
6
+
7
+ Internal representations are uniformly **0-based**: BM25 docs, FAISS
8
+ metadata, symbol-graph anchors, and the tree-sitter ``CodeChunk`` all count
9
+ lines from 0. The *agent boundary* is **1-based outward** -- line numbers
10
+ shown to, and accepted back from, the LLM are 1-based, mirroring the
11
+ ``CodeLocation`` convention already used at the dataset/HuggingFace boundary
12
+ (see ``_chunk_to_code_block`` in ``dataset/gt_locate.py``, which does the
13
+ same ``+1`` once).
14
+
15
+ Without a single conversion site there is a silent 0/1 split *inside one
16
+ result*: a ``bm25_search`` hit renders its ``content`` gutter 1-based (via
17
+ ``wrap_code_snippet(start_line + 1, ...)``) while its structured
18
+ ``start_line`` stays 0-based, so an LLM that reads "line 42" from the
19
+ snippet and feeds it back as a seed into ``graph_expand`` hits an
20
+ off-by-one that never raises.
21
+
22
+ Two helpers, one conversion each:
23
+
24
+ - :func:`to_agent_repr` -- serialize a result node for the LLM (``+1``).
25
+ - :func:`from_agent_repr` -- parse a line number coming back (``-1``).
26
+
27
+ Internals stay 0-based; only these two functions touch the offset.
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ from typing import Any, Dict, Optional
33
+
34
+ # The LLM sees 1-based lines; every internal index is 0-based.
35
+ AGENT_LINE_OFFSET = 1
36
+
37
+ # Structured fields carrying a line number on a result node.
38
+ _LINE_FIELDS = ("start_line", "end_line")
39
+
40
+
41
+ def _is_int_line(val: Any) -> bool:
42
+ """Whether *val* is a real integer line number.
43
+
44
+ ``bool`` is an ``int`` subclass; exclude it defensively so a stray
45
+ ``True``/``False`` is never shifted as if it were line ``1``/``0``.
46
+ """
47
+ return isinstance(val, int) and not isinstance(val, bool)
48
+
49
+
50
+ def is_line_bearing(obj: Any) -> bool:
51
+ """Whether *obj* is a result node that carries line-number fields.
52
+
53
+ Used to decide whether :func:`to_agent_repr` should be applied during
54
+ serialization; non-node results (bare strings, scores, dicts without
55
+ line fields) are left untouched.
56
+ """
57
+ if isinstance(obj, dict):
58
+ return "start_line" in obj or "end_line" in obj
59
+ return hasattr(obj, "start_line") or hasattr(obj, "end_line")
60
+
61
+
62
+ def to_agent_repr(node: Any) -> Dict[str, Any]:
63
+ """Serialize a result node to a 1-based dict for the LLM.
64
+
65
+ Accepts a pydantic ``NodeInfo`` / ``QueriedNode``, a plain object with
66
+ ``__dict__``, or a mapping. Returns a plain dict with ``start_line`` /
67
+ ``end_line`` shifted ``+1`` (0-based -> 1-based). ``None`` line values
68
+ are preserved; all other fields pass through unchanged.
69
+ """
70
+ data = _as_dict(node)
71
+ for fld in _LINE_FIELDS:
72
+ val = data.get(fld)
73
+ if _is_int_line(val):
74
+ data[fld] = val + AGENT_LINE_OFFSET
75
+ return data
76
+
77
+
78
+ def from_agent_repr(line: Optional[int]) -> Optional[int]:
79
+ """Convert a single 1-based line number from the LLM to 0-based.
80
+
81
+ ``None`` passes through. A malformed seed (the LLM emitting ``0`` or a
82
+ negative, which is not a valid 1-based line) is clamped at ``0`` so it
83
+ can never produce a negative internal index.
84
+ """
85
+ if line is None or isinstance(line, bool):
86
+ return line
87
+ converted = int(line) - AGENT_LINE_OFFSET
88
+ return converted if converted >= 0 else 0
89
+
90
+
91
+ def from_agent_repr_arg(value: Any) -> Any:
92
+ """Apply :func:`from_agent_repr` across a whole tool argument.
93
+
94
+ Handles the shapes a line-bearing skill argument can take:
95
+
96
+ - a scalar line number,
97
+ - a list/tuple of line numbers,
98
+ - a list of ``[start, end]`` pairs, or
99
+ - ``{"start_line": ..., "end_line": ...}`` range dicts.
100
+
101
+ Any other shape passes through unchanged. This is the input-side
102
+ counterpart wired into :class:`~codenib.agent.runner.AgentRunner` for
103
+ skill inputs marked ``is_line_number`` (e.g. ``graph_expand`` ranges,
104
+ ``read_code_block``).
105
+ """
106
+ if value is None or isinstance(value, bool):
107
+ return value
108
+ if isinstance(value, int):
109
+ return from_agent_repr(value)
110
+ if isinstance(value, (list, tuple)):
111
+ return type(value)(from_agent_repr_arg(v) for v in value)
112
+ if isinstance(value, dict):
113
+ out = dict(value)
114
+ for fld in _LINE_FIELDS:
115
+ if _is_int_line(out.get(fld)):
116
+ out[fld] = from_agent_repr(out[fld])
117
+ return out
118
+ return value
119
+
120
+
121
+ def _as_dict(node: Any) -> Dict[str, Any]:
122
+ """Best-effort conversion of a result node to a mutable dict."""
123
+ if isinstance(node, dict):
124
+ return dict(node)
125
+ if hasattr(node, "model_dump"):
126
+ return node.model_dump(exclude_none=True)
127
+ if hasattr(node, "__dict__"):
128
+ return dict(node.__dict__)
129
+ return {"value": node}
@@ -0,0 +1,219 @@
1
+ # SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Agent compile: query-time skill selection.
6
+
7
+ Implements the lookup mechanism from issue #133 (RFC: Agent compile).
8
+ At agent entry, ``classify(query, session_ctx)`` produces a ``Scenario``;
9
+ ``agent_compile`` then looks the scenario up in a ``compile_table`` and
10
+ returns the skill subset the agent is allowed to call this turn.
11
+
12
+ The classifier is deterministic by design. LLM-driven scenario
13
+ classification was explicitly de-scoped in the v2 RFC (open question 3):
14
+ start with rules, revisit once Phase 2 data is in. Two dimensions are
15
+ runtime-computable without GT access:
16
+
17
+ * ``language`` — taken from ``SessionContext.primary_language`` (which
18
+ upstream loaders fill from the dataset row or repo metadata).
19
+ * ``has_stacktrace`` — regex sweep over the query text.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import json
25
+ import logging
26
+ import re
27
+ from dataclasses import dataclass
28
+ from pathlib import Path
29
+ from typing import Dict, FrozenSet, Iterable, Mapping, Optional, Union
30
+
31
+ from ..compiler.params import SessionContext
32
+ from ..languages import (
33
+ agent_language_aliases,
34
+ normalize_agent_language,
35
+ supported_agent_languages,
36
+ )
37
+
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ SUPPORTED_LANGUAGES: FrozenSet[str] = supported_agent_languages()
42
+
43
+
44
+ # Stack-trace regexes. Each pattern matches a *structural* marker that only
45
+ # appears in a real captured trace — not in user prose mentioning the word
46
+ # "traceback" or "panic". Patterns are anchored where the runtime emits them
47
+ # (line start) and use ``re.MULTILINE`` because problem_statement bodies
48
+ # typically embed traces inline.
49
+ _STACKTRACE_PATTERNS = (
50
+ # Python — exact runtime banner
51
+ re.compile(r"Traceback \(most recent call last\):"),
52
+ # Rust — panic header
53
+ re.compile(r"thread '[^']+' panicked at", re.IGNORECASE),
54
+ re.compile(r"\bpanicked at\b 'try '", re.IGNORECASE), # older rust style
55
+ # Go — runtime panic line + a goroutine frame
56
+ re.compile(r"^panic: ", re.MULTILINE),
57
+ re.compile(r"^goroutine \d+ \[", re.MULTILINE),
58
+ # JS / TS / Node — stack frames " at name (file.js:42[:col])"
59
+ re.compile(
60
+ r"^\s+at\s+\S+\s*\([^()\n]+:\d+(?::\d+)?\)\s*$",
61
+ re.MULTILINE,
62
+ ),
63
+ # JVM — "\tat com.example.Class.method(File.java:42)"
64
+ re.compile(r"^\s+at\s+\S+\.\S+\([^()\n]+:\d+\)\s*$", re.MULTILINE),
65
+ # Ruby — "/app/lib/foo.rb:42:in `bar'" or "\tfrom ...rb:8:in '<main>'"
66
+ re.compile(
67
+ r"^\s*(?:from\s+)?[^:\n]+\.rb:\d+:in\s+[`'][^`'\n]+[`']",
68
+ re.MULTILINE,
69
+ ),
70
+ # .NET — " at Namespace.Type.Method(...) in File.cs:line 42"
71
+ re.compile(
72
+ r"^\s+at\s+\S+\.\S+\([^()\n]*\)\s+in\s+[^:\n]+\.cs:line\s+\d+\s*$",
73
+ re.MULTILINE,
74
+ ),
75
+ # PHP — "#0 /app/src/Foo.php(42): Class->method(...)"
76
+ re.compile(r"^#\d+\s+[^()\n]+\.php\(\d+\):\s+\S+", re.MULTILINE),
77
+ # C/C++ — addr2line / backtrace lines look like "#0 0x... in fn at file:42"
78
+ re.compile(r"^#\d+\s+0x[0-9a-fA-F]+\s+in\s+\S+", re.MULTILINE),
79
+ )
80
+
81
+
82
+ def detect_stacktrace(query: str) -> bool:
83
+ """Return True if the query embeds a recognisable runtime stack trace."""
84
+ if not query:
85
+ return False
86
+ return any(p.search(query) for p in _STACKTRACE_PATTERNS)
87
+
88
+
89
+ _LANGUAGE_ALIASES: Dict[str, str] = agent_language_aliases()
90
+
91
+
92
+ def normalize_language(raw: Optional[str]) -> Optional[str]:
93
+ """Map a dataset / repo-meta language string to a canonical key.
94
+
95
+ Returns ``None`` for unknown or empty inputs so callers can branch on
96
+ "no language signal" without sentinel strings.
97
+ """
98
+ if not raw:
99
+ return None
100
+ return normalize_agent_language(raw)
101
+
102
+
103
+ @dataclass(frozen=True, slots=True)
104
+ class Scenario:
105
+ """A (query, repo) bucket used as a compile-table lookup key.
106
+
107
+ Two-dimensional per RFC v2 — ``query_length`` and ``query_concreteness``
108
+ from v1 were dropped to keep the eval cells statistically meaningful.
109
+ """
110
+
111
+ language: Optional[str]
112
+ has_stacktrace: bool
113
+
114
+ def key(self) -> str:
115
+ """Stable string key for ``compile_table.json`` lookup."""
116
+ lang = self.language or "unknown"
117
+ flag = "stacktrace" if self.has_stacktrace else "no_stacktrace"
118
+ return f"{lang}:{flag}"
119
+
120
+ @classmethod
121
+ def from_key(cls, key: str) -> "Scenario":
122
+ lang, flag = key.split(":", 1)
123
+ return cls(
124
+ language=None if lang == "unknown" else lang,
125
+ has_stacktrace=(flag == "stacktrace"),
126
+ )
127
+
128
+
129
+ def classify(query: str, session_ctx: Optional[SessionContext]) -> Scenario:
130
+ """Compute the scenario for a single (query, repo) pair."""
131
+ lang: Optional[str] = None
132
+ if session_ctx is not None:
133
+ lang = normalize_language(session_ctx.primary_language)
134
+ return Scenario(language=lang, has_stacktrace=detect_stacktrace(query))
135
+
136
+
137
+ CompileTable = Mapping[str, Iterable[str]]
138
+
139
+
140
+ def load_compile_table(path: Union[str, Path]) -> Dict[str, FrozenSet[str]]:
141
+ """Load a ``compile_table`` file as a ``{scenario_key: frozenset}`` map.
142
+
143
+ Supports JSON (``.json``) and YAML (``.yaml`` / ``.yml``). The on-disk
144
+ format is a mapping whose keys are the strings returned by
145
+ :meth:`Scenario.key` and whose values are lists of skill IDs.
146
+ """
147
+ p = Path(path)
148
+ suffix = p.suffix.lower()
149
+ with p.open("r", encoding="utf-8") as f:
150
+ if suffix in {".yaml", ".yml"}:
151
+ import yaml # local import — PyYAML is already a project dep
152
+
153
+ raw = yaml.safe_load(f)
154
+ elif suffix == ".json":
155
+ raw = json.load(f)
156
+ else:
157
+ raise ValueError(
158
+ f"compile_table at {p}: unsupported extension {suffix!r}; "
159
+ "use .json, .yaml, or .yml"
160
+ )
161
+ if not isinstance(raw, dict):
162
+ raise ValueError(
163
+ f"compile_table at {p} must be a mapping, got {type(raw).__name__}"
164
+ )
165
+ out: Dict[str, FrozenSet[str]] = {}
166
+ for k, v in raw.items():
167
+ if not isinstance(v, (list, tuple)):
168
+ raise ValueError(
169
+ f"compile_table[{k!r}] must be a list of skill IDs, "
170
+ f"got {type(v).__name__}"
171
+ )
172
+ out[k] = frozenset(str(s) for s in v)
173
+ return out
174
+
175
+
176
+ def agent_compile(
177
+ query: str,
178
+ session_ctx: Optional[SessionContext],
179
+ table: Optional[CompileTable] = None,
180
+ ) -> Optional[FrozenSet[str]]:
181
+ """Resolve which skills the agent should be allowed to invoke.
182
+
183
+ Args:
184
+ query: The incoming user query / problem statement.
185
+ session_ctx: Repo-side context (language, repo size, ...). May be ``None``.
186
+ table: Mapping from scenario key to skill-ID iterable. ``None`` or empty
187
+ means "no restriction" — caller should expose the full registry.
188
+
189
+ Returns:
190
+ A ``frozenset`` of skill IDs to allow, or ``None`` to signal "no
191
+ restriction" (caller falls back to its default, typically A6 = full
192
+ registry). This matches ``AgentRunner.allow_skills`` semantics where
193
+ ``None`` means "no filter".
194
+ """
195
+ if not table:
196
+ return None
197
+ scenario = classify(query, session_ctx)
198
+ key = scenario.key()
199
+ if key in table:
200
+ return frozenset(table[key])
201
+ logger.warning(
202
+ "agent_compile: scenario %r not in compile_table (size=%d); "
203
+ "falling back to full registry",
204
+ key,
205
+ len(table),
206
+ )
207
+ return None
208
+
209
+
210
+ __all__ = [
211
+ "Scenario",
212
+ "CompileTable",
213
+ "SUPPORTED_LANGUAGES",
214
+ "classify",
215
+ "detect_stacktrace",
216
+ "normalize_language",
217
+ "load_compile_table",
218
+ "agent_compile",
219
+ ]