codesearch-mcp 0.0.15-alpha → 0.0.17-alpha
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.
- package/CHANGELOG.md +53 -0
- package/README.md +74 -33
- package/dist/app.d.ts +1 -1
- package/dist/app.js +67 -16
- package/dist/src/commands/BackfillCommand.js +15 -5
- package/dist/src/commands/ConfigCommand.d.ts +12 -0
- package/dist/src/commands/ConfigCommand.js +98 -0
- package/dist/src/commands/IndexCommand.js +1 -1
- package/dist/src/config-store.d.ts +53 -0
- package/dist/src/config-store.js +197 -0
- package/dist/src/config.d.ts +22 -8
- package/dist/src/config.js +103 -58
- package/dist/src/container.d.ts +1 -1
- package/dist/src/container.js +8 -7
- package/dist/src/db/index.d.ts +2 -3
- package/dist/src/db/index.js +6 -7
- package/dist/src/db/schema.d.ts +577 -0
- package/dist/src/db/schema.js +47 -0
- package/dist/src/help.js +28 -12
- package/dist/src/interfaces/IAstParser.d.ts +19 -0
- package/dist/src/interfaces/IEmbedder.d.ts +1 -0
- package/dist/src/project-selector.d.ts +14 -5
- package/dist/src/project-selector.js +74 -60
- package/dist/src/services/AstParserService.d.ts +7 -0
- package/dist/src/services/AstParserService.js +191 -28
- package/dist/src/services/DatabaseService.d.ts +11 -4
- package/dist/src/services/DatabaseService.js +107 -48
- package/dist/src/services/IndexerService.d.ts +9 -0
- package/dist/src/services/IndexerService.js +224 -60
- package/dist/src/services/LoggerService.d.ts +5 -1
- package/dist/src/services/LoggerService.js +8 -5
- package/dist/src/services/McpServer.d.ts +1 -0
- package/dist/src/services/McpServer.js +74 -4
- package/dist/src/services/OllamaEmbedder.d.ts +2 -0
- package/dist/src/services/OllamaEmbedder.js +29 -0
- package/dist/src/services/SearcherService.d.ts +13 -0
- package/dist/src/services/SearcherService.js +118 -22
- package/dist/src/setup.js +57 -62
- package/package.json +4 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,59 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
5
5
|
|
|
6
|
+
## [0.0.17-alpha] - 2026-05-13
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- **`get_callers` MCP tool** — finds all call sites of a function or method by exact name. Uses the `code_call` table populated by `rag-index backfill --calls`. Requires both `symbol` and `project`; optional `callee_file` to disambiguate overloaded names. Returns empty if backfill has not been run.
|
|
11
|
+
|
|
12
|
+
- **Call graph indexing** — `code_call` table records per-call-site entries `(project, fromFile, fromSymbol, calleeName, calleeFile, calleeSymbol, line, col)`. Populated during normal indexing (`ingestFile`) and via `rag-index backfill --calls` for existing installations. `AstParserService` extracts call expressions using ts-morph `CallExpression` nodes.
|
|
13
|
+
|
|
14
|
+
- **`analyzeProject` `skipDependencyResolution` option** — `IAstParser.analyzeProject` now accepts `opts?: { skipDependencyResolution?: boolean }`. `AstParserService.createMorphProject` propagates the flag to ts-morph `Project` options. Used by `IndexerService` for large projects to avoid OOM.
|
|
15
|
+
|
|
16
|
+
- **Configurable AST batch size (`indexing.astBatchSize`)** — `IndexerService` splits large projects into ts-morph batches. Threshold and batch size are now controlled by `indexing.astBatchSize` (default `3000`, configurable via `rag-config set indexing.astBatchSize <N>`). Projects above the threshold use `skipDependencyResolution: true` and print a console warning about potentially incomplete cross-batch dependency edges.
|
|
17
|
+
|
|
18
|
+
- **`include_graph_context` parameter for `search_codebase`** — appends direct imports and dependents inline with each result (`Imports: X · Y` / `Used by: Z`), eliminating separate `get_dependencies` / `get_dependents` calls for basic context. Single batch SQL query (UNION ALL + VALUES) for all result files — no N+1. Deduplicates via Sets; limits to 50 entries per direction per file.
|
|
19
|
+
|
|
20
|
+
- **Cross-encoder reranking** — optional second-pass via `POST /api/rerank` (requires Ollama ≥ 0.6). Controlled by `reranker.enabled`, `reranker.model`, `reranker.url` (defaults to `${ollama.host}/api/rerank`), `reranker.overfetch`. When enabled, `search_codebase` overfetches `limit × reranker.overfetch` vector candidates and reranks before returning `limit` results. Falls back gracefully to vector order on error (`warn` log). `rerank?` is an optional method on `IEmbedder` — `OllamaEmbedder` assigns it only when both `reranker.enabled=true` and `reranker.model` is set.
|
|
21
|
+
|
|
22
|
+
- **`ProjectSelector` unit tests** — full test coverage for project selection workflows including first-run auto-select, `--select` flag, `.ragprojects` / `.ragskip` persistence
|
|
23
|
+
|
|
24
|
+
- **`rag-config` command** — manage `~/.config/codesearch-mcp/config.json` from the CLI: `rag-config show`, `rag-config get <key>`, `rag-config set <key> <value>`, `rag-config reset <key>`. Supports all config keys with type coercion (string / number / boolean).
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **Config migrated from `.env` to `config.json`** — configuration is now stored in `~/.config/codesearch-mcp/config.json` instead of a `.env` file. `rag-setup` writes JSON; `dotenv` dependency removed. Existing `.env` files are no longer read — run `rag-setup` once to migrate.
|
|
29
|
+
|
|
30
|
+
- **`Config` class replaces module-level singleton** — `src/config.ts` now exports a `Config` class instantiated in `createContainer()`. Reads `config.json` via `readConfigJson()`, Zod-validates, throws `ConfigError` on missing required fields (caught in `app.ts` with a user-friendly message).
|
|
31
|
+
|
|
32
|
+
- **`LoggerService.fromConfig(cfg, name?)`** replaces `fromEnv()` — takes the `logging` sub-object from `Config` directly instead of reading `LOG_LEVEL` / `LOG_DIR` from `process.env`.
|
|
33
|
+
|
|
34
|
+
- **`reranker.*` and `search.*` config keys** — `RERANKER_ENABLED` and `RERANKER_OVERFETCH` in `config.search`; `config.ollama` retains only `rerankerModel` and `rerankerUrl`
|
|
35
|
+
- **`fetchLimit` capped at 200** — prevents runaway DB queries when `reranker.overfetch` is high
|
|
36
|
+
- **Reranker index validation** — indices from cross-encoder filtered for bounds before mapping
|
|
37
|
+
- **30s timeout + truncated error body on rerank HTTP call** — `AbortSignal.timeout(30_000)`; error body sliced to 200 chars
|
|
38
|
+
- **Enriched embedding context** — chunks now include `Project`, `Role` (inferred from file path), `Symbols` (overlapping definitions), and `Dependencies` in the embedding prompt. Improves semantic search quality for architectural queries. **Requires full re-index** (`rag-index --reindex`).
|
|
39
|
+
- **`ProjectSelector` refactored** — improved modularity and maintainability; extracted logic into smaller focused methods
|
|
40
|
+
- **`IndexCommand` argument validation** — enhanced error handling and validation across CLI modes
|
|
41
|
+
|
|
42
|
+
## [0.0.16-alpha] - 2026-05-02
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- **Hybrid incremental indexing (mtime + SHA-256)** — `rag-index` now uses a two-step skip check per file: fast `mtime` comparison first (no file read), then SHA-256 content hash if `mtime` changed. Files with identical content but reset timestamps (after `git clone`, DB transfer, or `touch`) are skipped without re-embedding. `lastModified` is refreshed in a single batch SQL `UPDATE` after each project scan. `--reindex` clears both fields.
|
|
47
|
+
- `contentHash varchar(64)` column added to `code_chunk`; applied automatically via `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` on startup — no manual migration needed.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- **Migrated from TypeORM to Drizzle ORM** — schema management and queries rewritten with Drizzle API; TypeORM decorators and metadata removed
|
|
52
|
+
- **Batch AST parsing (`analyzeProject`)** — `IndexerService` now parses all project files in a single `MorphProject` instance instead of one per file, reducing ts-morph overhead on large projects
|
|
53
|
+
- **Enriched embedding context** — chunks now include `[Symbols: class Foo, function bar]` tag when the chunk overlaps known symbol definitions, improving semantic search quality for partial/truncated chunks. **Requires full re-index** (`rag-index /path --reindex`) — existing embeddings were built without symbol context and will produce degraded similarity scores against new chunks if mixed.
|
|
54
|
+
- **`endLine` added to `SymbolEntry`** — enables accurate chunk-to-symbol overlap detection used by enriched prompts
|
|
55
|
+
- **`analyzeProject` error isolation** — parse failures are caught per-file; one broken file no longer aborts the entire project scan
|
|
56
|
+
- **Memory cleanup in `analyzeProject`** — source files are explicitly removed from `MorphProject` after parsing to release memory
|
|
57
|
+
- **Logging improvements** — `AstParser: analyzeProject done` debug log reports total files, parsed count, and elapsed ms; per-file `depsMs` renamed to `astMs` (now ~0 since AST work is done upfront)
|
|
58
|
+
|
|
6
59
|
## [0.0.15-alpha] - 2026-05-02
|
|
7
60
|
|
|
8
61
|
### Changed
|
package/README.md
CHANGED
|
@@ -6,13 +6,15 @@ Ask Claude things like *"where is the payment retry logic?"* or *"show me how au
|
|
|
6
6
|
|
|
7
7
|
> **Alpha** — works well locally, API may change before 1.0.
|
|
8
8
|
|
|
9
|
+
See `CHANGELOG.md` for version history.
|
|
10
|
+
|
|
9
11
|
## How it works
|
|
10
12
|
|
|
11
13
|
1. `rag-index` scans your projects, chunks source files, embeds them with [bge-m3](https://huggingface.co/BAAI/bge-m3) via Ollama, and stores vectors in PostgreSQL
|
|
12
14
|
2. `rag-mcp` exposes an MCP server — Claude calls it automatically when you ask about code
|
|
13
15
|
3. Incremental — only changed files are re-indexed on subsequent runs
|
|
14
16
|
|
|
15
|
-
**Stack:** TypeScript ·
|
|
17
|
+
**Stack:** TypeScript · Drizzle ORM · PostgreSQL + pgvector · Ollama (bge-m3) · LangChain text splitters · ts-morph
|
|
16
18
|
|
|
17
19
|
## Requirements
|
|
18
20
|
|
|
@@ -32,24 +34,24 @@ rag-setup
|
|
|
32
34
|
```
|
|
33
35
|
|
|
34
36
|
Walks you through:
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
+
- **Database** — enter connection details; optionally starts Docker containers automatically
|
|
38
|
+
- **Ollama** — configure API URL
|
|
37
39
|
- **Logging** — choose log level and directory (defaults: `error` level, `~/.config/codesearch-mcp/logs/`)
|
|
38
40
|
|
|
39
|
-
Config is saved to `~/.config/codesearch-mcp
|
|
41
|
+
Config is saved to `~/.config/codesearch-mcp/config.json`.
|
|
40
42
|
|
|
41
43
|
## Index your projects
|
|
42
44
|
|
|
43
45
|
```bash
|
|
44
|
-
rag-index
|
|
46
|
+
rag-index
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
On first run
|
|
49
|
+
`workspaceRoot` (set by `rag-setup` or `rag-config set workspaceRoot /path`) determines which directory is scanned. On first run — or when no projects are selected — the selector launches automatically. Selections are saved in `.ragprojects` / `.ragskip` at the workspace root.
|
|
48
50
|
|
|
49
51
|
```bash
|
|
50
|
-
rag-index
|
|
51
|
-
rag-index
|
|
52
|
-
rag-index
|
|
52
|
+
rag-index --select # re-run project selection
|
|
53
|
+
rag-index --reindex # force re-embed all files (use after model change)
|
|
54
|
+
rag-index --select --reindex
|
|
53
55
|
```
|
|
54
56
|
|
|
55
57
|
## Register with Claude Code
|
|
@@ -64,14 +66,15 @@ Then ask Claude anything about your code — it will use the tools below automat
|
|
|
64
66
|
|
|
65
67
|
| Tool | Description |
|
|
66
68
|
|------|-------------|
|
|
67
|
-
| `search_codebase` | Semantic search across all indexed projects |
|
|
69
|
+
| `search_codebase` | Semantic search across all indexed projects. Accepts `include_graph_context` to append direct imports/dependents to each result, and `include_neighbors` for surrounding chunks |
|
|
68
70
|
| `list_projects` | List projects with metadata and chunk counts |
|
|
69
71
|
| `find_symbol` | Find a function, class, or type by exact name — faster than semantic search |
|
|
70
72
|
| `list_files` | Browse the directory tree of a project |
|
|
71
73
|
| `read_file` | Read a complete file by absolute path |
|
|
72
74
|
| `read_file_range` | Read a specific line range from an indexed file |
|
|
73
|
-
| `get_dependencies` | Show what files a given file imports |
|
|
74
|
-
| `get_dependents` | Show which files import a given file |
|
|
75
|
+
| `get_dependencies` | Show what files a given file imports (direct or transitive) |
|
|
76
|
+
| `get_dependents` | Show which files import a given file (direct or transitive) |
|
|
77
|
+
| `get_callers` | Find all call sites of a function or method by exact name |
|
|
75
78
|
|
|
76
79
|
## Project metadata
|
|
77
80
|
|
|
@@ -90,6 +93,39 @@ Add `.ragmeta.json` to a project root to enrich `list_projects` and generate a v
|
|
|
90
93
|
|
|
91
94
|
After each indexing run an interactive `project-graph.html` is written to the workspace root.
|
|
92
95
|
|
|
96
|
+
## Graph context
|
|
97
|
+
|
|
98
|
+
Pass `include_graph_context: true` to `search_codebase` to see direct imports and dependents inline with each result — without extra `get_dependencies` / `get_dependents` calls:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
**File:** src/services/InvoiceService.ts **Line:** 45
|
|
102
|
+
...code...
|
|
103
|
+
**Relevance:** 0.32
|
|
104
|
+
**Imports:** src/repositories/InvoiceRepo.ts · src/dto/CreateInvoiceDto.ts
|
|
105
|
+
**Used by:** src/controllers/InvoiceController.ts
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Useful for immediately understanding a file's role in the dependency graph.
|
|
109
|
+
|
|
110
|
+
## Cross-encoder reranking
|
|
111
|
+
|
|
112
|
+
By default, results are ordered by cosine distance (vector similarity). Enable cross-encoder reranking to reorder candidates by semantic relevance — better for queries where the exact wording differs from how the code is written.
|
|
113
|
+
|
|
114
|
+
Requires Ollama ≥ 0.6 and a reranker model:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
ollama pull qllama/bge-reranker-v2-m3
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
rag-config set reranker.enabled true
|
|
122
|
+
rag-config set reranker.model qllama/bge-reranker-v2-m3
|
|
123
|
+
# rag-config set reranker.url http://localhost:11434/api/rerank # default
|
|
124
|
+
# rag-config set reranker.overfetch 3 # fetch limit×3 candidates before reranking
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
When enabled, `search_codebase` fetches `limit × reranker.overfetch` vector candidates, then the cross-encoder reranks them and returns the top `limit`. Falls back gracefully to vector order if the reranker is unreachable.
|
|
128
|
+
|
|
93
129
|
## Excluding files
|
|
94
130
|
|
|
95
131
|
Create `.ragignore` in a project root — same syntax as `.gitignore`:
|
|
@@ -110,31 +146,36 @@ tail -f ~/.config/codesearch-mcp/logs/indexer/current.log
|
|
|
110
146
|
npx pino-pretty < ~/.config/codesearch-mcp/logs/indexer/current.log
|
|
111
147
|
|
|
112
148
|
# Detailed indexing diagnostics (timing per file: deps / embed / db)
|
|
113
|
-
|
|
149
|
+
rag-config set logging.level debug
|
|
114
150
|
|
|
115
151
|
# Disable file logging
|
|
116
|
-
|
|
152
|
+
rag-config set logging.dir false
|
|
117
153
|
```
|
|
118
154
|
|
|
119
|
-
##
|
|
120
|
-
|
|
121
|
-
All set by `rag-setup`. Override
|
|
122
|
-
|
|
123
|
-
|
|
|
124
|
-
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
155
|
+
## Configuration
|
|
156
|
+
|
|
157
|
+
All set by `rag-setup`. Override individual keys with `rag-config set <key> <value>`. Stored in `~/.config/codesearch-mcp/config.json`.
|
|
158
|
+
|
|
159
|
+
| Key | Default | Description |
|
|
160
|
+
|-----|---------|-------------|
|
|
161
|
+
| `db.host` | — | PostgreSQL host |
|
|
162
|
+
| `db.port` | `5433` | PostgreSQL port |
|
|
163
|
+
| `db.user` | — | PostgreSQL user |
|
|
164
|
+
| `db.password` | — | PostgreSQL password |
|
|
165
|
+
| `db.name` | `rag_<os-username>` | Database name — auto-created on first run |
|
|
166
|
+
| `workspaceRoot` | — | Root of your projects directory |
|
|
167
|
+
| `ollama.host` | `http://localhost:11434` | Ollama API URL |
|
|
168
|
+
| `ollama.model` | `bge-m3` | Embedding model |
|
|
169
|
+
| `search.similarityThreshold` | `0.6` | Max cosine distance — raise if search returns nothing |
|
|
170
|
+
| `search.autoTranslate` | `false` | Translate non-English queries to English before embedding |
|
|
171
|
+
| `search.translateModel` | `llama3.2` | Ollama model for translation (requires `ollama pull llama3.2`) |
|
|
172
|
+
| `indexing.astBatchSize` | `3000` | Max files per ts-morph batch — lower if indexing large projects causes OOM |
|
|
173
|
+
| `reranker.enabled` | `false` | Enable cross-encoder reranking (requires Ollama ≥ 0.6 and `reranker.model`) |
|
|
174
|
+
| `reranker.model` | — | Reranker model name (e.g. `qllama/bge-reranker-v2-m3`) |
|
|
175
|
+
| `reranker.url` | `${ollama.host}/api/rerank` | Override rerank endpoint URL |
|
|
176
|
+
| `reranker.overfetch` | `3` | Candidate multiplier before reranking (`limit × N`, max 20) |
|
|
177
|
+
| `logging.level` | `error` | Log level written to file: `error` \| `warn` \| `info` \| `debug` |
|
|
178
|
+
| `logging.dir` | `~/.config/codesearch-mcp/logs` | Base log directory, or `"false"` to disable |
|
|
138
179
|
|
|
139
180
|
## License
|
|
140
181
|
|
package/dist/app.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
package/dist/app.js
CHANGED
|
@@ -34,38 +34,89 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
};
|
|
35
35
|
})();
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
require("./src/env-loader");
|
|
38
37
|
const path = __importStar(require("path"));
|
|
39
|
-
const container_1 = require("./src/container");
|
|
40
38
|
const help_1 = require("./src/help");
|
|
39
|
+
const container_1 = require("./src/container");
|
|
40
|
+
const config_1 = require("./src/config");
|
|
41
41
|
const IndexCommand_1 = require("./src/commands/IndexCommand");
|
|
42
42
|
const McpCommand_1 = require("./src/commands/McpCommand");
|
|
43
|
-
const SetupCommand_1 = require("./src/commands/SetupCommand");
|
|
44
43
|
const BackfillCommand_1 = require("./src/commands/BackfillCommand");
|
|
44
|
+
const ConfigCommand_1 = require("./src/commands/ConfigCommand");
|
|
45
|
+
const setup_1 = require("./src/setup");
|
|
45
46
|
async function main() {
|
|
46
47
|
const argv1 = path.basename(process.argv[1] ?? '');
|
|
47
|
-
const isIndex = argv1 === 'rag-index' || process.argv[2] === 'index';
|
|
48
|
-
const isMcp = argv1 === 'rag-mcp' || process.argv[2] === 'mcp';
|
|
49
|
-
const isSetup = argv1 === 'rag-setup' || process.argv[2] === 'setup';
|
|
50
|
-
const
|
|
51
|
-
const
|
|
48
|
+
const isIndex = argv1 === 'rag-index' || process.argv[2] === 'index' || process.argv[2] === 'rag-index';
|
|
49
|
+
const isMcp = argv1 === 'rag-mcp' || process.argv[2] === 'mcp' || process.argv[2] === 'rag-mcp';
|
|
50
|
+
const isSetup = argv1 === 'rag-setup' || process.argv[2] === 'setup' || process.argv[2] === 'rag-setup';
|
|
51
|
+
const isConfig = argv1 === 'rag-config' || process.argv[2] === 'config' || process.argv[2] === 'rag-config';
|
|
52
|
+
const isBackfill = process.argv[2] === 'backfill' ||
|
|
53
|
+
(process.argv[2] === 'rag-index' && process.argv[3] === 'backfill');
|
|
54
|
+
const mode = isBackfill ? 'backfill' : isIndex ? 'index' : isMcp ? 'mcp' : isSetup ? 'setup' : isConfig ? 'config' : (process.argv[2] ?? '');
|
|
55
|
+
const isBinary = ['rag-index', 'rag-mcp', 'rag-setup', 'rag-config'].includes(argv1);
|
|
52
56
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
53
|
-
(0, help_1.printHelp)(
|
|
57
|
+
(0, help_1.printHelp)(isBinary ? argv1 : mode);
|
|
54
58
|
process.exit(0);
|
|
55
59
|
}
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
if (
|
|
60
|
+
const effectiveArgs = process.argv.slice(isBinary ? 2 : 3);
|
|
61
|
+
// Arg validation
|
|
62
|
+
if (mode === 'index') {
|
|
63
|
+
const knownFlags = new Set(['--reindex', '--select']);
|
|
64
|
+
const unknown = effectiveArgs.filter(a => !a.startsWith('-') || !knownFlags.has(a));
|
|
65
|
+
if (unknown.length > 0) {
|
|
66
|
+
console.error(`Unexpected argument: ${unknown[0]}\n`);
|
|
67
|
+
(0, help_1.printHelp)(isBinary ? argv1 : 'rag-index');
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (mode === 'mcp' || mode === 'setup') {
|
|
72
|
+
if (effectiveArgs.length > 0) {
|
|
73
|
+
console.error(`Unexpected argument: ${effectiveArgs[0]}\n`);
|
|
74
|
+
(0, help_1.printHelp)(isBinary ? argv1 : `rag-${mode}`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (mode === 'backfill') {
|
|
79
|
+
const knownBackfillFlags = new Set(['--calls']);
|
|
80
|
+
const backfillIdx = process.argv.indexOf('backfill');
|
|
81
|
+
const backfillArgs = backfillIdx >= 0 ? process.argv.slice(backfillIdx + 1) : [];
|
|
82
|
+
const unknown = backfillArgs.filter(a => !knownBackfillFlags.has(a));
|
|
83
|
+
if (unknown.length > 0) {
|
|
84
|
+
console.error(`Unexpected argument: ${unknown[0]}\n`);
|
|
85
|
+
(0, help_1.printHelp)('rag-index');
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (mode === 'setup') {
|
|
90
|
+
await (0, setup_1.runSetup)();
|
|
91
|
+
process.exit(0);
|
|
92
|
+
}
|
|
93
|
+
if (mode === 'config') {
|
|
94
|
+
await new ConfigCommand_1.ConfigCommand(effectiveArgs).execute();
|
|
95
|
+
process.exit(0);
|
|
96
|
+
}
|
|
97
|
+
// All other modes require a valid config.json
|
|
98
|
+
const loggerName = mode === 'index' || mode === 'backfill' ? 'indexer' : mode === 'mcp' ? 'mcp' : undefined;
|
|
99
|
+
let container;
|
|
100
|
+
try {
|
|
101
|
+
container = (0, container_1.createContainer)(loggerName);
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
if (e instanceof config_1.ConfigError) {
|
|
105
|
+
console.error(e.message);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
throw e;
|
|
109
|
+
}
|
|
110
|
+
if (!container.config.workspaceRoot) {
|
|
59
111
|
const hint = argv1 === 'rag-mcp'
|
|
60
|
-
? '
|
|
61
|
-
: 'Run
|
|
62
|
-
console.error(`
|
|
112
|
+
? 'Run rag-setup or: rag-config set workspaceRoot /path/to/projects'
|
|
113
|
+
: 'Run rag-setup to configure workspaceRoot.';
|
|
114
|
+
console.error(`workspaceRoot is not configured. ${hint}`);
|
|
63
115
|
process.exit(1);
|
|
64
116
|
}
|
|
65
117
|
const commands = {
|
|
66
118
|
index: new IndexCommand_1.IndexCommand(container, argv1),
|
|
67
119
|
mcp: new McpCommand_1.McpCommand(container),
|
|
68
|
-
setup: new SetupCommand_1.SetupCommand(container),
|
|
69
120
|
backfill: new BackfillCommand_1.BackfillCommand(container),
|
|
70
121
|
};
|
|
71
122
|
const cmd = commands[mode];
|
|
@@ -10,14 +10,24 @@ class BackfillCommand {
|
|
|
10
10
|
async execute() {
|
|
11
11
|
const { db, indexer } = this.container;
|
|
12
12
|
await db.initDbWithSchema();
|
|
13
|
+
const doCalls = process.argv.includes('--calls');
|
|
13
14
|
const controller = new AbortController();
|
|
14
15
|
const teardown = (0, interrupt_1.setupInterrupt)(controller);
|
|
15
16
|
try {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
if (doCalls) {
|
|
18
|
+
console.log('Backfilling call graph...\n');
|
|
19
|
+
const stats = await indexer.backfillCalls(controller.signal);
|
|
20
|
+
if (controller.signal.aborted)
|
|
21
|
+
console.log('\nBackfill interrupted.');
|
|
22
|
+
console.log(`\nDone. Total: ${stats.total}, Processed: ${stats.processed}, Skipped (not on disk): ${stats.skipped}, Failed: ${stats.failed}`);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log('Backfilling symbol index...\n');
|
|
26
|
+
const stats = await indexer.backfillSymbols(controller.signal);
|
|
27
|
+
if (controller.signal.aborted)
|
|
28
|
+
console.log('\nBackfill interrupted.');
|
|
29
|
+
console.log(`\nDone. Total: ${stats.total}, Processed: ${stats.processed}, Skipped (not on disk): ${stats.skipped}, Failed: ${stats.failed}`);
|
|
30
|
+
}
|
|
21
31
|
}
|
|
22
32
|
finally {
|
|
23
33
|
teardown();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ALL_KEYS } from '../config-store';
|
|
2
|
+
import type { ICommand } from './ICommand';
|
|
3
|
+
export declare class ConfigCommand implements ICommand {
|
|
4
|
+
private readonly args;
|
|
5
|
+
constructor(args: string[]);
|
|
6
|
+
execute(): Promise<void>;
|
|
7
|
+
private show;
|
|
8
|
+
private get;
|
|
9
|
+
private set;
|
|
10
|
+
private reset;
|
|
11
|
+
}
|
|
12
|
+
export { ALL_KEYS };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ALL_KEYS = exports.ConfigCommand = void 0;
|
|
4
|
+
const config_store_1 = require("../config-store");
|
|
5
|
+
Object.defineProperty(exports, "ALL_KEYS", { enumerable: true, get: function () { return config_store_1.ALL_KEYS; } });
|
|
6
|
+
const help_1 = require("../help");
|
|
7
|
+
class ConfigCommand {
|
|
8
|
+
args;
|
|
9
|
+
constructor(args) {
|
|
10
|
+
this.args = args;
|
|
11
|
+
}
|
|
12
|
+
async execute() {
|
|
13
|
+
const [sub, key, value] = this.args;
|
|
14
|
+
switch (sub) {
|
|
15
|
+
case 'show': return this.show();
|
|
16
|
+
case 'get': return this.get(key);
|
|
17
|
+
case 'set': return this.set(key, value);
|
|
18
|
+
case 'reset': return this.reset(key);
|
|
19
|
+
default:
|
|
20
|
+
if (sub)
|
|
21
|
+
console.error(`Unknown subcommand: ${sub}\n`);
|
|
22
|
+
(0, help_1.printHelp)('rag-config');
|
|
23
|
+
process.exit(sub ? 1 : 0);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
show() {
|
|
27
|
+
let cfg = null;
|
|
28
|
+
try {
|
|
29
|
+
cfg = (0, config_store_1.readConfigJson)();
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
console.error(e.message);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
if (!cfg) {
|
|
36
|
+
console.log(`No config found at ${config_store_1.CONFIG_FILE}. Run rag-setup.`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// redact password for display
|
|
40
|
+
const display = JSON.parse(JSON.stringify(cfg));
|
|
41
|
+
if (display.db?.password !== undefined)
|
|
42
|
+
display.db.password = '***';
|
|
43
|
+
console.log(JSON.stringify(display, null, 2));
|
|
44
|
+
}
|
|
45
|
+
get(key) {
|
|
46
|
+
if (!key) {
|
|
47
|
+
console.error('Usage: rag-config get <key>');
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
let cfg = null;
|
|
51
|
+
try {
|
|
52
|
+
cfg = (0, config_store_1.readConfigJson)();
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
console.error(e.message);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
if (!cfg) {
|
|
59
|
+
console.log('(no config)');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const val = (0, config_store_1.getNestedValue)(cfg, key);
|
|
63
|
+
console.log(val === undefined ? '(not set)' : String(val));
|
|
64
|
+
}
|
|
65
|
+
set(key, value) {
|
|
66
|
+
if (!key || value === undefined) {
|
|
67
|
+
console.error('Usage: rag-config set <key> <value>');
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const cfg = (0, config_store_1.readConfigJson)() ?? {};
|
|
72
|
+
const updated = (0, config_store_1.setNestedValue)(cfg, key, value);
|
|
73
|
+
(0, config_store_1.writeConfigJson)(updated);
|
|
74
|
+
console.log(`${key} = ${value}`);
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
console.error(e.message);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
reset(key) {
|
|
82
|
+
if (!key) {
|
|
83
|
+
console.error('Usage: rag-config reset <key>');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const cfg = (0, config_store_1.readConfigJson)() ?? {};
|
|
88
|
+
const updated = (0, config_store_1.deleteNestedValue)(cfg, key);
|
|
89
|
+
(0, config_store_1.writeConfigJson)(updated);
|
|
90
|
+
console.log(`${key} reset to default`);
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
console.error(e.message);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.ConfigCommand = ConfigCommand;
|
|
@@ -22,7 +22,7 @@ class IndexCommand {
|
|
|
22
22
|
const teardown = (0, interrupt_1.setupInterrupt)(controller);
|
|
23
23
|
try {
|
|
24
24
|
const discovered = indexer.discoverProjects(config.workspaceRoot);
|
|
25
|
-
const projects = await
|
|
25
|
+
const projects = await new project_selector_1.ProjectSelector(config.workspaceRoot).select(discovered, forceSelect);
|
|
26
26
|
if (projects.length === 0)
|
|
27
27
|
return;
|
|
28
28
|
const filesPerProject = projects.map(p => (0, file_utils_1.collectFiles)(p.path, (0, file_utils_1.loadIgnore)(p.path), p.path));
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const CONFIG_DIR: string;
|
|
3
|
+
export declare const CONFIG_FILE: string;
|
|
4
|
+
declare const jsonSchema: z.ZodObject<{
|
|
5
|
+
db: z.ZodOptional<z.ZodObject<{
|
|
6
|
+
host: z.ZodOptional<z.ZodString>;
|
|
7
|
+
port: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
user: z.ZodOptional<z.ZodString>;
|
|
9
|
+
password: z.ZodOptional<z.ZodString>;
|
|
10
|
+
name: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, z.core.$strip>>;
|
|
12
|
+
ollama: z.ZodOptional<z.ZodObject<{
|
|
13
|
+
host: z.ZodOptional<z.ZodString>;
|
|
14
|
+
model: z.ZodOptional<z.ZodString>;
|
|
15
|
+
}, z.core.$strip>>;
|
|
16
|
+
indexing: z.ZodOptional<z.ZodObject<{
|
|
17
|
+
chunkSize: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
chunkOverlap: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
embedBatchSize: z.ZodOptional<z.ZodNumber>;
|
|
20
|
+
astBatchSize: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
}, z.core.$strip>>;
|
|
22
|
+
search: z.ZodOptional<z.ZodObject<{
|
|
23
|
+
similarityThreshold: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
defaultLimit: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
maxLimit: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
autoTranslate: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
+
translateModel: z.ZodOptional<z.ZodString>;
|
|
28
|
+
}, z.core.$strip>>;
|
|
29
|
+
reranker: z.ZodOptional<z.ZodObject<{
|
|
30
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
31
|
+
model: z.ZodOptional<z.ZodString>;
|
|
32
|
+
url: z.ZodOptional<z.ZodString>;
|
|
33
|
+
overfetch: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
}, z.core.$strip>>;
|
|
35
|
+
logging: z.ZodOptional<z.ZodObject<{
|
|
36
|
+
level: z.ZodOptional<z.ZodEnum<{
|
|
37
|
+
error: "error";
|
|
38
|
+
debug: "debug";
|
|
39
|
+
info: "info";
|
|
40
|
+
warn: "warn";
|
|
41
|
+
}>>;
|
|
42
|
+
dir: z.ZodOptional<z.ZodString>;
|
|
43
|
+
}, z.core.$strip>>;
|
|
44
|
+
workspaceRoot: z.ZodOptional<z.ZodString>;
|
|
45
|
+
}, z.core.$strip>;
|
|
46
|
+
export type JsonConfig = z.infer<typeof jsonSchema>;
|
|
47
|
+
export declare const ALL_KEYS: string[];
|
|
48
|
+
export declare function readConfigJson(): JsonConfig | null;
|
|
49
|
+
export declare function writeConfigJson(data: JsonConfig): void;
|
|
50
|
+
export declare function getNestedValue(cfg: JsonConfig, key: string): unknown;
|
|
51
|
+
export declare function setNestedValue(cfg: JsonConfig, key: string, raw: string): JsonConfig;
|
|
52
|
+
export declare function deleteNestedValue(cfg: JsonConfig, key: string): JsonConfig;
|
|
53
|
+
export {};
|