codesearch-mcp 0.0.9-alpha → 0.0.11-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/README.md +26 -14
- package/dist/app.js +24 -143
- package/dist/src/commands/BackfillCommand.d.ts +7 -0
- package/dist/src/commands/BackfillCommand.js +27 -0
- package/dist/src/commands/ICommand.d.ts +3 -0
- package/dist/src/commands/ICommand.js +2 -0
- package/dist/src/commands/IndexCommand.d.ts +9 -0
- package/dist/src/commands/IndexCommand.js +75 -0
- package/dist/src/commands/McpCommand.d.ts +7 -0
- package/dist/src/commands/McpCommand.js +21 -0
- package/dist/src/commands/SetupCommand.d.ts +4 -0
- package/dist/src/commands/SetupCommand.js +10 -0
- package/dist/src/config.d.ts +1 -0
- package/dist/src/config.js +41 -2
- package/dist/src/container.d.ts +15 -0
- package/dist/src/container.js +21 -0
- package/dist/src/db/entities/code-chunk.entity.d.ts +1 -1
- package/dist/src/db/entities/code-chunk.entity.js +2 -2
- package/dist/src/db/entities/code-symbol.entity.d.ts +10 -0
- package/dist/src/db/entities/code-symbol.entity.js +59 -0
- package/dist/src/db/index.d.ts +1 -2
- package/dist/src/db/index.js +3 -6
- package/dist/src/file-utils.d.ts +2 -1
- package/dist/src/file-utils.js +10 -5
- package/dist/src/graph.js +5 -4
- package/dist/src/help.js +1 -1
- package/dist/src/interfaces/IAstParser.d.ts +24 -0
- package/dist/src/interfaces/IAstParser.js +2 -0
- package/dist/src/interfaces/IEmbedder.d.ts +4 -0
- package/dist/src/interfaces/IEmbedder.js +2 -0
- package/dist/src/interrupt.d.ts +1 -3
- package/dist/src/interrupt.js +14 -16
- package/dist/src/services/AstParserService.d.ts +14 -0
- package/dist/src/services/AstParserService.js +256 -0
- package/dist/src/services/DatabaseService.d.ts +14 -0
- package/dist/src/services/DatabaseService.js +133 -0
- package/dist/src/services/IndexerService.d.ts +39 -0
- package/dist/src/services/IndexerService.js +286 -0
- package/dist/src/services/LoggerService.d.ts +12 -0
- package/dist/src/services/LoggerService.js +73 -0
- package/dist/src/services/McpServer.d.ts +13 -0
- package/dist/src/services/McpServer.js +411 -0
- package/dist/src/services/OllamaEmbedder.d.ts +9 -0
- package/dist/src/services/OllamaEmbedder.js +27 -0
- package/dist/src/services/SearcherService.d.ts +91 -0
- package/dist/src/services/SearcherService.js +453 -0
- package/dist/src/setup.js +23 -7
- package/package.json +11 -10
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ rag-setup
|
|
|
34
34
|
Walks you through:
|
|
35
35
|
- **Local Docker** — copies `docker-compose.yml`, starts PostgreSQL + Ollama, pulls `bge-m3` automatically
|
|
36
36
|
- **Remote DB** — enter connection details for Supabase, Railway, or self-hosted; connection is verified before saving
|
|
37
|
+
- **Logging** — choose log level and file path (defaults: `error` level, `~/.config/codesearch-mcp/rag.log`)
|
|
37
38
|
|
|
38
39
|
Config is saved to `~/.config/codesearch-mcp/.env`.
|
|
39
40
|
|
|
@@ -43,18 +44,7 @@ Config is saved to `~/.config/codesearch-mcp/.env`.
|
|
|
43
44
|
rag-index /home/user/Projects
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
On first run you will be prompted
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
Found 5 new project(s). Select which to index:
|
|
50
|
-
y = yes | n = skip this time | s = always skip
|
|
51
|
-
|
|
52
|
-
myapp [y/n/s]: y
|
|
53
|
-
legacy-app [y/n/s]: s
|
|
54
|
-
→ added to .ragskip
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Selections are saved in `.ragprojects` / `.ragskip` at the workspace root. Use `--select` to revisit them.
|
|
47
|
+
On first run you will be prompted to select which projects to index. Selections are saved in `.ragprojects` / `.ragskip` at the workspace root.
|
|
58
48
|
|
|
59
49
|
```bash
|
|
60
50
|
rag-index /path --select # re-run project selection
|
|
@@ -68,7 +58,7 @@ rag-index /path --select --reindex
|
|
|
68
58
|
claude mcp add codesearch-mcp -s user -- rag-mcp
|
|
69
59
|
```
|
|
70
60
|
|
|
71
|
-
Then ask Claude anything about your code — it will use
|
|
61
|
+
Then ask Claude anything about your code — it will use the tools below automatically.
|
|
72
62
|
|
|
73
63
|
## MCP Tools
|
|
74
64
|
|
|
@@ -76,6 +66,9 @@ Then ask Claude anything about your code — it will use `search_codebase`, `lis
|
|
|
76
66
|
|------|-------------|
|
|
77
67
|
| `search_codebase` | Semantic search across all indexed projects |
|
|
78
68
|
| `list_projects` | List projects with metadata and chunk counts |
|
|
69
|
+
| `find_symbol` | Find a function, class, or type by exact name — faster than semantic search |
|
|
70
|
+
| `list_files` | Browse the directory tree of a project |
|
|
71
|
+
| `read_file` | Read a complete file by absolute path |
|
|
79
72
|
| `read_file_range` | Read a specific line range from an indexed file |
|
|
80
73
|
| `get_dependencies` | Show what files a given file imports |
|
|
81
74
|
| `get_dependents` | Show which files import a given file |
|
|
@@ -107,6 +100,22 @@ src/gql/graphql.ts
|
|
|
107
100
|
src/generated/
|
|
108
101
|
```
|
|
109
102
|
|
|
103
|
+
## Logging
|
|
104
|
+
|
|
105
|
+
Logs are written to `~/.config/codesearch-mcp/rag.log` by default. Only errors are logged unless configured otherwise.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Read logs
|
|
109
|
+
tail -f ~/.config/codesearch-mcp/rag.log
|
|
110
|
+
npx pino-pretty < ~/.config/codesearch-mcp/rag.log
|
|
111
|
+
|
|
112
|
+
# Detailed indexing diagnostics (timing per file: deps / embed / db)
|
|
113
|
+
LOG_LEVEL=debug rag-index /path/to/workspace
|
|
114
|
+
|
|
115
|
+
# Disable file logging
|
|
116
|
+
LOG_FILE=false rag-index /path/to/workspace
|
|
117
|
+
```
|
|
118
|
+
|
|
110
119
|
## Environment variables
|
|
111
120
|
|
|
112
121
|
All set by `rag-setup`. Override any of them in `~/.config/codesearch-mcp/.env`.
|
|
@@ -117,12 +126,15 @@ All set by `rag-setup`. Override any of them in `~/.config/codesearch-mcp/.env`.
|
|
|
117
126
|
| `DB_PORT` | `5433` | PostgreSQL port |
|
|
118
127
|
| `DB_USER` | — | PostgreSQL user |
|
|
119
128
|
| `DB_PASS` | — | PostgreSQL password |
|
|
120
|
-
| `DB_NAME` |
|
|
129
|
+
| `DB_NAME` | `rag_<os-username>` | Database name — auto-created on first run |
|
|
121
130
|
| `WORKSPACE_ROOT` | — | Root of your projects directory |
|
|
122
131
|
| `OLLAMA_HOST` | `http://localhost:11434` | Ollama API URL |
|
|
123
132
|
| `OLLAMA_MODEL` | `bge-m3` | Embedding model |
|
|
124
133
|
| `SIMILARITY_THRESHOLD` | `0.6` | Max cosine distance — raise if search returns nothing |
|
|
125
134
|
| `AUTO_TRANSLATE` | `false` | Translate non-English queries to English before embedding |
|
|
135
|
+
| `TRANSLATE_MODEL` | `llama3.2` | Ollama model for translation (requires `ollama pull llama3.2`) |
|
|
136
|
+
| `LOG_LEVEL` | `error` | Log level written to file: `error` \| `warn` \| `info` \| `debug` |
|
|
137
|
+
| `LOG_FILE` | `~/.config/codesearch-mcp/rag.log` | Log file path, or `false` to disable |
|
|
126
138
|
|
|
127
139
|
## License
|
|
128
140
|
|
package/dist/app.js
CHANGED
|
@@ -36,43 +36,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
37
|
require("./src/env-loader");
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
+
const container_1 = require("./src/container");
|
|
39
40
|
const help_1 = require("./src/help");
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const s = sec % 60;
|
|
45
|
-
return s > 0 ? `${m}m ${s}s` : `${m}m`;
|
|
46
|
-
}
|
|
47
|
-
function printSummary(allStats) {
|
|
48
|
-
const cols = { name: 30, num: 8 };
|
|
49
|
-
const line = '─'.repeat(cols.name + cols.num * 5 + 5);
|
|
50
|
-
console.log('\n=== Indexing Summary ===');
|
|
51
|
-
console.log('Service'.padEnd(cols.name), 'Indexed'.padStart(cols.num), 'Skipped'.padStart(cols.num), 'Failed'.padStart(cols.num), 'Chunks'.padStart(cols.num), 'Time(s)'.padStart(cols.num));
|
|
52
|
-
console.log(line);
|
|
53
|
-
for (const s of allStats) {
|
|
54
|
-
console.log(s.serviceName.padEnd(cols.name), String(s.indexed).padStart(cols.num), String(s.skipped).padStart(cols.num), String(s.failed).padStart(cols.num), String(s.chunks).padStart(cols.num), String(s.elapsedSec).padStart(cols.num));
|
|
55
|
-
}
|
|
56
|
-
console.log(line);
|
|
57
|
-
const total = allStats.reduce((acc, s) => ({
|
|
58
|
-
indexed: acc.indexed + s.indexed,
|
|
59
|
-
skipped: acc.skipped + s.skipped,
|
|
60
|
-
failed: acc.failed + s.failed,
|
|
61
|
-
chunks: acc.chunks + s.chunks,
|
|
62
|
-
elapsedSec: acc.elapsedSec + s.elapsedSec,
|
|
63
|
-
}), { indexed: 0, skipped: 0, failed: 0, chunks: 0, elapsedSec: 0 });
|
|
64
|
-
console.log('TOTAL'.padEnd(cols.name), String(total.indexed).padStart(cols.num), String(total.skipped).padStart(cols.num), String(total.failed).padStart(cols.num), String(total.chunks).padStart(cols.num), String(total.elapsedSec.toFixed(1)).padStart(cols.num));
|
|
65
|
-
// Reprint warnings at the end — progress bar activity scrolls per-project warnings out of
|
|
66
|
-
// view, so we collect them on IndexStats and surface them here as an explicit section.
|
|
67
|
-
// const projectsWithWarnings = allStats.filter(s => s.warnings.length > 0);
|
|
68
|
-
// if (projectsWithWarnings.length > 0) {
|
|
69
|
-
// console.log('\n=== Warnings ===');
|
|
70
|
-
// for (const s of projectsWithWarnings) {
|
|
71
|
-
// console.log(`\n${s.serviceName}:`);
|
|
72
|
-
// for (const w of s.warnings) console.log(` ⚠ ${w}`);
|
|
73
|
-
// }
|
|
74
|
-
// }
|
|
75
|
-
}
|
|
41
|
+
const IndexCommand_1 = require("./src/commands/IndexCommand");
|
|
42
|
+
const McpCommand_1 = require("./src/commands/McpCommand");
|
|
43
|
+
const SetupCommand_1 = require("./src/commands/SetupCommand");
|
|
44
|
+
const BackfillCommand_1 = require("./src/commands/BackfillCommand");
|
|
76
45
|
async function main() {
|
|
77
46
|
const argv1 = path.basename(process.argv[1] ?? '');
|
|
78
47
|
const isIndex = argv1 === 'rag-index' || process.argv[2] === 'index';
|
|
@@ -84,118 +53,30 @@ async function main() {
|
|
|
84
53
|
(0, help_1.printHelp)(argv1 !== 'app.js' ? argv1 : mode);
|
|
85
54
|
process.exit(0);
|
|
86
55
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const argPath = args.find(a => !a.startsWith('--'));
|
|
95
|
-
const force = args.includes('--reindex');
|
|
96
|
-
const forceSelect = args.includes('--select');
|
|
97
|
-
// Prefer explicit arg, then WORKSPACE_ROOT from config
|
|
98
|
-
const workspacePath = argPath ?? process.env.WORKSPACE_ROOT;
|
|
99
|
-
if (!workspacePath) {
|
|
100
|
-
console.error('Usage: rag-index [path] [--reindex] [--select]');
|
|
101
|
-
console.error(' path defaults to WORKSPACE_ROOT set during rag-setup');
|
|
102
|
-
process.exit(1);
|
|
103
|
-
}
|
|
104
|
-
process.env.WORKSPACE_ROOT ??= workspacePath;
|
|
105
|
-
await initDbWithSchema();
|
|
106
|
-
setupInterrupt();
|
|
107
|
-
try {
|
|
108
|
-
const { collectFiles, loadIgnore } = await Promise.resolve().then(() => __importStar(require('./src/file-utils')));
|
|
109
|
-
const discovered = discoverProjects(workspacePath);
|
|
110
|
-
const projects = await selectProjects(discovered, workspacePath, forceSelect);
|
|
111
|
-
if (projects.length === 0)
|
|
112
|
-
process.exit(0);
|
|
113
|
-
const filesPerProject = projects.map(p => collectFiles(p.path, loadIgnore(p.path), p.path));
|
|
114
|
-
const totalFiles = filesPerProject.reduce((sum, f) => sum + f.length, 0);
|
|
115
|
-
console.log(`\n${projects.length} projects — ${totalFiles} files total`);
|
|
116
|
-
if (force)
|
|
117
|
-
console.log('Reindex mode: all files will be re-indexed.');
|
|
118
|
-
const allStats = [];
|
|
119
|
-
for (let i = 0; i < projects.length; i++) {
|
|
120
|
-
if (signal.aborted)
|
|
121
|
-
break;
|
|
122
|
-
const stats = await scanAndIndex(projects[i].path, projects[i].name, force, signal, filesPerProject[i]);
|
|
123
|
-
allStats.push(stats);
|
|
124
|
-
const remaining = projects.length - allStats.length;
|
|
125
|
-
if (remaining > 0 && !signal.aborted) {
|
|
126
|
-
const doneFiles = allStats.reduce((s, r) => s + r.indexed + r.skipped + r.failed, 0);
|
|
127
|
-
const elapsedSec = allStats.reduce((s, r) => s + r.elapsedSec, 0);
|
|
128
|
-
const leftFiles = filesPerProject.slice(allStats.length).reduce((sum, f) => sum + f.length, 0);
|
|
129
|
-
const eta = doneFiles > 0 ? formatEta(Math.round(elapsedSec / doneFiles * leftFiles)) : '?';
|
|
130
|
-
console.log(` ${allStats.length}/${projects.length} projects done — ${remaining} left (~${leftFiles} files) — ETA ~${eta}`);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
if (signal.aborted)
|
|
134
|
-
console.log('\nIndexing interrupted.');
|
|
135
|
-
printSummary(allStats);
|
|
136
|
-
if (!signal.aborted)
|
|
137
|
-
generateProjectGraph(projects, workspacePath);
|
|
138
|
-
}
|
|
139
|
-
finally {
|
|
140
|
-
teardownInterrupt();
|
|
141
|
-
}
|
|
142
|
-
process.exit(0);
|
|
143
|
-
}
|
|
144
|
-
else if (mode === 'mcp') {
|
|
145
|
-
const { initDb } = await Promise.resolve().then(() => __importStar(require('./src/db')));
|
|
146
|
-
const { startMCP } = await Promise.resolve().then(() => __importStar(require('./src/mcp')));
|
|
147
|
-
if (!process.env.WORKSPACE_ROOT) {
|
|
148
|
-
if (argv1 === 'rag-mcp') {
|
|
149
|
-
console.error('WORKSPACE_ROOT is required for MCP mode. Set it in ~/.config/codesearch-mcp/.env');
|
|
150
|
-
console.error('Run `rag-setup` to configure.');
|
|
151
|
-
process.exit(1);
|
|
152
|
-
}
|
|
153
|
-
// dev fallback: infer from cwd (project lives inside workspace)
|
|
154
|
-
process.env.WORKSPACE_ROOT = path.dirname(process.cwd());
|
|
155
|
-
}
|
|
156
|
-
await initDb();
|
|
157
|
-
await startMCP();
|
|
56
|
+
const container = (0, container_1.createContainer)();
|
|
57
|
+
if (!container.config.workspaceRoot && mode !== 'setup') {
|
|
58
|
+
const hint = argv1 === 'rag-mcp'
|
|
59
|
+
? 'Set WORKSPACE_ROOT in ~/.config/codesearch-mcp/.env or run `rag-setup`.'
|
|
60
|
+
: 'Run `rag-setup` to configure WORKSPACE_ROOT.';
|
|
61
|
+
console.error(`WORKSPACE_ROOT is not configured. ${hint}`);
|
|
62
|
+
process.exit(1);
|
|
158
63
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
168
|
-
const path = await Promise.resolve().then(() => __importStar(require('path')));
|
|
169
|
-
await initDbWithSchema();
|
|
170
|
-
const rows = await db.query(`SELECT DISTINCT "serviceName", "filePath" FROM code_chunk ORDER BY "serviceName", "filePath"`);
|
|
171
|
-
console.log(`Backfilling dependency edges for ${rows.length} indexed files...\n`);
|
|
172
|
-
let processed = 0, skipped = 0, totalEdges = 0;
|
|
173
|
-
for (const { serviceName, filePath } of rows) {
|
|
174
|
-
const absPath = path.join(config.workspaceRoot, filePath);
|
|
175
|
-
const projectRoot = path.join(config.workspaceRoot, serviceName);
|
|
176
|
-
if (!fs.existsSync(absPath)) {
|
|
177
|
-
skipped++;
|
|
178
|
-
continue;
|
|
179
|
-
}
|
|
180
|
-
const edges = await collectDepEdges(absPath, serviceName, projectRoot);
|
|
181
|
-
await writeDepEdges(serviceName, filePath, edges);
|
|
182
|
-
totalEdges += edges.length;
|
|
183
|
-
processed++;
|
|
184
|
-
if (processed % 50 === 0)
|
|
185
|
-
process.stdout.write(` ${processed}/${rows.length} processed, ${totalEdges} edges...\r`);
|
|
186
|
-
}
|
|
187
|
-
console.log(`\nDone. Processed: ${processed}, Skipped (not on disk): ${skipped}, Total edges: ${totalEdges}`);
|
|
188
|
-
await db.destroy();
|
|
189
|
-
process.exit(0);
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
// No command → show help and exit cleanly. Unknown command → error + help + exit 1.
|
|
64
|
+
const commands = {
|
|
65
|
+
index: new IndexCommand_1.IndexCommand(container, argv1),
|
|
66
|
+
mcp: new McpCommand_1.McpCommand(container),
|
|
67
|
+
setup: new SetupCommand_1.SetupCommand(),
|
|
68
|
+
backfill: new BackfillCommand_1.BackfillCommand(container),
|
|
69
|
+
};
|
|
70
|
+
const cmd = commands[mode];
|
|
71
|
+
if (!cmd) {
|
|
193
72
|
const hasUnknownArg = mode !== '';
|
|
194
|
-
const out = hasUnknownArg ? console.error : console.log;
|
|
195
73
|
if (hasUnknownArg)
|
|
196
|
-
|
|
74
|
+
console.error(`Unknown command: ${mode}\n`);
|
|
197
75
|
(0, help_1.printHelp)('default');
|
|
198
76
|
process.exit(hasUnknownArg ? 1 : 0);
|
|
199
77
|
}
|
|
78
|
+
await cmd.execute();
|
|
79
|
+
await container.db.destroy();
|
|
80
|
+
process.exit(0);
|
|
200
81
|
}
|
|
201
82
|
main().catch(err => { console.error(err); process.exit(1); });
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BackfillCommand = void 0;
|
|
4
|
+
const interrupt_1 = require("../interrupt");
|
|
5
|
+
class BackfillCommand {
|
|
6
|
+
container;
|
|
7
|
+
constructor(container) {
|
|
8
|
+
this.container = container;
|
|
9
|
+
}
|
|
10
|
+
async execute() {
|
|
11
|
+
const { db, indexer } = this.container;
|
|
12
|
+
await db.initDbWithSchema();
|
|
13
|
+
const controller = new AbortController();
|
|
14
|
+
const teardown = (0, interrupt_1.setupInterrupt)(controller);
|
|
15
|
+
try {
|
|
16
|
+
console.log('Backfilling symbol index...\n');
|
|
17
|
+
const stats = await indexer.backfillSymbols(controller.signal);
|
|
18
|
+
if (controller.signal.aborted)
|
|
19
|
+
console.log('\nBackfill interrupted.');
|
|
20
|
+
console.log(`\nDone. Total: ${stats.total}, Processed: ${stats.processed}, Skipped (not on disk): ${stats.skipped}, Failed: ${stats.failed}`);
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
teardown();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.BackfillCommand = BackfillCommand;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Container } from '../container';
|
|
2
|
+
import type { ICommand } from './ICommand';
|
|
3
|
+
export declare class IndexCommand implements ICommand {
|
|
4
|
+
private container;
|
|
5
|
+
private argv1;
|
|
6
|
+
constructor(container: Container, argv1: string);
|
|
7
|
+
execute(): Promise<void>;
|
|
8
|
+
private printSummary;
|
|
9
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IndexCommand = void 0;
|
|
4
|
+
const interrupt_1 = require("../interrupt");
|
|
5
|
+
const project_selector_1 = require("../project-selector");
|
|
6
|
+
const graph_1 = require("../graph");
|
|
7
|
+
const file_utils_1 = require("../file-utils");
|
|
8
|
+
class IndexCommand {
|
|
9
|
+
container;
|
|
10
|
+
argv1;
|
|
11
|
+
constructor(container, argv1) {
|
|
12
|
+
this.container = container;
|
|
13
|
+
this.argv1 = argv1;
|
|
14
|
+
}
|
|
15
|
+
async execute() {
|
|
16
|
+
const { db, indexer, config } = this.container;
|
|
17
|
+
const args = process.argv.slice(this.argv1 === 'rag-index' ? 2 : 3);
|
|
18
|
+
const force = args.includes('--reindex');
|
|
19
|
+
const forceSelect = args.includes('--select');
|
|
20
|
+
await db.initDbWithSchema();
|
|
21
|
+
const controller = new AbortController();
|
|
22
|
+
const teardown = (0, interrupt_1.setupInterrupt)(controller);
|
|
23
|
+
try {
|
|
24
|
+
const discovered = indexer.discoverProjects(config.workspaceRoot);
|
|
25
|
+
const projects = await (0, project_selector_1.selectProjects)(discovered, config.workspaceRoot, forceSelect);
|
|
26
|
+
if (projects.length === 0)
|
|
27
|
+
return;
|
|
28
|
+
const filesPerProject = projects.map(p => (0, file_utils_1.collectFiles)(p.path, (0, file_utils_1.loadIgnore)(p.path), p.path));
|
|
29
|
+
const totalFiles = filesPerProject.reduce((sum, f) => sum + f.length, 0);
|
|
30
|
+
console.log(`\n${projects.length} projects — ${totalFiles} files total`);
|
|
31
|
+
if (force)
|
|
32
|
+
console.log('Reindex mode: all files will be re-indexed.');
|
|
33
|
+
const allStats = [];
|
|
34
|
+
for (let i = 0; i < projects.length; i++) {
|
|
35
|
+
if (controller.signal.aborted)
|
|
36
|
+
break;
|
|
37
|
+
const stats = await indexer.scanAndIndex(projects[i].path, projects[i].name, force, controller.signal, filesPerProject[i]);
|
|
38
|
+
allStats.push(stats);
|
|
39
|
+
const remaining = projects.length - allStats.length;
|
|
40
|
+
if (remaining > 0 && !controller.signal.aborted) {
|
|
41
|
+
const leftFiles = filesPerProject.slice(allStats.length).reduce((sum, f) => sum + f.length, 0);
|
|
42
|
+
console.log(` ${allStats.length}/${projects.length} projects — done in ${stats.elapsedSec}s — ${leftFiles} files left`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (controller.signal.aborted)
|
|
46
|
+
console.log('\nIndexing interrupted.');
|
|
47
|
+
this.printSummary(allStats);
|
|
48
|
+
if (!controller.signal.aborted)
|
|
49
|
+
(0, graph_1.generateProjectGraph)(projects, config.workspaceRoot);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
teardown();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
printSummary(allStats) {
|
|
56
|
+
const cols = { name: 30, num: 8 };
|
|
57
|
+
const line = '─'.repeat(cols.name + cols.num * 5 + 5);
|
|
58
|
+
console.log('\n=== Indexing Summary ===');
|
|
59
|
+
console.log('Service'.padEnd(cols.name), 'Indexed'.padStart(cols.num), 'Skipped'.padStart(cols.num), 'Failed'.padStart(cols.num), 'Chunks'.padStart(cols.num), 'Time(s)'.padStart(cols.num));
|
|
60
|
+
console.log(line);
|
|
61
|
+
for (const s of allStats) {
|
|
62
|
+
console.log(s.serviceName.padEnd(cols.name), String(s.indexed).padStart(cols.num), String(s.skipped).padStart(cols.num), String(s.failed).padStart(cols.num), String(s.chunks).padStart(cols.num), String(s.elapsedSec).padStart(cols.num));
|
|
63
|
+
}
|
|
64
|
+
console.log(line);
|
|
65
|
+
const total = allStats.reduce((acc, s) => ({
|
|
66
|
+
indexed: acc.indexed + s.indexed,
|
|
67
|
+
skipped: acc.skipped + s.skipped,
|
|
68
|
+
failed: acc.failed + s.failed,
|
|
69
|
+
chunks: acc.chunks + s.chunks,
|
|
70
|
+
elapsedSec: acc.elapsedSec + s.elapsedSec,
|
|
71
|
+
}), { indexed: 0, skipped: 0, failed: 0, chunks: 0, elapsedSec: 0 });
|
|
72
|
+
console.log('TOTAL'.padEnd(cols.name), String(total.indexed).padStart(cols.num), String(total.skipped).padStart(cols.num), String(total.failed).padStart(cols.num), String(total.chunks).padStart(cols.num), String(total.elapsedSec.toFixed(1)).padStart(cols.num));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.IndexCommand = IndexCommand;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.McpCommand = void 0;
|
|
4
|
+
class McpCommand {
|
|
5
|
+
container;
|
|
6
|
+
constructor(container) {
|
|
7
|
+
this.container = container;
|
|
8
|
+
}
|
|
9
|
+
async execute() {
|
|
10
|
+
const { db, mcp } = this.container;
|
|
11
|
+
await db.initDb();
|
|
12
|
+
await mcp.start();
|
|
13
|
+
// server.connect() resolves immediately after setup; keep the process alive
|
|
14
|
+
// until the MCP client disconnects (stdin closes)
|
|
15
|
+
await new Promise(resolve => {
|
|
16
|
+
process.stdin.once('close', resolve);
|
|
17
|
+
process.stdin.once('end', resolve);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.McpCommand = McpCommand;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SetupCommand = void 0;
|
|
4
|
+
const setup_1 = require("../setup");
|
|
5
|
+
class SetupCommand {
|
|
6
|
+
async execute() {
|
|
7
|
+
await (0, setup_1.runSetup)();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.SetupCommand = SetupCommand;
|
package/dist/src/config.d.ts
CHANGED
package/dist/src/config.js
CHANGED
|
@@ -1,15 +1,54 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.config = void 0;
|
|
37
|
+
const os = __importStar(require("os"));
|
|
4
38
|
const zod_1 = require("zod");
|
|
5
39
|
const constants_1 = require("./constants");
|
|
40
|
+
function deriveDbName() {
|
|
41
|
+
const username = os.userInfo().username;
|
|
42
|
+
const sanitized = username.toLowerCase().replace(/[^a-z0-9_]/g, '_');
|
|
43
|
+
return 'rag_' + (sanitized || 'user');
|
|
44
|
+
}
|
|
6
45
|
const schema = zod_1.z.object({
|
|
7
46
|
// required — no defaults, process exits if missing
|
|
8
47
|
DB_HOST: zod_1.z.string(),
|
|
9
48
|
DB_PORT: zod_1.z.coerce.number().default(5433),
|
|
10
49
|
DB_USER: zod_1.z.string(),
|
|
11
50
|
DB_PASS: zod_1.z.string(),
|
|
12
|
-
DB_NAME: zod_1.z.string(),
|
|
51
|
+
DB_NAME: zod_1.z.string().optional(),
|
|
13
52
|
// optional with defaults
|
|
14
53
|
OLLAMA_HOST: zod_1.z.string().url().default('http://localhost:11434'),
|
|
15
54
|
OLLAMA_MODEL: zod_1.z.string().default(constants_1.DEFAULT_EMBED_MODEL),
|
|
@@ -39,7 +78,7 @@ exports.config = {
|
|
|
39
78
|
port: env.DB_PORT,
|
|
40
79
|
username: env.DB_USER,
|
|
41
80
|
password: env.DB_PASS,
|
|
42
|
-
database: env.DB_NAME,
|
|
81
|
+
database: env.DB_NAME ?? deriveDbName(),
|
|
43
82
|
},
|
|
44
83
|
ollama: {
|
|
45
84
|
host: env.OLLAMA_HOST,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Config } from './config';
|
|
2
|
+
import { DatabaseService } from './services/DatabaseService';
|
|
3
|
+
import { IndexerService } from './services/IndexerService';
|
|
4
|
+
import { SearcherService } from './services/SearcherService';
|
|
5
|
+
import { McpServer } from './services/McpServer';
|
|
6
|
+
import { LoggerService } from './services/LoggerService';
|
|
7
|
+
export interface Container {
|
|
8
|
+
config: Config;
|
|
9
|
+
db: DatabaseService;
|
|
10
|
+
indexer: IndexerService;
|
|
11
|
+
searcher: SearcherService;
|
|
12
|
+
mcp: McpServer;
|
|
13
|
+
logger: LoggerService;
|
|
14
|
+
}
|
|
15
|
+
export declare function createContainer(): Container;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createContainer = createContainer;
|
|
4
|
+
const config_1 = require("./config");
|
|
5
|
+
const DatabaseService_1 = require("./services/DatabaseService");
|
|
6
|
+
const OllamaEmbedder_1 = require("./services/OllamaEmbedder");
|
|
7
|
+
const AstParserService_1 = require("./services/AstParserService");
|
|
8
|
+
const IndexerService_1 = require("./services/IndexerService");
|
|
9
|
+
const SearcherService_1 = require("./services/SearcherService");
|
|
10
|
+
const McpServer_1 = require("./services/McpServer");
|
|
11
|
+
const LoggerService_1 = require("./services/LoggerService");
|
|
12
|
+
function createContainer() {
|
|
13
|
+
const logger = LoggerService_1.LoggerService.fromEnv();
|
|
14
|
+
const db = new DatabaseService_1.DatabaseService(config_1.config);
|
|
15
|
+
const embedder = new OllamaEmbedder_1.OllamaEmbedder(config_1.config);
|
|
16
|
+
const ast = new AstParserService_1.AstParserService(logger);
|
|
17
|
+
const indexer = new IndexerService_1.IndexerService(db, embedder, ast, config_1.config, logger);
|
|
18
|
+
const searcher = new SearcherService_1.SearcherService(db, embedder, config_1.config, logger);
|
|
19
|
+
const mcp = new McpServer_1.McpServer(searcher, config_1.config, logger);
|
|
20
|
+
return { config: config_1.config, db, indexer, searcher, mcp, logger };
|
|
21
|
+
}
|
|
@@ -34,8 +34,8 @@ __decorate([
|
|
|
34
34
|
__metadata("design:type", String)
|
|
35
35
|
], CodeChunk.prototype, "filePath", void 0);
|
|
36
36
|
__decorate([
|
|
37
|
-
(0, typeorm_1.Column)({ nullable: true }),
|
|
38
|
-
__metadata("design:type",
|
|
37
|
+
(0, typeorm_1.Column)({ type: 'int', nullable: true }),
|
|
38
|
+
__metadata("design:type", Object)
|
|
39
39
|
], CodeChunk.prototype, "startLine", void 0);
|
|
40
40
|
__decorate([
|
|
41
41
|
(0, typeorm_1.Column)('text'),
|