agent-coderag 1.3.1__tar.gz → 1.3.3__tar.gz

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 (80) hide show
  1. {agent_coderag-1.3.1/agent_coderag.egg-info → agent_coderag-1.3.3}/PKG-INFO +26 -3
  2. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/README.md +23 -1
  3. {agent_coderag-1.3.1 → agent_coderag-1.3.3/agent_coderag.egg-info}/PKG-INFO +26 -3
  4. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/agent_coderag.egg-info/SOURCES.txt +14 -0
  5. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/agent_coderag.egg-info/requires.txt +2 -1
  6. agent_coderag-1.3.3/code_rag/__init__.py +16 -0
  7. agent_coderag-1.3.3/code_rag/api/__init__.py +6 -0
  8. agent_coderag-1.3.3/code_rag/api/client.py +87 -0
  9. agent_coderag-1.3.3/code_rag/api/models.py +20 -0
  10. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/core/manager.py +14 -1
  11. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/entry/cli.py +90 -106
  12. agent_coderag-1.3.3/code_rag/services/config.py +25 -0
  13. agent_coderag-1.3.3/code_rag/services/discovery_api.py +8 -0
  14. agent_coderag-1.3.3/code_rag/services/factory.py +28 -0
  15. agent_coderag-1.3.3/code_rag/services/search.py +6 -0
  16. agent_coderag-1.3.3/code_rag/services/setup.py +72 -0
  17. agent_coderag-1.3.3/code_rag/services/sync.py +101 -0
  18. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/pyproject.toml +3 -2
  19. agent_coderag-1.3.3/tests/test_api_client.py +186 -0
  20. agent_coderag-1.3.3/tests/test_api_models.py +25 -0
  21. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_cli.py +26 -0
  22. agent_coderag-1.3.3/tests/test_cli_json_parity.py +100 -0
  23. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_manager_detailed.py +30 -1
  24. agent_coderag-1.3.3/tests/test_readme_library_usage.py +8 -0
  25. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/LICENSE +0 -0
  26. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/NOTICE +0 -0
  27. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/agent_coderag.egg-info/dependency_links.txt +0 -0
  28. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/agent_coderag.egg-info/entry_points.txt +0 -0
  29. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/agent_coderag.egg-info/top_level.txt +0 -0
  30. {agent_coderag-1.3.1/code_rag → agent_coderag-1.3.3/code_rag/core}/__init__.py +0 -0
  31. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/core/constants.py +0 -0
  32. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/core/exceptions.py +0 -0
  33. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/core/interfaces.py +0 -0
  34. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/core/models.py +0 -0
  35. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/core/utils.py +0 -0
  36. {agent_coderag-1.3.1/code_rag/core → agent_coderag-1.3.3/code_rag/discovery}/__init__.py +0 -0
  37. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/discovery/dependency.py +0 -0
  38. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/discovery/java_discovery.py +0 -0
  39. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/discovery/manager.py +0 -0
  40. {agent_coderag-1.3.1/code_rag/discovery → agent_coderag-1.3.3/code_rag/discovery/providers}/__init__.py +0 -0
  41. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/discovery/providers/base.py +0 -0
  42. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/discovery/providers/csharp.py +0 -0
  43. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/discovery/providers/go.py +0 -0
  44. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/discovery/providers/java.py +0 -0
  45. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/discovery/providers/javascript.py +0 -0
  46. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/discovery/providers/python.py +0 -0
  47. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/discovery/providers/rust.py +0 -0
  48. {agent_coderag-1.3.1/code_rag/discovery/providers → agent_coderag-1.3.3/code_rag/entry}/__init__.py +0 -0
  49. {agent_coderag-1.3.1/code_rag/entry → agent_coderag-1.3.3/code_rag/intelligence}/__init__.py +0 -0
  50. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/intelligence/distiller.py +0 -0
  51. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/intelligence/embedder.py +0 -0
  52. {agent_coderag-1.3.1/code_rag/intelligence → agent_coderag-1.3.3/code_rag/parsers}/__init__.py +0 -0
  53. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/parsers/languages.py +0 -0
  54. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/parsers/multi_parser.py +0 -0
  55. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/parsers/tree_sitter.py +0 -0
  56. {agent_coderag-1.3.1/code_rag/parsers → agent_coderag-1.3.3/code_rag/services}/__init__.py +0 -0
  57. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/storage/__init__.py +0 -0
  58. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/code_rag/storage/duckdb_impl.py +0 -0
  59. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/setup.cfg +0 -0
  60. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_cli_detailed.py +0 -0
  61. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_code_rag_simple.py +0 -0
  62. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_csharp_discovery_detailed.py +0 -0
  63. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_dependency_discovery.py +0 -0
  64. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_discovery_manager_detailed.py +0 -0
  65. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_discovery_providers_extra.py +0 -0
  66. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_discovery_python.py +0 -0
  67. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_distiller.py +0 -0
  68. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_distiller_extra.py +0 -0
  69. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_embedder.py +0 -0
  70. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_embedder_detailed.py +0 -0
  71. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_interfaces.py +0 -0
  72. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_js_discovery_detailed.py +0 -0
  73. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_languages.py +0 -0
  74. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_manager_extra.py +0 -0
  75. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_models.py +0 -0
  76. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_multi_parser.py +0 -0
  77. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_rust_discovery_detailed.py +0 -0
  78. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_storage_detailed.py +0 -0
  79. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_tree_sitter_parser.py +0 -0
  80. {agent_coderag-1.3.1 → agent_coderag-1.3.3}/tests/test_utils_detailed.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-coderag
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: Lightweight semantic code search and distillation utility for AI coding agents. It solves the API knowledge gap via real-time local signature extraction and intent analysis without PyTorch. Optimized for token efficiency, it compresses codebase context into compact semantic summaries stored in a local DuckDB vector similarity index.
5
5
  Author-email: Igor Boloban <naranor@gmail.com>
6
6
  License: MIT
@@ -24,11 +24,12 @@ License-File: LICENSE
24
24
  License-File: NOTICE
25
25
  Requires-Dist: duckdb
26
26
  Requires-Dist: numpy
27
- Requires-Dist: litellm
27
+ Requires-Dist: litellm==1.96.2
28
28
  Requires-Dist: onnxruntime
29
29
  Requires-Dist: tokenizers
30
30
  Requires-Dist: pydantic
31
31
  Requires-Dist: httpx
32
+ Requires-Dist: requests
32
33
  Requires-Dist: aiofiles
33
34
  Requires-Dist: pathspec
34
35
  Requires-Dist: tree-sitter
@@ -123,10 +124,17 @@ If you don't configure an LLM provider, agent-coderag works in **100% Offline Mo
123
124
  # Index your entire project (respects .gitignore automatically)
124
125
  agent-coderag sync --all
125
126
 
127
+ # Trusted Maven/Gradle projects only: allow dependency resolution
128
+ agent-coderag sync --all --allow-build-execution
129
+
126
130
  # Perform a semantic search
127
131
  agent-coderag search "how does the authentication middleware work?"
128
132
  ```
129
133
 
134
+ Dependency build execution is disabled by default. Maven and Gradle build files
135
+ can execute repository-controlled code, so use `--allow-build-execution` only
136
+ after you have reviewed and trust the project.
137
+
130
138
  ### API Discovery
131
139
  Verify external library signatures without leaving the CLI:
132
140
  ```bash
@@ -141,12 +149,27 @@ agent-coderag api fmt
141
149
 
142
150
  ---
143
151
 
152
+ ## Library Usage
153
+
154
+ ```python
155
+ from code_rag import CodeRAG
156
+
157
+ async def main():
158
+ async with CodeRAG(db="code_rag.db") as rag:
159
+ await rag.setup()
160
+ await rag.sync(index_all=True)
161
+ hits = await rag.search("authentication middleware", limit=5)
162
+ report = await rag.api("pydantic", lang="python")
163
+ ```
164
+
165
+ ---
166
+
144
167
  ## Supported Ecosystems (Discovery)
145
168
 
146
169
  | Language | Method | Discovery Source |
147
170
  | :--- | :--- | :--- |
148
171
  | **Python** | 3-Stage Probe | `.pyi` stubs, static source, or runtime `inspect` |
149
- | **Java** | Bytecode Reflection | JARs resolved via Maven (`pom.xml`) or Gradle |
172
+ | **Java** | Bytecode Reflection | JARs resolved via Maven or Gradle with explicit `--allow-build-execution` opt-in |
150
173
  | **Go** | Standard Tooling | Native `go doc -all` integration |
151
174
  | **TypeScript/JS** | Declaration Maps | `.d.ts` files from `node_modules` or `@types` |
152
175
  | **Rust** | Registry Analysis | Source code from Cargo registry via `cargo metadata` |
@@ -78,10 +78,17 @@ If you don't configure an LLM provider, agent-coderag works in **100% Offline Mo
78
78
  # Index your entire project (respects .gitignore automatically)
79
79
  agent-coderag sync --all
80
80
 
81
+ # Trusted Maven/Gradle projects only: allow dependency resolution
82
+ agent-coderag sync --all --allow-build-execution
83
+
81
84
  # Perform a semantic search
82
85
  agent-coderag search "how does the authentication middleware work?"
83
86
  ```
84
87
 
88
+ Dependency build execution is disabled by default. Maven and Gradle build files
89
+ can execute repository-controlled code, so use `--allow-build-execution` only
90
+ after you have reviewed and trust the project.
91
+
85
92
  ### API Discovery
86
93
  Verify external library signatures without leaving the CLI:
87
94
  ```bash
@@ -96,12 +103,27 @@ agent-coderag api fmt
96
103
 
97
104
  ---
98
105
 
106
+ ## Library Usage
107
+
108
+ ```python
109
+ from code_rag import CodeRAG
110
+
111
+ async def main():
112
+ async with CodeRAG(db="code_rag.db") as rag:
113
+ await rag.setup()
114
+ await rag.sync(index_all=True)
115
+ hits = await rag.search("authentication middleware", limit=5)
116
+ report = await rag.api("pydantic", lang="python")
117
+ ```
118
+
119
+ ---
120
+
99
121
  ## Supported Ecosystems (Discovery)
100
122
 
101
123
  | Language | Method | Discovery Source |
102
124
  | :--- | :--- | :--- |
103
125
  | **Python** | 3-Stage Probe | `.pyi` stubs, static source, or runtime `inspect` |
104
- | **Java** | Bytecode Reflection | JARs resolved via Maven (`pom.xml`) or Gradle |
126
+ | **Java** | Bytecode Reflection | JARs resolved via Maven or Gradle with explicit `--allow-build-execution` opt-in |
105
127
  | **Go** | Standard Tooling | Native `go doc -all` integration |
106
128
  | **TypeScript/JS** | Declaration Maps | `.d.ts` files from `node_modules` or `@types` |
107
129
  | **Rust** | Registry Analysis | Source code from Cargo registry via `cargo metadata` |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-coderag
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: Lightweight semantic code search and distillation utility for AI coding agents. It solves the API knowledge gap via real-time local signature extraction and intent analysis without PyTorch. Optimized for token efficiency, it compresses codebase context into compact semantic summaries stored in a local DuckDB vector similarity index.
5
5
  Author-email: Igor Boloban <naranor@gmail.com>
6
6
  License: MIT
@@ -24,11 +24,12 @@ License-File: LICENSE
24
24
  License-File: NOTICE
25
25
  Requires-Dist: duckdb
26
26
  Requires-Dist: numpy
27
- Requires-Dist: litellm
27
+ Requires-Dist: litellm==1.96.2
28
28
  Requires-Dist: onnxruntime
29
29
  Requires-Dist: tokenizers
30
30
  Requires-Dist: pydantic
31
31
  Requires-Dist: httpx
32
+ Requires-Dist: requests
32
33
  Requires-Dist: aiofiles
33
34
  Requires-Dist: pathspec
34
35
  Requires-Dist: tree-sitter
@@ -123,10 +124,17 @@ If you don't configure an LLM provider, agent-coderag works in **100% Offline Mo
123
124
  # Index your entire project (respects .gitignore automatically)
124
125
  agent-coderag sync --all
125
126
 
127
+ # Trusted Maven/Gradle projects only: allow dependency resolution
128
+ agent-coderag sync --all --allow-build-execution
129
+
126
130
  # Perform a semantic search
127
131
  agent-coderag search "how does the authentication middleware work?"
128
132
  ```
129
133
 
134
+ Dependency build execution is disabled by default. Maven and Gradle build files
135
+ can execute repository-controlled code, so use `--allow-build-execution` only
136
+ after you have reviewed and trust the project.
137
+
130
138
  ### API Discovery
131
139
  Verify external library signatures without leaving the CLI:
132
140
  ```bash
@@ -141,12 +149,27 @@ agent-coderag api fmt
141
149
 
142
150
  ---
143
151
 
152
+ ## Library Usage
153
+
154
+ ```python
155
+ from code_rag import CodeRAG
156
+
157
+ async def main():
158
+ async with CodeRAG(db="code_rag.db") as rag:
159
+ await rag.setup()
160
+ await rag.sync(index_all=True)
161
+ hits = await rag.search("authentication middleware", limit=5)
162
+ report = await rag.api("pydantic", lang="python")
163
+ ```
164
+
165
+ ---
166
+
144
167
  ## Supported Ecosystems (Discovery)
145
168
 
146
169
  | Language | Method | Discovery Source |
147
170
  | :--- | :--- | :--- |
148
171
  | **Python** | 3-Stage Probe | `.pyi` stubs, static source, or runtime `inspect` |
149
- | **Java** | Bytecode Reflection | JARs resolved via Maven (`pom.xml`) or Gradle |
172
+ | **Java** | Bytecode Reflection | JARs resolved via Maven or Gradle with explicit `--allow-build-execution` opt-in |
150
173
  | **Go** | Standard Tooling | Native `go doc -all` integration |
151
174
  | **TypeScript/JS** | Declaration Maps | `.d.ts` files from `node_modules` or `@types` |
152
175
  | **Rust** | Registry Analysis | Source code from Cargo registry via `cargo metadata` |
@@ -9,6 +9,9 @@ agent_coderag.egg-info/entry_points.txt
9
9
  agent_coderag.egg-info/requires.txt
10
10
  agent_coderag.egg-info/top_level.txt
11
11
  code_rag/__init__.py
12
+ code_rag/api/__init__.py
13
+ code_rag/api/client.py
14
+ code_rag/api/models.py
12
15
  code_rag/core/__init__.py
13
16
  code_rag/core/constants.py
14
17
  code_rag/core/exceptions.py
@@ -37,10 +40,20 @@ code_rag/parsers/__init__.py
37
40
  code_rag/parsers/languages.py
38
41
  code_rag/parsers/multi_parser.py
39
42
  code_rag/parsers/tree_sitter.py
43
+ code_rag/services/__init__.py
44
+ code_rag/services/config.py
45
+ code_rag/services/discovery_api.py
46
+ code_rag/services/factory.py
47
+ code_rag/services/search.py
48
+ code_rag/services/setup.py
49
+ code_rag/services/sync.py
40
50
  code_rag/storage/__init__.py
41
51
  code_rag/storage/duckdb_impl.py
52
+ tests/test_api_client.py
53
+ tests/test_api_models.py
42
54
  tests/test_cli.py
43
55
  tests/test_cli_detailed.py
56
+ tests/test_cli_json_parity.py
44
57
  tests/test_code_rag_simple.py
45
58
  tests/test_csharp_discovery_detailed.py
46
59
  tests/test_dependency_discovery.py
@@ -58,6 +71,7 @@ tests/test_manager_detailed.py
58
71
  tests/test_manager_extra.py
59
72
  tests/test_models.py
60
73
  tests/test_multi_parser.py
74
+ tests/test_readme_library_usage.py
61
75
  tests/test_rust_discovery_detailed.py
62
76
  tests/test_storage_detailed.py
63
77
  tests/test_tree_sitter_parser.py
@@ -1,10 +1,11 @@
1
1
  duckdb
2
2
  numpy
3
- litellm
3
+ litellm==1.96.2
4
4
  onnxruntime
5
5
  tokenizers
6
6
  pydantic
7
7
  httpx
8
+ requests
8
9
  aiofiles
9
10
  pathspec
10
11
  tree-sitter
@@ -0,0 +1,16 @@
1
+ from code_rag.api.client import CodeRAG
2
+ from code_rag.api.models import SyncResult, ApiReport, SetupResult
3
+ from code_rag.core.models import KnowledgeUnit, UnitKind
4
+ from code_rag.intelligence.distiller import DistillerConfig
5
+ from code_rag.core.exceptions import CodeRAGError
6
+
7
+ __all__ = [
8
+ "CodeRAG",
9
+ "SyncResult",
10
+ "ApiReport",
11
+ "SetupResult",
12
+ "KnowledgeUnit",
13
+ "UnitKind",
14
+ "DistillerConfig",
15
+ "CodeRAGError",
16
+ ]
@@ -0,0 +1,6 @@
1
+ """Public API package for CodeRAG.
2
+
3
+ `CodeRAG` lives in `code_rag.api.client` and is re-exported from top-level
4
+ `code_rag`. Import models from `code_rag.api.models` directly; this package
5
+ init stays empty to avoid circular imports with `code_rag.services.*`.
6
+ """
@@ -0,0 +1,87 @@
1
+ from pathlib import Path
2
+ from typing import Optional, Union
3
+
4
+ from code_rag.api.models import ApiReport, SetupResult, SyncResult
5
+ from code_rag.core.models import KnowledgeUnit
6
+ from code_rag.intelligence.distiller import DistillerConfig
7
+ from code_rag.services.config import load_or_update_config
8
+ from code_rag.services.discovery_api import run_api
9
+ from code_rag.services.factory import create_manager
10
+ from code_rag.services.search import run_search
11
+ from code_rag.services.setup import run_setup
12
+ from code_rag.services.sync import run_rebuild, run_sync
13
+
14
+
15
+ class CodeRAG:
16
+ """Public async facade over CodeRAG services and the storage/search manager."""
17
+
18
+ def __init__(
19
+ self,
20
+ db: str = "code_rag.db",
21
+ onnx: Optional[str] = None,
22
+ *,
23
+ root: Optional[Union[str, Path]] = None,
24
+ allow_build_execution: bool = False,
25
+ ):
26
+ self._db = db
27
+ self._onnx = onnx
28
+ self._root = Path(root) if root is not None else Path.cwd()
29
+ self._allow_build_execution = allow_build_execution
30
+ self._manager = None
31
+
32
+ async def __aenter__(self) -> "CodeRAG":
33
+ return self
34
+
35
+ async def __aexit__(self, *_exc) -> None:
36
+ await self.close()
37
+
38
+ async def close(self) -> None:
39
+ if self._manager is not None:
40
+ await self._manager.close()
41
+ self._manager = None
42
+
43
+ def _ensure_manager(self):
44
+ if self._manager is None:
45
+ self._manager = create_manager(
46
+ self._db, self._onnx, allow_build_execution=self._allow_build_execution
47
+ )
48
+ return self._manager
49
+
50
+ async def config(
51
+ self,
52
+ *,
53
+ url: Optional[str] = None,
54
+ key: Optional[str] = None,
55
+ model: Optional[str] = None,
56
+ provider: Optional[str] = None,
57
+ ) -> DistillerConfig:
58
+ return load_or_update_config(url=url, key=key, model=model, provider=provider)
59
+
60
+ async def setup(self, *, force: bool = False) -> SetupResult:
61
+ return await run_setup(force=force)
62
+
63
+ async def sync(
64
+ self,
65
+ path: Optional[str] = None,
66
+ *,
67
+ index_all: bool = False,
68
+ force: bool = False,
69
+ ) -> SyncResult:
70
+ if path is None and not index_all:
71
+ return SyncResult(status="success", indexed_files=0)
72
+ return await run_sync(
73
+ self._ensure_manager(),
74
+ root=self._root,
75
+ path=path,
76
+ index_all=index_all,
77
+ force=force,
78
+ )
79
+
80
+ async def search(self, query: str, *, limit: int = 5) -> list[KnowledgeUnit]:
81
+ return await run_search(self._ensure_manager(), query, limit=limit)
82
+
83
+ async def api(self, library: str, *, lang: Optional[str] = None) -> ApiReport:
84
+ return await run_api(self._ensure_manager(), library, lang=lang)
85
+
86
+ async def rebuild(self) -> SyncResult:
87
+ return await run_rebuild(self._ensure_manager(), root=self._root)
@@ -0,0 +1,20 @@
1
+ from pydantic import BaseModel, ConfigDict
2
+
3
+
4
+ class SyncResult(BaseModel):
5
+ status: str
6
+ indexed_files: int
7
+
8
+
9
+ class ApiReport(BaseModel):
10
+ library: str
11
+ language: str
12
+ report: str
13
+
14
+
15
+ class SetupResult(BaseModel):
16
+ model_config = ConfigDict(protected_namespaces=())
17
+
18
+ model_dir: str
19
+ downloaded: list[str]
20
+ skipped: list[str]
@@ -19,17 +19,19 @@ class CodeRAGManager:
19
19
  Orchestrates the RAG workflow: parsing, distillation, and storage.
20
20
  """
21
21
 
22
- def __init__(
22
+ def __init__( # pylint: disable=too-many-arguments,too-many-positional-arguments
23
23
  self,
24
24
  storage: IStorage,
25
25
  parser: IParser,
26
26
  intelligence: IIntelligence,
27
27
  max_concurrency: int = MAX_CONCURRENT_TASKS,
28
+ allow_build_execution: bool = False,
28
29
  ):
29
30
  self.storage = storage
30
31
  self.parser = parser
31
32
  self.intelligence = intelligence
32
33
  self.max_concurrency = max_concurrency
34
+ self.allow_build_execution = allow_build_execution
33
35
  self.semaphore = asyncio.Semaphore(max_concurrency)
34
36
  self.discovery = DiscoveryManager(storage=storage)
35
37
 
@@ -41,6 +43,17 @@ class CodeRAGManager:
41
43
  pom_xml = root / "pom.xml"
42
44
  gradle_files = list(root.glob("build.gradle*"))
43
45
 
46
+ if not pom_xml.exists() and not gradle_files:
47
+ return
48
+
49
+ if not self.allow_build_execution:
50
+ logger.warning(
51
+ "Dependency sync is disabled by default because Maven/Gradle "
52
+ "build files are executable repository code. Use the explicit "
53
+ "allow_build_execution option only for trusted projects."
54
+ )
55
+ return
56
+
44
57
  if pom_xml.exists():
45
58
  await self._sync_maven(root)
46
59
  elif gradle_files:
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  import asyncio
3
- import os
4
3
  import argparse
5
4
  import sys
6
5
  import json
@@ -15,87 +14,66 @@ from ..storage.duckdb_impl import DuckDBStorage
15
14
  from ..parsers.multi_parser import MultiParser
16
15
  from ..intelligence.distiller import Distiller, DistillerConfig
17
16
  from ..intelligence.embedder import Embedder, get_global_dir
18
- from ..parsers.languages import EXTENSION_TO_LANGUAGE
19
17
  from ..core.utils import validate_path
20
- from ..core.exceptions import CodeRAGError, DiscoveryError
18
+ from ..core.exceptions import CodeRAGError
19
+ from ..services import sync as sync_service
20
+ from ..services.discovery_api import run_api
21
+ from ..services.search import run_search
22
+ from ..services.setup import run_setup
21
23
 
22
24
  logger = logging.getLogger(__name__)
23
25
 
26
+ # Legacy compatibility surface: these names are imported/patched by existing
27
+ # integrations and tests, so they must stay resolvable on this module.
28
+ __all__ = [
29
+ "get_manager",
30
+ "load_ignore_patterns",
31
+ "should_index",
32
+ "sync_cmd",
33
+ "search_cmd",
34
+ "api_cmd",
35
+ "config_cmd",
36
+ "setup_cmd",
37
+ "rebuild_cmd",
38
+ "DistillerConfig",
39
+ "Embedder",
40
+ "DuckDBStorage",
41
+ "MultiParser",
42
+ "Distiller",
43
+ "get_global_dir",
44
+ "requests",
45
+ "validate_path",
46
+ "main",
47
+ ]
48
+
24
49
 
25
50
  def load_ignore_patterns() -> pathspec.PathSpec:
26
- """Loads ignore patterns from .gitignore or defaults."""
27
- lines = []
28
- if os.path.exists(".gitignore"):
29
- with open(".gitignore", "r", encoding="utf-8") as f:
30
- lines = f.readlines()
31
-
32
- common_excludes = [
33
- "node_modules/",
34
- "venv/",
35
- ".venv/",
36
- "__pycache__/",
37
- ".git/",
38
- ".idea/",
39
- ".vscode/",
40
- ".onnx",
41
- ".db",
42
- ".ai/",
43
- ]
44
- return pathspec.PathSpec.from_lines("gitignore", lines + common_excludes)
51
+ """Loads ignore patterns from the current directory's .gitignore or defaults."""
52
+ return sync_service.load_ignore_patterns(Path.cwd())
45
53
 
46
54
 
47
55
  def should_index(path: Path, ignore_spec: Optional[pathspec.PathSpec] = None) -> bool:
48
56
  """Filters files that should NOT be indexed."""
49
- # Convert backslashes to forward slashes for cross-platform matching
50
- path_str = str(path).replace(os.sep, "/")
51
-
52
- # 1. Check against ignore spec (including .gitignore and common excludes)
53
- if ignore_spec and ignore_spec.match_file(path_str):
54
- return False
55
-
56
- return path.suffix.lower() in EXTENSION_TO_LANGUAGE
57
+ return sync_service.should_index(path, ignore_spec)
57
58
 
58
59
 
59
60
  async def sync_cmd(args):
60
- # Validate input path
61
61
  if args.path:
62
62
  args.path = str(validate_path(args.path))
63
63
 
64
- manager = get_manager(args.db, args.onnx)
64
+ manager = get_manager(
65
+ args.db,
66
+ args.onnx,
67
+ allow_build_execution=getattr(args, "allow_build_execution", False),
68
+ )
65
69
  try:
66
- ignore_spec = load_ignore_patterns()
67
-
68
- # Task 2: Sync dependencies before indexing
69
- try:
70
- await manager.sync_dependencies(args.path or ".")
71
- except DiscoveryError as de:
72
- logger.warning("Dependency discovery failed: %s", de)
73
-
74
- if args.path:
75
- target_path = Path(args.path)
76
- if target_path.is_file():
77
- if should_index(target_path, ignore_spec):
78
- await manager.sync_file(str(target_path), force_distill=args.force)
79
- else:
80
- paths = [
81
- str(p)
82
- for p in target_path.rglob("*")
83
- if p.is_file() and should_index(p, ignore_spec)
84
- ]
85
-
86
- if args.verbose:
87
- logger.info("Indexing %d files...", len(paths))
88
- await manager.sync_project(paths, force_distill=args.force)
89
- elif args.all:
90
- paths = [
91
- str(p)
92
- for p in Path(".").rglob("*")
93
- if p.is_file() and should_index(p, ignore_spec)
94
- ]
95
-
96
- if args.verbose:
97
- logger.info("Indexing %d files...", len(paths))
98
- await manager.sync_project(paths, force_distill=args.force)
70
+ await sync_service.run_sync(
71
+ manager,
72
+ root=Path.cwd(),
73
+ path=args.path,
74
+ index_all=bool(args.all),
75
+ force=bool(args.force),
76
+ )
99
77
 
100
78
  if args.json:
101
79
  print(json.dumps({"status": "success", "indexed_files": "auto"}))
@@ -112,7 +90,7 @@ async def sync_cmd(args):
112
90
  async def search_cmd(args):
113
91
  manager = get_manager(args.db, args.onnx)
114
92
  try:
115
- results = await manager.search(args.query, limit=args.limit)
93
+ results = await run_search(manager, args.query, limit=args.limit)
116
94
 
117
95
  if args.json:
118
96
  output = []
@@ -146,14 +124,12 @@ async def search_cmd(args):
146
124
  async def api_cmd(args):
147
125
  manager = get_manager(args.db, args.onnx)
148
126
  try:
149
- # Default to python if not specified
150
- lang = args.lang or "python"
151
- api_report = await manager.discovery.extract_api(args.library, language=lang)
127
+ report = await run_api(manager, args.library, lang=args.lang)
152
128
 
153
129
  if args.json:
154
- print(json.dumps({"library": args.library, "report": api_report}))
130
+ print(json.dumps({"library": report.library, "report": report.report}))
155
131
  else:
156
- print(api_report)
132
+ print(report.report)
157
133
  except Exception as e:
158
134
  logger.error("API discovery failed: %s", e)
159
135
  if args.json:
@@ -196,40 +172,33 @@ def config_cmd(args):
196
172
  async def setup_cmd(args):
197
173
  """Downloads necessary local models."""
198
174
  global_dir = get_global_dir()
199
- model_dir = global_dir / "models" / "mini-lm"
200
- model_dir.mkdir(parents=True, exist_ok=True)
201
-
202
- files = {
203
- "model.onnx": "https://huggingface.co/naranor/all-MiniLM-L6-v2-onnx/resolve/main/model.onnx",
204
- "tokenizer.json": "https://huggingface.co/naranor/all-MiniLM-L6-v2-onnx/resolve/main/tokenizer.json",
205
- }
206
175
 
207
176
  if not args.json:
208
177
  print(f"Setting up agent-coderag in {global_dir}...")
209
178
 
210
- for name, url in files.items():
211
- target_path = model_dir / name
212
- if target_path.exists() and not args.force:
213
- if not args.json:
214
- print(f" {name} already exists. Skipping.")
215
- continue
216
-
217
- if not args.json:
218
- print(f" Downloading {name}...")
219
- tmp_path = target_path.with_suffix(".tmp")
220
- try:
221
- response = requests.get(url, stream=True, timeout=30)
222
- response.raise_for_status()
223
- with open(tmp_path, "wb") as f:
224
- for chunk in response.iter_content(chunk_size=8192):
225
- f.write(chunk)
226
- os.replace(tmp_path, target_path)
227
- except Exception as e:
228
- if tmp_path.exists():
229
- tmp_path.unlink()
230
- if not args.json:
231
- print(f" Error downloading {name}: {e}")
179
+ def _on_progress(event: str, name: str, error: Optional[BaseException]) -> None:
180
+ if args.json:
232
181
  return
182
+ if event == "skipped":
183
+ print(f" {name} already exists. Skipping.")
184
+ elif event == "downloading":
185
+ print(f" Downloading {name}...")
186
+ elif event == "error":
187
+ print(f" Error downloading {name}: {error}")
188
+
189
+ try:
190
+ # Pass module-level requests.get so @patch("code_rag.entry.cli.requests.get")
191
+ # continues to intercept downloads in legacy CLI tests.
192
+ await run_setup(
193
+ force=args.force,
194
+ global_dir=global_dir,
195
+ on_progress=_on_progress,
196
+ http_get=requests.get,
197
+ )
198
+ except Exception:
199
+ # Legacy behaviour: per-file error already reported via on_progress;
200
+ # stop here without crashing or printing "Setup complete.".
201
+ return
233
202
 
234
203
  if not args.json:
235
204
  print("Setup complete.")
@@ -244,19 +213,29 @@ async def rebuild_cmd(args):
244
213
  await sync_cmd(args)
245
214
 
246
215
 
247
- def get_manager(db_path: str, onnx_path: Optional[str] = None) -> CodeRAGManager:
248
- # 1. Setup Intelligence
216
+ def get_manager(
217
+ db_path: str,
218
+ onnx_path: Optional[str] = None,
219
+ allow_build_execution: bool = False,
220
+ ) -> CodeRAGManager:
221
+ """Wires a manager from the module-level components (legacy patch points).
222
+
223
+ Mirrors ``code_rag.services.factory.create_manager`` but resolves the
224
+ components through this module so existing CLI tests can substitute them.
225
+ """
249
226
  config = DistillerConfig.load()
250
227
  distiller = Distiller(config)
251
228
  embedder = Embedder(model_path=onnx_path)
252
229
 
253
- # 2. Setup Storage
254
230
  storage = DuckDBStorage(db_path, embedder=embedder)
255
-
256
- # 3. Setup Parser
257
231
  parser = MultiParser()
258
232
 
259
- return CodeRAGManager(storage, parser, distiller)
233
+ return CodeRAGManager(
234
+ storage,
235
+ parser,
236
+ distiller,
237
+ allow_build_execution=allow_build_execution,
238
+ )
260
239
 
261
240
 
262
241
  def main():
@@ -277,6 +256,11 @@ def main():
277
256
  sync.add_argument("path", nargs="?", help="File or directory to index.")
278
257
  sync.add_argument("--all", action="store_true", help="Index all supported files.")
279
258
  sync.add_argument("--force", action="store_true", help="Force re-distillation.")
259
+ sync.add_argument(
260
+ "--allow-build-execution",
261
+ action="store_true",
262
+ help="Execute repository Maven/Gradle build files during dependency sync (trusted projects only).",
263
+ )
280
264
 
281
265
  # Search
282
266
  search = subparsers.add_parser("search", help="Semantic search.")