bluera-knowledge 0.17.1 → 0.18.0
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 +98 -0
- package/README.md +3 -3
- package/dist/brands-3EYIYV6T.js +13 -0
- package/dist/chunk-CLIMKLTW.js +28 -0
- package/dist/chunk-CLIMKLTW.js.map +1 -0
- package/dist/{chunk-ZGEQCLOZ.js → chunk-EZXJ3W5X.js} +79 -32
- package/dist/chunk-EZXJ3W5X.js.map +1 -0
- package/dist/chunk-HXBIIMYL.js +140 -0
- package/dist/chunk-HXBIIMYL.js.map +1 -0
- package/dist/{chunk-VKTVMW45.js → chunk-RDDGZIDL.js} +1182 -330
- package/dist/chunk-RDDGZIDL.js.map +1 -0
- package/dist/{chunk-RAXRD23K.js → chunk-VUGQ7HAR.js} +10 -6
- package/dist/chunk-VUGQ7HAR.js.map +1 -0
- package/dist/index.js +227 -84
- package/dist/index.js.map +1 -1
- package/dist/mcp/bootstrap.js +22 -3
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/server.d.ts +169 -18
- package/dist/mcp/server.js +4 -3
- package/dist/watch.service-VDSUQ72Z.js +7 -0
- package/dist/watch.service-VDSUQ72Z.js.map +1 -0
- package/dist/workers/background-worker-cli.js +20 -9
- package/dist/workers/background-worker-cli.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-HRQD3MPH.js +0 -69
- package/dist/chunk-HRQD3MPH.js.map +0 -1
- package/dist/chunk-RAXRD23K.js.map +0 -1
- package/dist/chunk-VKTVMW45.js.map +0 -1
- package/dist/chunk-ZGEQCLOZ.js.map +0 -1
- package/dist/watch.service-OPLKIDFQ.js +0 -7
- /package/dist/{watch.service-OPLKIDFQ.js.map → brands-3EYIYV6T.js.map} +0 -0
package/dist/mcp/bootstrap.js
CHANGED
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
import { homedir } from "os";
|
|
15
15
|
import { dirname, join } from "path";
|
|
16
16
|
import { fileURLToPath } from "url";
|
|
17
|
-
var
|
|
17
|
+
var envProjectRoot = process.env["PROJECT_ROOT"];
|
|
18
|
+
var logDir = envProjectRoot !== void 0 && envProjectRoot !== "" ? join(envProjectRoot, ".bluera", "bluera-knowledge", "logs") : join(homedir(), ".bluera", "bluera-knowledge", "logs");
|
|
18
19
|
var logFile = join(logDir, "app.log");
|
|
19
20
|
var log = (level, msg, data) => {
|
|
20
21
|
try {
|
|
@@ -57,8 +58,26 @@ function installWithPackageManager() {
|
|
|
57
58
|
})();
|
|
58
59
|
const cmd = hasBun ? "bun install --frozen-lockfile" : "npm ci --silent";
|
|
59
60
|
log("info", "Installing dependencies with package manager", { hasBun, cmd });
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
try {
|
|
62
|
+
const output = execSync(cmd, { cwd: pluginRoot, stdio: "pipe" });
|
|
63
|
+
if (output.length > 0) {
|
|
64
|
+
log("debug", "Install output", { output: output.toString().trim() });
|
|
65
|
+
}
|
|
66
|
+
log("info", "Dependencies installed via package manager");
|
|
67
|
+
} catch (error) {
|
|
68
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
69
|
+
const errorDetails = { message: errorMessage };
|
|
70
|
+
if (typeof error === "object" && error !== null) {
|
|
71
|
+
if ("stdout" in error && Buffer.isBuffer(error.stdout)) {
|
|
72
|
+
errorDetails["stdout"] = error.stdout.toString().trim();
|
|
73
|
+
}
|
|
74
|
+
if ("stderr" in error && Buffer.isBuffer(error.stderr)) {
|
|
75
|
+
errorDetails["stderr"] = error.stderr.toString().trim();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
log("error", "Dependency installation failed", errorDetails);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
62
81
|
}
|
|
63
82
|
function ensureDependencies() {
|
|
64
83
|
const nodeModulesPath = join(pluginRoot, "node_modules");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/bootstrap.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * MCP Server Bootstrap - installs dependencies before starting server.\n *\n * Uses only Node.js built-ins (no external dependencies required).\n * Self-locates plugin root via import.meta.url (doesn't rely on CLAUDE_PLUGIN_ROOT).\n *\n * Dependency installation strategy:\n * 1. Fast path: node_modules already exists → skip\n * 2. Package manager: Run bun install or npm ci\n *\n * IMPORTANT: MCP servers must NOT log to stderr - Claude Code treats stderr output\n * as an error and may mark the MCP server as failed. All logging goes to file.\n */\nimport { execSync } from 'node:child_process';\nimport {\n appendFileSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n unlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n// Logging helper - writes to file since MCP servers must NOT use stderr\n// (Claude Code treats stderr as error and may fail the server)\n// JSON format matches pino output for consistency\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/bootstrap.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * MCP Server Bootstrap - installs dependencies before starting server.\n *\n * Uses only Node.js built-ins (no external dependencies required).\n * Self-locates plugin root via import.meta.url (doesn't rely on CLAUDE_PLUGIN_ROOT).\n *\n * Dependency installation strategy:\n * 1. Fast path: node_modules already exists → skip\n * 2. Package manager: Run bun install or npm ci\n *\n * IMPORTANT: MCP servers must NOT log to stderr - Claude Code treats stderr output\n * as an error and may mark the MCP server as failed. All logging goes to file.\n */\nimport { execSync } from 'node:child_process';\nimport {\n appendFileSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n unlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n// Logging helper - writes to file since MCP servers must NOT use stderr\n// (Claude Code treats stderr as error and may fail the server)\n// JSON format matches pino output for consistency\n// Use PROJECT_ROOT if available (set by Claude Code), else fall back to home dir\nconst envProjectRoot = process.env['PROJECT_ROOT'];\nconst logDir =\n envProjectRoot !== undefined && envProjectRoot !== ''\n ? join(envProjectRoot, '.bluera', 'bluera-knowledge', 'logs')\n : join(homedir(), '.bluera', 'bluera-knowledge', 'logs');\nconst logFile = join(logDir, 'app.log');\n\nconst log = (\n level: 'info' | 'error' | 'debug',\n msg: string,\n data?: Record<string, unknown>\n): void => {\n try {\n mkdirSync(logDir, { recursive: true });\n const entry = {\n time: new Date().toISOString(),\n level,\n module: 'bootstrap',\n msg,\n ...data,\n };\n appendFileSync(logFile, `${JSON.stringify(entry)}\\n`);\n } catch {\n // Silently fail - we cannot use stderr for MCP servers\n }\n};\n\n// Self-locate plugin root from this file's path\n// dist/mcp/bootstrap.js -> plugin root (two directories up)\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst pluginRoot = join(__dirname, '..', '..');\n\n// Lock file to detect interrupted installs\nconst installLockFile = join(pluginRoot, '.node_modules_installing');\n\n// Get version from package.json for logging\nconst getVersion = (): string => {\n try {\n const pkg: unknown = JSON.parse(readFileSync(join(pluginRoot, 'package.json'), 'utf-8'));\n if (\n typeof pkg === 'object' &&\n pkg !== null &&\n 'version' in pkg &&\n typeof pkg.version === 'string'\n ) {\n return `v${pkg.version}`;\n }\n return 'unknown';\n } catch {\n return 'unknown';\n }\n};\n\n/**\n * Install dependencies using bun or npm.\n * Uses stdio: 'pipe' to capture output and avoid corrupting MCP stdio transport.\n */\nfunction installWithPackageManager(): void {\n const hasBun = ((): boolean => {\n try {\n execSync('which bun', { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n })();\n\n const cmd = hasBun ? 'bun install --frozen-lockfile' : 'npm ci --silent';\n log('info', 'Installing dependencies with package manager', { hasBun, cmd });\n\n try {\n // Use stdio: 'pipe' to capture output - 'inherit' would corrupt MCP stdio transport\n const output = execSync(cmd, { cwd: pluginRoot, stdio: 'pipe' });\n if (output.length > 0) {\n log('debug', 'Install output', { output: output.toString().trim() });\n }\n log('info', 'Dependencies installed via package manager');\n } catch (error) {\n // Log installation failure details before re-throwing\n // execSync throws an object with stdout/stderr buffers on failure\n const errorMessage = error instanceof Error ? error.message : String(error);\n const errorDetails: Record<string, unknown> = { message: errorMessage };\n\n if (typeof error === 'object' && error !== null) {\n if ('stdout' in error && Buffer.isBuffer(error.stdout)) {\n errorDetails['stdout'] = error.stdout.toString().trim();\n }\n if ('stderr' in error && Buffer.isBuffer(error.stderr)) {\n errorDetails['stderr'] = error.stderr.toString().trim();\n }\n }\n\n log('error', 'Dependency installation failed', errorDetails);\n throw error;\n }\n}\n\n/**\n * Ensure dependencies are available.\n * Uses a lock file to detect and recover from interrupted installs.\n */\nfunction ensureDependencies(): void {\n const nodeModulesPath = join(pluginRoot, 'node_modules');\n\n // Check for interrupted install - lock file exists means previous install was killed\n if (existsSync(installLockFile)) {\n log('info', 'Detected interrupted install, cleaning up');\n rmSync(nodeModulesPath, { recursive: true, force: true });\n unlinkSync(installLockFile);\n }\n\n // Fast path: already installed\n if (existsSync(nodeModulesPath)) {\n log('info', 'Dependencies already installed');\n return;\n }\n\n // Create lock file before install (left behind if install interrupted/fails)\n writeFileSync(installLockFile, new Date().toISOString());\n\n installWithPackageManager();\n\n // Remove lock file on success\n unlinkSync(installLockFile);\n}\n\n// Main entry point\nconst VERSION = getVersion();\nlog('info', 'Bootstrap starting', { pluginRoot, version: VERSION });\n\nensureDependencies();\n\n// Now that dependencies are installed, import and run the server\n// Dynamic import required because @modelcontextprotocol/sdk wouldn't be available before install\nlog('info', 'Loading server module');\nconst { runMCPServer } = await import('./server.js');\n\nconst projectRoot = process.env['PROJECT_ROOT'];\nif (projectRoot === undefined) {\n throw new Error('PROJECT_ROOT environment variable is required');\n}\n\nlog('info', 'Starting MCP server', {\n projectRoot,\n dataDir: process.env['DATA_DIR'],\n});\n\nawait runMCPServer({\n dataDir: process.env['DATA_DIR'],\n config: process.env['CONFIG_PATH'],\n projectRoot,\n});\n"],"mappings":"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","names":[]}
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -156,6 +156,22 @@ type DocumentId = string & {
|
|
|
156
156
|
readonly [DocumentIdBrand]: typeof DocumentIdBrand;
|
|
157
157
|
};
|
|
158
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Events emitted when cached data becomes stale.
|
|
161
|
+
* Used to notify dependent services (e.g., SearchService) when
|
|
162
|
+
* source data (e.g., code graphs) has been updated or deleted.
|
|
163
|
+
*/
|
|
164
|
+
interface CacheInvalidationEvent {
|
|
165
|
+
/** Type of invalidation */
|
|
166
|
+
type: 'graph-updated' | 'graph-deleted';
|
|
167
|
+
/** The store whose data changed */
|
|
168
|
+
storeId: StoreId;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Listener function for cache invalidation events.
|
|
172
|
+
*/
|
|
173
|
+
type CacheInvalidationListener = (event: CacheInvalidationEvent) => void;
|
|
174
|
+
|
|
159
175
|
/**
|
|
160
176
|
* Service for building, persisting, and querying code graphs.
|
|
161
177
|
* Code graphs track relationships between code elements (functions, classes, etc.)
|
|
@@ -166,7 +182,17 @@ declare class CodeGraphService {
|
|
|
166
182
|
private readonly parser;
|
|
167
183
|
private readonly parserFactory;
|
|
168
184
|
private readonly graphCache;
|
|
185
|
+
private readonly cacheListeners;
|
|
169
186
|
constructor(dataDir: string, pythonBridge?: PythonBridge);
|
|
187
|
+
/**
|
|
188
|
+
* Subscribe to cache invalidation events.
|
|
189
|
+
* Returns an unsubscribe function.
|
|
190
|
+
*/
|
|
191
|
+
onCacheInvalidation(listener: CacheInvalidationListener): () => void;
|
|
192
|
+
/**
|
|
193
|
+
* Emit a cache invalidation event to all listeners.
|
|
194
|
+
*/
|
|
195
|
+
private emitCacheInvalidation;
|
|
170
196
|
/**
|
|
171
197
|
* Build a code graph from source files.
|
|
172
198
|
*/
|
|
@@ -232,7 +258,6 @@ declare class CodeGraphService {
|
|
|
232
258
|
interface EmbeddingConfig {
|
|
233
259
|
readonly model: string;
|
|
234
260
|
readonly batchSize: number;
|
|
235
|
-
readonly dimensions: number;
|
|
236
261
|
}
|
|
237
262
|
interface IndexingConfig {
|
|
238
263
|
readonly concurrency: number;
|
|
@@ -243,12 +268,6 @@ interface IndexingConfig {
|
|
|
243
268
|
interface SearchConfig {
|
|
244
269
|
readonly defaultMode: 'vector' | 'fts' | 'hybrid';
|
|
245
270
|
readonly defaultLimit: number;
|
|
246
|
-
readonly minScore: number;
|
|
247
|
-
readonly rrf: {
|
|
248
|
-
readonly k: number;
|
|
249
|
-
readonly vectorWeight: number;
|
|
250
|
-
readonly ftsWeight: number;
|
|
251
|
-
};
|
|
252
271
|
}
|
|
253
272
|
interface CrawlConfig {
|
|
254
273
|
readonly userAgent: string;
|
|
@@ -272,8 +291,13 @@ interface AppConfig {
|
|
|
272
291
|
declare class ConfigService {
|
|
273
292
|
private readonly configPath;
|
|
274
293
|
private readonly dataDir;
|
|
294
|
+
private readonly projectRoot;
|
|
275
295
|
private config;
|
|
276
296
|
constructor(configPath?: string, dataDir?: string, projectRoot?: string);
|
|
297
|
+
/**
|
|
298
|
+
* Get the resolved project root directory.
|
|
299
|
+
*/
|
|
300
|
+
resolveProjectRoot(): string;
|
|
277
301
|
load(): Promise<AppConfig>;
|
|
278
302
|
save(config: AppConfig): Promise<void>;
|
|
279
303
|
resolveDataDir(): string;
|
|
@@ -281,15 +305,87 @@ declare class ConfigService {
|
|
|
281
305
|
private expandPath;
|
|
282
306
|
}
|
|
283
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Type-safe manifest with branded StoreId.
|
|
310
|
+
* Use this in service code for proper type safety.
|
|
311
|
+
*/
|
|
312
|
+
interface TypedStoreManifest {
|
|
313
|
+
version: 1;
|
|
314
|
+
storeId: StoreId;
|
|
315
|
+
indexedAt: string;
|
|
316
|
+
files: Record<string, TypedFileState>;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Type-safe file state with branded DocumentIds.
|
|
320
|
+
*/
|
|
321
|
+
interface TypedFileState {
|
|
322
|
+
mtime: number;
|
|
323
|
+
size: number;
|
|
324
|
+
hash: string;
|
|
325
|
+
documentIds: DocumentId[];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Service for managing store manifests.
|
|
330
|
+
*
|
|
331
|
+
* Manifests track the state of indexed files to enable incremental re-indexing.
|
|
332
|
+
* They are stored in the data directory under manifests/{storeId}.manifest.json.
|
|
333
|
+
*/
|
|
334
|
+
declare class ManifestService {
|
|
335
|
+
private readonly manifestsDir;
|
|
336
|
+
constructor(dataDir: string);
|
|
337
|
+
/**
|
|
338
|
+
* Initialize the manifests directory.
|
|
339
|
+
*/
|
|
340
|
+
initialize(): Promise<void>;
|
|
341
|
+
/**
|
|
342
|
+
* Get the file path for a store's manifest.
|
|
343
|
+
*/
|
|
344
|
+
getManifestPath(storeId: StoreId): string;
|
|
345
|
+
/**
|
|
346
|
+
* Load a store's manifest.
|
|
347
|
+
* Returns an empty manifest if one doesn't exist.
|
|
348
|
+
* Throws on parse/validation errors (fail fast).
|
|
349
|
+
*/
|
|
350
|
+
load(storeId: StoreId): Promise<TypedStoreManifest>;
|
|
351
|
+
/**
|
|
352
|
+
* Save a store's manifest atomically.
|
|
353
|
+
*/
|
|
354
|
+
save(manifest: TypedStoreManifest): Promise<void>;
|
|
355
|
+
/**
|
|
356
|
+
* Delete a store's manifest.
|
|
357
|
+
* Called when a store is deleted or during full re-index.
|
|
358
|
+
*/
|
|
359
|
+
delete(storeId: StoreId): Promise<void>;
|
|
360
|
+
/**
|
|
361
|
+
* Check if a file exists.
|
|
362
|
+
*/
|
|
363
|
+
private fileExists;
|
|
364
|
+
/**
|
|
365
|
+
* Convert a parsed manifest to a typed manifest with branded types.
|
|
366
|
+
*/
|
|
367
|
+
private toTypedManifest;
|
|
368
|
+
}
|
|
369
|
+
|
|
284
370
|
declare class EmbeddingEngine {
|
|
285
371
|
private extractor;
|
|
372
|
+
private _dimensions;
|
|
286
373
|
private readonly modelName;
|
|
287
|
-
private readonly
|
|
288
|
-
constructor(modelName?: string,
|
|
374
|
+
private readonly batchSize;
|
|
375
|
+
constructor(modelName?: string, batchSize?: number);
|
|
289
376
|
initialize(): Promise<void>;
|
|
290
377
|
embed(text: string): Promise<number[]>;
|
|
291
378
|
embedBatch(texts: string[]): Promise<number[][]>;
|
|
379
|
+
/**
|
|
380
|
+
* Get cached embedding dimensions. Throws if embed() hasn't been called yet.
|
|
381
|
+
* Use ensureDimensions() if you need to guarantee dimensions are available.
|
|
382
|
+
*/
|
|
292
383
|
getDimensions(): number;
|
|
384
|
+
/**
|
|
385
|
+
* Ensure dimensions are available, initializing the model if needed.
|
|
386
|
+
* Returns the embedding dimensions for the current model.
|
|
387
|
+
*/
|
|
388
|
+
ensureDimensions(): Promise<number>;
|
|
293
389
|
/**
|
|
294
390
|
* Dispose the embedding pipeline to free resources.
|
|
295
391
|
* Should be called before process exit to prevent ONNX runtime cleanup issues on macOS.
|
|
@@ -308,7 +404,7 @@ interface DocumentMetadata {
|
|
|
308
404
|
readonly url?: string | undefined;
|
|
309
405
|
readonly type: DocumentType;
|
|
310
406
|
readonly storeId: StoreId;
|
|
311
|
-
readonly indexedAt:
|
|
407
|
+
readonly indexedAt: string;
|
|
312
408
|
readonly fileHash?: string | undefined;
|
|
313
409
|
readonly chunkIndex?: number | undefined;
|
|
314
410
|
readonly totalChunks?: number | undefined;
|
|
@@ -325,10 +421,18 @@ declare class LanceStore {
|
|
|
325
421
|
private connection;
|
|
326
422
|
private readonly tables;
|
|
327
423
|
private readonly dataDir;
|
|
424
|
+
private _dimensions;
|
|
328
425
|
constructor(dataDir: string);
|
|
426
|
+
/**
|
|
427
|
+
* Set the embedding dimensions. Must be called before initialize().
|
|
428
|
+
* This allows dimensions to be derived from the embedding model at runtime.
|
|
429
|
+
* Idempotent: subsequent calls are ignored if dimensions are already set.
|
|
430
|
+
*/
|
|
431
|
+
setDimensions(dimensions: number): void;
|
|
329
432
|
initialize(storeId: StoreId): Promise<void>;
|
|
330
433
|
addDocuments(storeId: StoreId, documents: Document[]): Promise<void>;
|
|
331
434
|
deleteDocuments(storeId: StoreId, documentIds: DocumentId[]): Promise<void>;
|
|
435
|
+
clearAllDocuments(storeId: StoreId): Promise<void>;
|
|
332
436
|
search(storeId: StoreId, vector: number[], limit: number, _threshold?: number): Promise<Array<{
|
|
333
437
|
id: DocumentId;
|
|
334
438
|
content: string;
|
|
@@ -391,17 +495,20 @@ interface RepoStore extends BaseStore {
|
|
|
391
495
|
readonly path: string;
|
|
392
496
|
readonly url?: string | undefined;
|
|
393
497
|
readonly branch?: string | undefined;
|
|
498
|
+
readonly depth?: number | undefined;
|
|
394
499
|
}
|
|
395
500
|
interface WebStore extends BaseStore {
|
|
396
501
|
readonly type: 'web';
|
|
397
502
|
readonly url: string;
|
|
398
503
|
readonly depth: number;
|
|
399
504
|
readonly maxPages?: number | undefined;
|
|
505
|
+
readonly crawlInstructions?: string | undefined;
|
|
506
|
+
readonly extractInstructions?: string | undefined;
|
|
400
507
|
}
|
|
401
508
|
type Store = FileStore | RepoStore | WebStore;
|
|
402
509
|
|
|
403
510
|
interface IndexResult {
|
|
404
|
-
|
|
511
|
+
filesIndexed: number;
|
|
405
512
|
chunksCreated: number;
|
|
406
513
|
timeMs: number;
|
|
407
514
|
}
|
|
@@ -410,15 +517,36 @@ interface IndexOptions {
|
|
|
410
517
|
chunkOverlap?: number;
|
|
411
518
|
codeGraphService?: CodeGraphService;
|
|
412
519
|
concurrency?: number;
|
|
520
|
+
manifestService?: ManifestService;
|
|
521
|
+
ignorePatterns?: readonly string[];
|
|
522
|
+
}
|
|
523
|
+
interface IncrementalIndexResult extends IndexResult {
|
|
524
|
+
filesAdded: number;
|
|
525
|
+
filesModified: number;
|
|
526
|
+
filesDeleted: number;
|
|
527
|
+
filesUnchanged: number;
|
|
413
528
|
}
|
|
414
529
|
declare class IndexService {
|
|
415
530
|
private readonly lanceStore;
|
|
416
531
|
private readonly embeddingEngine;
|
|
417
532
|
private readonly chunker;
|
|
418
533
|
private readonly codeGraphService;
|
|
534
|
+
private readonly manifestService;
|
|
535
|
+
private readonly driftService;
|
|
419
536
|
private readonly concurrency;
|
|
537
|
+
private readonly ignoreDirs;
|
|
538
|
+
private readonly ignoreFilePatterns;
|
|
420
539
|
constructor(lanceStore: LanceStore, embeddingEngine: EmbeddingEngine, options?: IndexOptions);
|
|
421
540
|
indexStore(store: Store, onProgress?: ProgressCallback): Promise<Result<IndexResult>>;
|
|
541
|
+
/**
|
|
542
|
+
* Incrementally index a store, only processing changed files.
|
|
543
|
+
* Requires manifestService to be configured.
|
|
544
|
+
*
|
|
545
|
+
* @param store - The store to index
|
|
546
|
+
* @param onProgress - Optional progress callback
|
|
547
|
+
* @returns Result with incremental index statistics
|
|
548
|
+
*/
|
|
549
|
+
indexStoreIncremental(store: Store, onProgress?: ProgressCallback): Promise<Result<IncrementalIndexResult>>;
|
|
422
550
|
private indexFileStore;
|
|
423
551
|
/**
|
|
424
552
|
* Process a single file: read, chunk, embed, and return documents.
|
|
@@ -440,6 +568,11 @@ declare class IndexService {
|
|
|
440
568
|
}
|
|
441
569
|
|
|
442
570
|
type SearchMode = 'vector' | 'fts' | 'hybrid';
|
|
571
|
+
/**
|
|
572
|
+
* Search intent hints for context-aware ranking.
|
|
573
|
+
* These align with the MCP API contract.
|
|
574
|
+
*/
|
|
575
|
+
type SearchIntent = 'find-pattern' | 'find-implementation' | 'find-usage' | 'find-definition' | 'find-documentation';
|
|
443
576
|
interface CodeUnit {
|
|
444
577
|
type: 'function' | 'class' | 'interface' | 'type' | 'const' | 'documentation' | 'example';
|
|
445
578
|
name: string;
|
|
@@ -484,9 +617,7 @@ interface SearchQuery {
|
|
|
484
617
|
readonly limit?: number | undefined;
|
|
485
618
|
readonly threshold?: number | undefined;
|
|
486
619
|
readonly minRelevance?: number | undefined;
|
|
487
|
-
readonly
|
|
488
|
-
readonly includeContent?: boolean | undefined;
|
|
489
|
-
readonly contextLines?: number | undefined;
|
|
620
|
+
readonly intent?: SearchIntent | undefined;
|
|
490
621
|
readonly detail?: DetailLevel | undefined;
|
|
491
622
|
}
|
|
492
623
|
interface SearchResult {
|
|
@@ -529,7 +660,14 @@ declare class SearchService {
|
|
|
529
660
|
private readonly codeUnitService;
|
|
530
661
|
private readonly codeGraphService;
|
|
531
662
|
private readonly graphCache;
|
|
532
|
-
|
|
663
|
+
private readonly searchConfig;
|
|
664
|
+
private readonly unsubscribeCacheInvalidation;
|
|
665
|
+
constructor(lanceStore: LanceStore, embeddingEngine: EmbeddingEngine, codeGraphService?: CodeGraphService, searchConfig?: SearchConfig);
|
|
666
|
+
/**
|
|
667
|
+
* Clean up resources (unsubscribe from events).
|
|
668
|
+
* Call this when destroying the service.
|
|
669
|
+
*/
|
|
670
|
+
cleanup(): void;
|
|
533
671
|
/**
|
|
534
672
|
* Load code graph for a store, with caching.
|
|
535
673
|
* Returns null if no graph is available.
|
|
@@ -565,7 +703,6 @@ declare class SearchService {
|
|
|
565
703
|
* Returns results with raw cosine similarity scores [0-1].
|
|
566
704
|
*/
|
|
567
705
|
private vectorSearchRaw;
|
|
568
|
-
private vectorSearch;
|
|
569
706
|
private ftsSearch;
|
|
570
707
|
/**
|
|
571
708
|
* Internal hybrid search result with additional metadata for confidence calculation.
|
|
@@ -671,7 +808,7 @@ declare const StoreDefinitionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
671
808
|
description: z.ZodOptional<z.ZodString>;
|
|
672
809
|
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
673
810
|
type: z.ZodLiteral<"repo">;
|
|
674
|
-
url: z.
|
|
811
|
+
url: z.ZodString;
|
|
675
812
|
branch: z.ZodOptional<z.ZodString>;
|
|
676
813
|
depth: z.ZodOptional<z.ZodNumber>;
|
|
677
814
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -703,7 +840,7 @@ declare const StoreDefinitionsConfigSchema: z.ZodObject<{
|
|
|
703
840
|
description: z.ZodOptional<z.ZodString>;
|
|
704
841
|
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
705
842
|
type: z.ZodLiteral<"repo">;
|
|
706
|
-
url: z.
|
|
843
|
+
url: z.ZodString;
|
|
707
844
|
branch: z.ZodOptional<z.ZodString>;
|
|
708
845
|
depth: z.ZodOptional<z.ZodNumber>;
|
|
709
846
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -800,12 +937,17 @@ interface CreateStoreInput {
|
|
|
800
937
|
tags?: string[] | undefined;
|
|
801
938
|
branch?: string | undefined;
|
|
802
939
|
depth?: number | undefined;
|
|
940
|
+
maxPages?: number | undefined;
|
|
941
|
+
crawlInstructions?: string | undefined;
|
|
942
|
+
extractInstructions?: string | undefined;
|
|
803
943
|
}
|
|
804
944
|
interface StoreServiceOptions {
|
|
805
945
|
/** Optional definition service for auto-updating git-committable config */
|
|
806
946
|
definitionService?: StoreDefinitionService;
|
|
807
947
|
/** Optional gitignore service for ensuring .gitignore patterns */
|
|
808
948
|
gitignoreService?: GitignoreService;
|
|
949
|
+
/** Optional project root for resolving relative paths */
|
|
950
|
+
projectRoot?: string;
|
|
809
951
|
}
|
|
810
952
|
interface OperationOptions {
|
|
811
953
|
/** Skip syncing to store definitions (used by stores:sync command) */
|
|
@@ -815,13 +957,21 @@ declare class StoreService {
|
|
|
815
957
|
private readonly dataDir;
|
|
816
958
|
private readonly definitionService;
|
|
817
959
|
private readonly gitignoreService;
|
|
960
|
+
private readonly projectRoot;
|
|
818
961
|
private registry;
|
|
819
962
|
constructor(dataDir: string, options?: StoreServiceOptions);
|
|
820
963
|
initialize(): Promise<void>;
|
|
821
964
|
/**
|
|
822
965
|
* Convert a Store and CreateStoreInput to a StoreDefinition for persistence.
|
|
966
|
+
* Returns undefined for stores that shouldn't be persisted (e.g., local repo stores).
|
|
823
967
|
*/
|
|
824
968
|
private createDefinitionFromStore;
|
|
969
|
+
/**
|
|
970
|
+
* Create a StoreDefinition from an existing store (without original input).
|
|
971
|
+
* Used when updating/renaming stores where we don't have the original input.
|
|
972
|
+
* Returns undefined for stores that shouldn't be persisted (e.g., local repo stores).
|
|
973
|
+
*/
|
|
974
|
+
private createDefinitionFromExistingStore;
|
|
825
975
|
create(input: CreateStoreInput, options?: OperationOptions): Promise<Result<Store>>;
|
|
826
976
|
list(type?: StoreType): Promise<Store[]>;
|
|
827
977
|
get(id: StoreId): Promise<Store | undefined>;
|
|
@@ -842,6 +992,7 @@ interface ServiceContainer {
|
|
|
842
992
|
embeddings: EmbeddingEngine;
|
|
843
993
|
codeGraph: CodeGraphService;
|
|
844
994
|
pythonBridge: PythonBridge;
|
|
995
|
+
manifest: ManifestService;
|
|
845
996
|
}
|
|
846
997
|
|
|
847
998
|
/**
|
package/dist/mcp/server.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createMCPServer,
|
|
3
3
|
runMCPServer
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-EZXJ3W5X.js";
|
|
5
|
+
import "../chunk-RDDGZIDL.js";
|
|
6
|
+
import "../chunk-CLIMKLTW.js";
|
|
7
|
+
import "../chunk-HXBIIMYL.js";
|
|
7
8
|
export {
|
|
8
9
|
createMCPServer,
|
|
9
10
|
runMCPServer
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
IntelligentCrawler
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-VUGQ7HAR.js";
|
|
5
5
|
import {
|
|
6
6
|
JobService,
|
|
7
|
-
createDocumentId,
|
|
8
7
|
createLogger,
|
|
9
8
|
createServices,
|
|
10
|
-
createStoreId,
|
|
11
9
|
destroyServices,
|
|
12
10
|
shutdownLogger
|
|
13
|
-
} from "../chunk-
|
|
14
|
-
import
|
|
11
|
+
} from "../chunk-RDDGZIDL.js";
|
|
12
|
+
import {
|
|
13
|
+
createDocumentId,
|
|
14
|
+
createStoreId
|
|
15
|
+
} from "../chunk-CLIMKLTW.js";
|
|
16
|
+
import "../chunk-HXBIIMYL.js";
|
|
15
17
|
|
|
16
18
|
// src/workers/background-worker-cli.ts
|
|
17
19
|
import { platform } from "os";
|
|
@@ -24,12 +26,13 @@ function calculateIndexProgress(current, total, scale = 100) {
|
|
|
24
26
|
return current / total * scale;
|
|
25
27
|
}
|
|
26
28
|
var BackgroundWorker = class {
|
|
27
|
-
constructor(jobService, storeService, indexService, lanceStore, embeddingEngine) {
|
|
29
|
+
constructor(jobService, storeService, indexService, lanceStore, embeddingEngine, crawlConfig) {
|
|
28
30
|
this.jobService = jobService;
|
|
29
31
|
this.storeService = storeService;
|
|
30
32
|
this.indexService = indexService;
|
|
31
33
|
this.lanceStore = lanceStore;
|
|
32
34
|
this.embeddingEngine = embeddingEngine;
|
|
35
|
+
this.crawlConfig = crawlConfig;
|
|
33
36
|
}
|
|
34
37
|
/**
|
|
35
38
|
* Execute a job based on its type
|
|
@@ -104,6 +107,8 @@ var BackgroundWorker = class {
|
|
|
104
107
|
message: "Repository cloned, starting indexing...",
|
|
105
108
|
progress: 30
|
|
106
109
|
});
|
|
110
|
+
this.lanceStore.setDimensions(await this.embeddingEngine.ensureDimensions());
|
|
111
|
+
await this.lanceStore.initialize(store.id);
|
|
107
112
|
const result = await this.indexService.indexStore(
|
|
108
113
|
store,
|
|
109
114
|
(event) => {
|
|
@@ -140,6 +145,8 @@ var BackgroundWorker = class {
|
|
|
140
145
|
if (!store) {
|
|
141
146
|
throw new Error(`Store ${storeId} not found`);
|
|
142
147
|
}
|
|
148
|
+
this.lanceStore.setDimensions(await this.embeddingEngine.ensureDimensions());
|
|
149
|
+
await this.lanceStore.initialize(store.id);
|
|
143
150
|
const result = await this.indexService.indexStore(
|
|
144
151
|
store,
|
|
145
152
|
(event) => {
|
|
@@ -179,7 +186,7 @@ var BackgroundWorker = class {
|
|
|
179
186
|
throw new Error(`Web store ${storeId} not found`);
|
|
180
187
|
}
|
|
181
188
|
const resolvedMaxPages = typeof maxPages === "number" ? maxPages : 50;
|
|
182
|
-
const crawler = new IntelligentCrawler();
|
|
189
|
+
const crawler = new IntelligentCrawler(this.crawlConfig);
|
|
183
190
|
crawler.on("progress", (progress) => {
|
|
184
191
|
const currentJob = this.jobService.getJob(job.id);
|
|
185
192
|
if (currentJob?.status === "cancelled") {
|
|
@@ -193,6 +200,7 @@ var BackgroundWorker = class {
|
|
|
193
200
|
});
|
|
194
201
|
});
|
|
195
202
|
try {
|
|
203
|
+
this.lanceStore.setDimensions(await this.embeddingEngine.ensureDimensions());
|
|
196
204
|
await this.lanceStore.initialize(store.id);
|
|
197
205
|
const docs = [];
|
|
198
206
|
const crawlOptions = {
|
|
@@ -225,7 +233,7 @@ var BackgroundWorker = class {
|
|
|
225
233
|
title: result.title,
|
|
226
234
|
extracted: result.extracted !== void 0,
|
|
227
235
|
depth: result.depth,
|
|
228
|
-
indexedAt: /* @__PURE__ */ new Date()
|
|
236
|
+
indexedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
229
237
|
}
|
|
230
238
|
});
|
|
231
239
|
}
|
|
@@ -234,6 +242,7 @@ var BackgroundWorker = class {
|
|
|
234
242
|
message: "Indexing crawled documents...",
|
|
235
243
|
progress: 85
|
|
236
244
|
});
|
|
245
|
+
await this.lanceStore.clearAllDocuments(store.id);
|
|
237
246
|
await this.lanceStore.addDocuments(store.id, docs);
|
|
238
247
|
await this.lanceStore.createFtsIndex(store.id);
|
|
239
248
|
}
|
|
@@ -330,12 +339,14 @@ async function main() {
|
|
|
330
339
|
}
|
|
331
340
|
void shutdownLogger().finally(() => process.exit(0));
|
|
332
341
|
});
|
|
342
|
+
const appConfig = await services.config.load();
|
|
333
343
|
const worker = new BackgroundWorker(
|
|
334
344
|
jobService,
|
|
335
345
|
services.store,
|
|
336
346
|
services.index,
|
|
337
347
|
services.lance,
|
|
338
|
-
services.embeddings
|
|
348
|
+
services.embeddings,
|
|
349
|
+
appConfig.crawl
|
|
339
350
|
);
|
|
340
351
|
try {
|
|
341
352
|
await worker.executeJob(jobId);
|