bluera-knowledge 0.28.1 → 0.30.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 +30 -0
- package/README.md +194 -13
- package/dist/{chunk-UXT3BCAH.js → chunk-AEXFPA57.js} +398 -106
- package/dist/chunk-AEXFPA57.js.map +1 -0
- package/dist/{chunk-WP2GERAJ.js → chunk-B335UOU7.js} +1328 -467
- package/dist/chunk-B335UOU7.js.map +1 -0
- package/dist/{chunk-BYLIDCWD.js → chunk-KCI4U6FH.js} +2 -2
- package/dist/{chunk-H25AEF47.js → chunk-N3XYMAU3.js} +81 -2
- package/dist/chunk-N3XYMAU3.js.map +1 -0
- package/dist/index.js +8 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp/bootstrap.js +9 -1
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/server.d.ts +135 -10
- package/dist/mcp/server.js +3 -3
- package/dist/{watch.service-THP6X5ZZ.js → watch.service-LRFCT52P.js} +2 -2
- package/dist/workers/background-worker-cli.js +3 -3
- package/package.json +12 -3
- package/dist/chunk-H25AEF47.js.map +0 -1
- package/dist/chunk-UXT3BCAH.js.map +0 -1
- package/dist/chunk-WP2GERAJ.js.map +0 -1
- /package/dist/{chunk-BYLIDCWD.js.map → chunk-KCI4U6FH.js.map} +0 -0
- /package/dist/{watch.service-THP6X5ZZ.js.map → watch.service-LRFCT52P.js.map} +0 -0
package/dist/mcp/bootstrap.js
CHANGED
|
@@ -72,7 +72,15 @@ function installWithPackageManager() {
|
|
|
72
72
|
const cmd = hasBun ? "bun install --frozen-lockfile" : "npm install --legacy-peer-deps --silent";
|
|
73
73
|
log("info", "Installing dependencies with package manager", { hasBun, cmd });
|
|
74
74
|
try {
|
|
75
|
-
const output = execSync(cmd, {
|
|
75
|
+
const output = execSync(cmd, {
|
|
76
|
+
cwd: pluginRoot,
|
|
77
|
+
stdio: "pipe",
|
|
78
|
+
env: {
|
|
79
|
+
...process.env,
|
|
80
|
+
PUPPETEER_SKIP_DOWNLOAD: "1",
|
|
81
|
+
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
|
|
82
|
+
}
|
|
83
|
+
});
|
|
76
84
|
if (output.length > 0) {
|
|
77
85
|
log("debug", "Install output", { output: output.toString().trim() });
|
|
78
86
|
}
|
|
@@ -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 install\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 * Check if build tools are available for native module compilation.\n * Logs error to file and throws if make is not found.\n */\nfunction checkBuildTools(): void {\n try {\n execSync('which make', { stdio: 'ignore' });\n log('debug', 'Build tools available (make found)');\n } catch {\n log('error', 'Build tools not found - make is required for native modules', {\n fix: 'Install build-essential (Debian/Ubuntu), Development Tools (Fedora), or Xcode CLI Tools (macOS)',\n });\n throw new Error(\n 'Build tools not found. Install: sudo apt install build-essential (Debian/Ubuntu), ' +\n 'sudo dnf groupinstall \"Development Tools\" (Fedora), or xcode-select --install (macOS)'\n );\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 // CRITICAL: npm needs peer-deps bypass flag (tree-sitter-go/rust have conflicting requirements)\n const cmd = hasBun ? 'bun install --frozen-lockfile' : 'npm install --legacy-peer-deps --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 startTime = Date.now();\n log('debug', 'ensureDependencies starting');\n\n const nodeModulesPath = join(pluginRoot, 'node_modules');\n\n // Check for interrupted install - lock file exists means previous install was killed\n log('debug', 'Checking for interrupted install lock file', { lockFile: installLockFile });\n if (existsSync(installLockFile)) {\n log('info', 'Detected interrupted install, cleaning up');\n rmSync(nodeModulesPath, { recursive: true, force: true });\n unlinkSync(installLockFile);\n log('debug', 'Cleanup complete');\n }\n\n // Fast path: already installed\n log('debug', 'Checking node_modules exists', { path: nodeModulesPath });\n if (existsSync(nodeModulesPath)) {\n log('info', 'Dependencies already installed', { elapsedMs: Date.now() - startTime });\n return;\n }\n\n // Check build tools before attempting install\n log('debug', 'Checking build tools before install');\n checkBuildTools();\n\n // Create lock file before install (left behind if install interrupted/fails)\n log('debug', 'Creating lock file before install');\n writeFileSync(installLockFile, new Date().toISOString());\n\n const installStart = Date.now();\n log('debug', 'Starting package manager install');\n installWithPackageManager();\n log('debug', 'Package manager install finished', { elapsedMs: Date.now() - installStart });\n\n // Remove lock file on success\n unlinkSync(installLockFile);\n log('debug', 'ensureDependencies complete', { totalElapsedMs: Date.now() - startTime });\n}\n\n// Main entry point\nconst bootstrapStartTime = Date.now();\nconst VERSION = getVersion();\nlog('info', 'Bootstrap starting', { pluginRoot, version: VERSION });\n\nlog('debug', 'Calling ensureDependencies');\nensureDependencies();\nlog('debug', 'ensureDependencies returned', { elapsedMs: Date.now() - bootstrapStartTime });\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 importStart = Date.now();\nconst { runMCPServer } = await import('./server.js');\nlog('debug', 'Server module loaded', { elapsedMs: Date.now() - importStart });\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":[]}
|
|
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 install\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 * Check if build tools are available for native module compilation.\n * Logs error to file and throws if make is not found.\n */\nfunction checkBuildTools(): void {\n try {\n execSync('which make', { stdio: 'ignore' });\n log('debug', 'Build tools available (make found)');\n } catch {\n log('error', 'Build tools not found - make is required for native modules', {\n fix: 'Install build-essential (Debian/Ubuntu), Development Tools (Fedora), or Xcode CLI Tools (macOS)',\n });\n throw new Error(\n 'Build tools not found. Install: sudo apt install build-essential (Debian/Ubuntu), ' +\n 'sudo dnf groupinstall \"Development Tools\" (Fedora), or xcode-select --install (macOS)'\n );\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 // CRITICAL: npm needs peer-deps bypass flag (tree-sitter-go/rust have conflicting requirements)\n const cmd = hasBun ? 'bun install --frozen-lockfile' : 'npm install --legacy-peer-deps --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 // Skip browser downloads during install - browsers are installed separately by setup.sh\n const output = execSync(cmd, {\n cwd: pluginRoot,\n stdio: 'pipe',\n env: {\n ...process.env,\n PUPPETEER_SKIP_DOWNLOAD: '1',\n PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1',\n },\n });\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 startTime = Date.now();\n log('debug', 'ensureDependencies starting');\n\n const nodeModulesPath = join(pluginRoot, 'node_modules');\n\n // Check for interrupted install - lock file exists means previous install was killed\n log('debug', 'Checking for interrupted install lock file', { lockFile: installLockFile });\n if (existsSync(installLockFile)) {\n log('info', 'Detected interrupted install, cleaning up');\n rmSync(nodeModulesPath, { recursive: true, force: true });\n unlinkSync(installLockFile);\n log('debug', 'Cleanup complete');\n }\n\n // Fast path: already installed\n log('debug', 'Checking node_modules exists', { path: nodeModulesPath });\n if (existsSync(nodeModulesPath)) {\n log('info', 'Dependencies already installed', { elapsedMs: Date.now() - startTime });\n return;\n }\n\n // Check build tools before attempting install\n log('debug', 'Checking build tools before install');\n checkBuildTools();\n\n // Create lock file before install (left behind if install interrupted/fails)\n log('debug', 'Creating lock file before install');\n writeFileSync(installLockFile, new Date().toISOString());\n\n const installStart = Date.now();\n log('debug', 'Starting package manager install');\n installWithPackageManager();\n log('debug', 'Package manager install finished', { elapsedMs: Date.now() - installStart });\n\n // Remove lock file on success\n unlinkSync(installLockFile);\n log('debug', 'ensureDependencies complete', { totalElapsedMs: Date.now() - startTime });\n}\n\n// Main entry point\nconst bootstrapStartTime = Date.now();\nconst VERSION = getVersion();\nlog('info', 'Bootstrap starting', { pluginRoot, version: VERSION });\n\nlog('debug', 'Calling ensureDependencies');\nensureDependencies();\nlog('debug', 'ensureDependencies returned', { elapsedMs: Date.now() - bootstrapStartTime });\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 importStart = Date.now();\nconst { runMCPServer } = await import('./server.js');\nlog('debug', 'Server module loaded', { elapsedMs: Date.now() - importStart });\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
|
@@ -241,6 +241,7 @@ interface IndexingConfig {
|
|
|
241
241
|
readonly chunkSize: number;
|
|
242
242
|
readonly chunkOverlap: number;
|
|
243
243
|
readonly ignorePatterns: readonly string[];
|
|
244
|
+
readonly prependPath: boolean;
|
|
244
245
|
readonly maxFileSizeBytes: number;
|
|
245
246
|
}
|
|
246
247
|
interface SearchConfig {
|
|
@@ -256,6 +257,12 @@ interface ServerConfig {
|
|
|
256
257
|
readonly port: number;
|
|
257
258
|
readonly host: string;
|
|
258
259
|
}
|
|
260
|
+
interface RerankerConfig {
|
|
261
|
+
readonly enabled: boolean;
|
|
262
|
+
readonly model: string;
|
|
263
|
+
readonly topK: number;
|
|
264
|
+
readonly returnK: number;
|
|
265
|
+
}
|
|
259
266
|
interface AppConfig {
|
|
260
267
|
readonly version: number;
|
|
261
268
|
readonly dataDir: string;
|
|
@@ -264,6 +271,7 @@ interface AppConfig {
|
|
|
264
271
|
readonly search: SearchConfig;
|
|
265
272
|
readonly crawl: CrawlConfig;
|
|
266
273
|
readonly server: ServerConfig;
|
|
274
|
+
readonly reranker: RerankerConfig;
|
|
267
275
|
}
|
|
268
276
|
|
|
269
277
|
declare class ConfigService {
|
|
@@ -496,6 +504,22 @@ declare class LanceStore {
|
|
|
496
504
|
score: number;
|
|
497
505
|
metadata: DocumentMetadata;
|
|
498
506
|
}>>;
|
|
507
|
+
/**
|
|
508
|
+
* Get all documents from a store (for training data generation).
|
|
509
|
+
* Returns documents in batches to avoid memory issues with large stores.
|
|
510
|
+
*/
|
|
511
|
+
getAllDocuments(storeId: StoreId, options?: {
|
|
512
|
+
limit?: number;
|
|
513
|
+
offset?: number;
|
|
514
|
+
}): Promise<Array<{
|
|
515
|
+
id: DocumentId;
|
|
516
|
+
content: string;
|
|
517
|
+
metadata: DocumentMetadata;
|
|
518
|
+
}>>;
|
|
519
|
+
/**
|
|
520
|
+
* Count total documents in a store.
|
|
521
|
+
*/
|
|
522
|
+
countDocuments(storeId: StoreId): Promise<number>;
|
|
499
523
|
deleteStore(storeId: StoreId): Promise<void>;
|
|
500
524
|
close(): void;
|
|
501
525
|
/**
|
|
@@ -508,12 +532,31 @@ declare class LanceStore {
|
|
|
508
532
|
private getTable;
|
|
509
533
|
}
|
|
510
534
|
|
|
535
|
+
/**
|
|
536
|
+
* Optional details for enhanced progress reporting.
|
|
537
|
+
* All fields are optional - consumers use what they need.
|
|
538
|
+
*/
|
|
539
|
+
interface ProgressDetails {
|
|
540
|
+
/** Current file being processed (basename) */
|
|
541
|
+
currentFile?: string;
|
|
542
|
+
/** Milliseconds elapsed since operation start */
|
|
543
|
+
elapsedMs?: number;
|
|
544
|
+
/** Throughput for ETA calculation */
|
|
545
|
+
filesPerSecond?: number;
|
|
546
|
+
/** Store-level progress for multi-store operations */
|
|
547
|
+
storeProgress?: {
|
|
548
|
+
current: number;
|
|
549
|
+
total: number;
|
|
550
|
+
storeName: string;
|
|
551
|
+
};
|
|
552
|
+
}
|
|
511
553
|
interface ProgressEvent {
|
|
512
554
|
type: 'start' | 'progress' | 'complete' | 'error';
|
|
513
555
|
current: number;
|
|
514
556
|
total: number;
|
|
515
557
|
message: string;
|
|
516
|
-
details
|
|
558
|
+
/** Enhanced details - optional, existing consumers can ignore */
|
|
559
|
+
details?: ProgressDetails;
|
|
517
560
|
}
|
|
518
561
|
type ProgressCallback = (event: ProgressEvent) => void;
|
|
519
562
|
|
|
@@ -702,6 +745,7 @@ interface IndexOptions {
|
|
|
702
745
|
concurrency?: number;
|
|
703
746
|
manifestService?: ManifestService;
|
|
704
747
|
ignorePatterns?: readonly string[];
|
|
748
|
+
prependPath?: boolean;
|
|
705
749
|
maxFileSizeBytes?: number;
|
|
706
750
|
}
|
|
707
751
|
interface IncrementalIndexResult extends IndexResult {
|
|
@@ -720,6 +764,7 @@ declare class IndexService {
|
|
|
720
764
|
private readonly concurrency;
|
|
721
765
|
private readonly ignoreDirs;
|
|
722
766
|
private readonly ignoreFilePatterns;
|
|
767
|
+
private readonly prependPath;
|
|
723
768
|
private readonly maxFileSizeBytes;
|
|
724
769
|
constructor(lanceStore: LanceStore, embeddingEngine: EmbeddingEngine, options?: IndexOptions);
|
|
725
770
|
indexStore(store: Store, onProgress?: ProgressCallback): Promise<Result<IndexResult>>;
|
|
@@ -767,6 +812,71 @@ declare class IndexService {
|
|
|
767
812
|
private isInternalImplementation;
|
|
768
813
|
}
|
|
769
814
|
|
|
815
|
+
interface RerankerCandidate {
|
|
816
|
+
readonly id: string;
|
|
817
|
+
readonly content: string;
|
|
818
|
+
readonly score: number;
|
|
819
|
+
}
|
|
820
|
+
interface RerankerResult {
|
|
821
|
+
readonly id: string;
|
|
822
|
+
readonly originalScore: number;
|
|
823
|
+
readonly rerankerScore: number;
|
|
824
|
+
}
|
|
825
|
+
interface RerankerOutput {
|
|
826
|
+
readonly results: readonly RerankerResult[];
|
|
827
|
+
readonly timeMs: number;
|
|
828
|
+
}
|
|
829
|
+
declare class RerankerService {
|
|
830
|
+
private model;
|
|
831
|
+
private tokenizer;
|
|
832
|
+
private initPromise;
|
|
833
|
+
private disposed;
|
|
834
|
+
private readonly config;
|
|
835
|
+
constructor(config: RerankerConfig);
|
|
836
|
+
/**
|
|
837
|
+
* Guard against use-after-dispose
|
|
838
|
+
*/
|
|
839
|
+
private assertNotDisposed;
|
|
840
|
+
/**
|
|
841
|
+
* Check if reranking is enabled
|
|
842
|
+
*/
|
|
843
|
+
isEnabled(): boolean;
|
|
844
|
+
/**
|
|
845
|
+
* Initialize the reranker model (concurrency-safe).
|
|
846
|
+
* Multiple concurrent calls will share the same initialization promise.
|
|
847
|
+
*/
|
|
848
|
+
initialize(): Promise<void>;
|
|
849
|
+
/**
|
|
850
|
+
* Rerank candidates by scoring query-document pairs with the cross-encoder.
|
|
851
|
+
* Returns results sorted by reranker score (descending).
|
|
852
|
+
*/
|
|
853
|
+
rerank(query: string, candidates: readonly RerankerCandidate[]): Promise<RerankerOutput>;
|
|
854
|
+
/**
|
|
855
|
+
* Score a single query-document pair using the cross-encoder.
|
|
856
|
+
*/
|
|
857
|
+
private scoreQueryDocPair;
|
|
858
|
+
/**
|
|
859
|
+
* Check if the reranker is initialized.
|
|
860
|
+
*/
|
|
861
|
+
isInitialized(): boolean;
|
|
862
|
+
/**
|
|
863
|
+
* Check if this service has been disposed.
|
|
864
|
+
*/
|
|
865
|
+
isDisposed(): boolean;
|
|
866
|
+
/**
|
|
867
|
+
* Reset the service to uninitialized state, allowing reuse after disposal.
|
|
868
|
+
*/
|
|
869
|
+
reset(): Promise<void>;
|
|
870
|
+
/**
|
|
871
|
+
* Log aggregate reranker debug stats. Only meaningful when BK_DEBUG_RERANKER=1.
|
|
872
|
+
*/
|
|
873
|
+
static logDebugStats(): void;
|
|
874
|
+
/**
|
|
875
|
+
* Dispose the reranker to free resources.
|
|
876
|
+
*/
|
|
877
|
+
dispose(): Promise<void>;
|
|
878
|
+
}
|
|
879
|
+
|
|
770
880
|
type SearchMode = 'vector' | 'fts' | 'hybrid';
|
|
771
881
|
/**
|
|
772
882
|
* Search intent hints for context-aware ranking.
|
|
@@ -839,6 +949,8 @@ interface SearchResult {
|
|
|
839
949
|
readonly frameworkBoost: number;
|
|
840
950
|
readonly urlKeywordBoost: number;
|
|
841
951
|
readonly pathKeywordBoost: number;
|
|
952
|
+
readonly depthBoost: number;
|
|
953
|
+
readonly entryPointBoost: number;
|
|
842
954
|
readonly rawVectorScore?: number;
|
|
843
955
|
} | undefined;
|
|
844
956
|
}
|
|
@@ -852,16 +964,18 @@ interface SearchResponse {
|
|
|
852
964
|
readonly timeMs: number;
|
|
853
965
|
readonly confidence?: SearchConfidence | undefined;
|
|
854
966
|
readonly maxRawScore?: number | undefined;
|
|
967
|
+
readonly rerankTimeMs?: number | undefined;
|
|
855
968
|
}
|
|
856
969
|
|
|
857
970
|
declare class SearchService {
|
|
858
971
|
private readonly lanceStore;
|
|
859
972
|
private readonly codeUnitService;
|
|
860
973
|
private readonly codeGraphService;
|
|
974
|
+
private readonly rerankerService;
|
|
861
975
|
private readonly graphCache;
|
|
862
976
|
private readonly searchConfig;
|
|
863
977
|
private readonly unsubscribeCacheInvalidation;
|
|
864
|
-
constructor(lanceStore: LanceStore, codeGraphService?: CodeGraphService, searchConfig?: SearchConfig);
|
|
978
|
+
constructor(lanceStore: LanceStore, codeGraphService?: CodeGraphService, searchConfig?: SearchConfig, rerankerService?: RerankerService);
|
|
865
979
|
/**
|
|
866
980
|
* Clean up resources (unsubscribe from events).
|
|
867
981
|
* Call this when destroying the service.
|
|
@@ -929,6 +1043,21 @@ declare class SearchService {
|
|
|
929
1043
|
* This helps queries like "dispatcher" rank async_dispatcher.py higher.
|
|
930
1044
|
*/
|
|
931
1045
|
private getPathKeywordBoost;
|
|
1046
|
+
/**
|
|
1047
|
+
* Get a depth-based score multiplier, gated by query intent.
|
|
1048
|
+
* Root-level files (depth 0) are boosted for how-to and conceptual queries
|
|
1049
|
+
* where high-level docs/READMEs are most relevant.
|
|
1050
|
+
* Returns 1.0 (no-op) for implementation/debugging/comparison intents
|
|
1051
|
+
* to avoid disturbing candidate ordering before reranker.
|
|
1052
|
+
*/
|
|
1053
|
+
private getDepthBoost;
|
|
1054
|
+
/**
|
|
1055
|
+
* Get an entry-point score multiplier, gated by query intent.
|
|
1056
|
+
* Entry-point files (index.ts, main.py, etc.) are boosted for how-to
|
|
1057
|
+
* and implementation queries where API surfaces are most relevant.
|
|
1058
|
+
* Returns 1.0 (no-op) for debugging/comparison/conceptual intents.
|
|
1059
|
+
*/
|
|
1060
|
+
private getEntryPointBoost;
|
|
932
1061
|
/**
|
|
933
1062
|
* Get a score multiplier based on framework context.
|
|
934
1063
|
* If query mentions a framework, boost results from that framework's files.
|
|
@@ -966,25 +1095,21 @@ declare class SearchService {
|
|
|
966
1095
|
* When stores are created, this service ensures the project's .gitignore
|
|
967
1096
|
* is updated to:
|
|
968
1097
|
* - Ignore the .bluera/ data directory (not committed)
|
|
969
|
-
* - Allow committing config
|
|
970
|
-
*
|
|
971
|
-
* Uses glob-style patterns (`.bluera/*`) for multi-plugin safety and
|
|
972
|
-
* managed `BEGIN`/`END` section markers for clean upgrades.
|
|
1098
|
+
* - Allow committing .bluera/bluera-knowledge/stores.config.json (for team sharing)
|
|
973
1099
|
*/
|
|
974
1100
|
declare class GitignoreService {
|
|
975
1101
|
private readonly gitignorePath;
|
|
976
1102
|
constructor(projectRoot: string);
|
|
977
1103
|
/**
|
|
978
|
-
* Check if all required patterns are
|
|
1104
|
+
* Check if all required patterns are present in .gitignore
|
|
979
1105
|
*/
|
|
980
1106
|
hasRequiredPatterns(): Promise<boolean>;
|
|
981
1107
|
/**
|
|
982
1108
|
* Ensure required .gitignore patterns are present.
|
|
983
1109
|
*
|
|
984
1110
|
* - Creates .gitignore if it doesn't exist
|
|
985
|
-
* -
|
|
986
|
-
* -
|
|
987
|
-
* - Persists cleanup even when no patterns are missing
|
|
1111
|
+
* - Appends missing patterns if .gitignore exists
|
|
1112
|
+
* - Does nothing if all patterns are already present
|
|
988
1113
|
*
|
|
989
1114
|
* @returns Object with updated flag and descriptive message
|
|
990
1115
|
*/
|
package/dist/mcp/server.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createMCPServer,
|
|
3
3
|
runMCPServer
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-AEXFPA57.js";
|
|
5
|
+
import "../chunk-B335UOU7.js";
|
|
6
6
|
import "../chunk-CLIMKLTW.js";
|
|
7
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-N3XYMAU3.js";
|
|
8
8
|
import "../chunk-DGUM43GV.js";
|
|
9
9
|
export {
|
|
10
10
|
createMCPServer,
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
IntelligentCrawler
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-KCI4U6FH.js";
|
|
5
5
|
import {
|
|
6
6
|
JobService,
|
|
7
7
|
createLogger,
|
|
8
8
|
createServices,
|
|
9
9
|
destroyServices,
|
|
10
10
|
shutdownLogger
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-B335UOU7.js";
|
|
12
12
|
import {
|
|
13
13
|
createDocumentId,
|
|
14
14
|
createStoreId
|
|
15
15
|
} from "../chunk-CLIMKLTW.js";
|
|
16
|
-
import "../chunk-
|
|
16
|
+
import "../chunk-N3XYMAU3.js";
|
|
17
17
|
import "../chunk-DGUM43GV.js";
|
|
18
18
|
|
|
19
19
|
// src/workers/background-worker-cli.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bluera-knowledge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"description": "CLI tool for managing knowledge stores with semantic search",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,6 +40,14 @@
|
|
|
40
40
|
"release:patch": "commit-and-tag-version --release-as patch && git push --follow-tags",
|
|
41
41
|
"release:minor": "commit-and-tag-version --release-as minor && git push --follow-tags",
|
|
42
42
|
"release:major": "commit-and-tag-version --release-as major && git push --follow-tags",
|
|
43
|
+
"bench:search": "bun run benchmarks/search/benchkit/run-bench.ts",
|
|
44
|
+
"bench:compare": "bun run benchmarks/search/benchkit/compare.ts",
|
|
45
|
+
"bench:smoke": "bun run bench:search --dataset smoke-v1 --driver service",
|
|
46
|
+
"models:download": "bun run scripts/download-models.ts",
|
|
47
|
+
"models:list": "bun run scripts/download-models.ts --list",
|
|
48
|
+
"training:generate": "bun run training/generate-queries.ts",
|
|
49
|
+
"training:negatives": "bun run training/mine-negatives.ts",
|
|
50
|
+
"training:validate": "bun run training/validate.ts",
|
|
43
51
|
"validate:npm": "./scripts/validate-npm-release.sh",
|
|
44
52
|
"validate:local": "./scripts/validate-local.sh",
|
|
45
53
|
"gh:status": "gh run list --limit 5",
|
|
@@ -73,6 +81,7 @@
|
|
|
73
81
|
"LICENSE"
|
|
74
82
|
],
|
|
75
83
|
"devDependencies": {
|
|
84
|
+
"@anthropic-ai/sdk": "^0.72.1",
|
|
76
85
|
"@eslint/js": "^9.39.2",
|
|
77
86
|
"@types/babel__core": "^7.20.5",
|
|
78
87
|
"@types/babel__traverse": "^7.28.0",
|
|
@@ -94,7 +103,8 @@
|
|
|
94
103
|
"tsx": "^4.21.0",
|
|
95
104
|
"typescript": "^5.9.3",
|
|
96
105
|
"typescript-eslint": "^8.52.0",
|
|
97
|
-
"vitest": "^4.0.16"
|
|
106
|
+
"vitest": "^4.0.16",
|
|
107
|
+
"yaml": "^2.8.2"
|
|
98
108
|
},
|
|
99
109
|
"dependencies": {
|
|
100
110
|
"@babel/parser": "^7.28.5",
|
|
@@ -119,7 +129,6 @@
|
|
|
119
129
|
"pino": "^10.1.0",
|
|
120
130
|
"pino-roll": "^4.0.0",
|
|
121
131
|
"playwright": "^1.58.0",
|
|
122
|
-
"slurp-ai": "^1.0.6",
|
|
123
132
|
"turndown": "^7.2.2",
|
|
124
133
|
"turndown-plugin-gfm": "^1.0.2",
|
|
125
134
|
"zod": "^4.3.5"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/services/watch.service.ts","../src/utils/ignore-patterns.ts","../src/utils/model-validation.ts"],"sourcesContent":["import { watch, type FSWatcher } from 'chokidar';\nimport { normalizeGlobPatterns } from '../utils/ignore-patterns.js';\nimport { validateStoreModelCompatibility } from '../utils/model-validation.js';\nimport type { IndexService } from './index.service.js';\nimport type { EmbeddingEngine } from '../db/embeddings.js';\nimport type { LanceStore } from '../db/lance.js';\nimport type { FileStore, RepoStore } from '../types/store.js';\n\nexport interface WatchServiceOptions {\n ignorePatterns?: readonly string[];\n /** Current embedding model ID for compatibility validation */\n currentModelId?: string;\n}\n\nexport class WatchService {\n private readonly watchers: Map<string, FSWatcher> = new Map();\n private readonly pendingTimeouts: Map<string, NodeJS.Timeout> = new Map();\n private readonly indexService: IndexService;\n private readonly lanceStore: LanceStore;\n private readonly embeddings: EmbeddingEngine;\n private readonly ignorePatterns: readonly string[];\n private readonly currentModelId: string | undefined;\n\n constructor(\n indexService: IndexService,\n lanceStore: LanceStore,\n embeddings: EmbeddingEngine,\n options: WatchServiceOptions = {}\n ) {\n this.indexService = indexService;\n this.lanceStore = lanceStore;\n this.embeddings = embeddings;\n // Use shared utility to normalize patterns to glob format with defaults\n this.ignorePatterns = normalizeGlobPatterns(options.ignorePatterns ?? []);\n this.currentModelId = options.currentModelId;\n }\n\n async watch(\n store: FileStore | RepoStore,\n debounceMs: number,\n onReindex: (() => void) | undefined,\n onError: (error: Error) => void\n ): Promise<void> {\n if (this.watchers.has(store.id)) {\n return Promise.resolve(); // Already watching\n }\n\n let timeout: NodeJS.Timeout | null = null;\n\n const watcher = watch(store.path, {\n ignored: [...this.ignorePatterns],\n persistent: true,\n ignoreInitial: true,\n });\n\n const reindexHandler = (): void => {\n if (timeout) clearTimeout(timeout);\n timeout = setTimeout(() => {\n this.pendingTimeouts.delete(store.id);\n void (async (): Promise<void> => {\n try {\n // Validate model compatibility before incremental indexing\n // If currentModelId is set, check that store was indexed with same model\n if (this.currentModelId !== undefined) {\n validateStoreModelCompatibility(store, { currentModelId: this.currentModelId });\n }\n\n this.lanceStore.setDimensions(await this.embeddings.ensureDimensions());\n await this.lanceStore.initialize(store.id);\n\n // Try incremental indexing first if available, fall back to full indexing\n let useFullReindex = true;\n if (typeof this.indexService.indexStoreIncremental === 'function') {\n const incrementalResult = await this.indexService.indexStoreIncremental(store);\n if (incrementalResult.success) {\n useFullReindex = false;\n }\n }\n\n if (useFullReindex) {\n const fullResult = await this.indexService.indexStore(store);\n if (!fullResult.success) {\n onError(fullResult.error);\n return;\n }\n }\n\n onReindex?.();\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e));\n onError(error);\n }\n })();\n }, debounceMs);\n this.pendingTimeouts.set(store.id, timeout);\n };\n\n watcher.on('all', reindexHandler);\n\n watcher.on('error', (e) => {\n const error = e instanceof Error ? e : new Error(String(e));\n onError(error);\n });\n\n this.watchers.set(store.id, watcher);\n return Promise.resolve();\n }\n\n async unwatch(storeId: string): Promise<void> {\n // Clear any pending timeout to prevent timer leak\n const pendingTimeout = this.pendingTimeouts.get(storeId);\n if (pendingTimeout) {\n clearTimeout(pendingTimeout);\n this.pendingTimeouts.delete(storeId);\n }\n\n const watcher = this.watchers.get(storeId);\n if (watcher) {\n await watcher.close();\n this.watchers.delete(storeId);\n }\n }\n\n async unwatchAll(): Promise<void> {\n for (const [id] of this.watchers) {\n await this.unwatch(id);\n }\n }\n}\n","/**\n * Unified ignore pattern handling for consistent behavior across IndexService and WatchService.\n *\n * Pattern normalization ensures the same config patterns work identically whether used\n * for fs.readdir scanning (IndexService) or chokidar watching (WatchService).\n */\n\n/** Default directories to always ignore */\nexport const DEFAULT_IGNORE_DIRS = ['node_modules', '.git', '.bluera', 'dist', 'build'] as const;\n\n/**\n * Normalize patterns to standard glob format for chokidar and micromatch.\n *\n * Transformations:\n * - 'node_modules' → '** /node_modules/**' (directory anywhere in tree)\n * - 'node_modules/**' → '** /node_modules/**' (explicit directory pattern)\n * - '*.min.js' → '**\\/*.min.js' (extension pattern anywhere)\n * - '** /foo/**' → unchanged (already in glob format)\n *\n * @param patterns - User-provided patterns from config\n * @param includeDefaults - Whether to include DEFAULT_IGNORE_DIRS (default: true)\n */\nexport function normalizeGlobPatterns(\n patterns: readonly string[],\n includeDefaults = true\n): string[] {\n const result: string[] = [];\n\n // Add defaults first\n if (includeDefaults) {\n for (const dir of DEFAULT_IGNORE_DIRS) {\n result.push(`**/${dir}/**`);\n }\n }\n\n // Process user patterns\n for (const pattern of patterns) {\n if (pattern.startsWith('**/') && pattern.endsWith('/**')) {\n // Already in glob format\n result.push(pattern);\n } else if (pattern.endsWith('/**')) {\n // Directory pattern: 'foo/**' → '**/foo/**'\n result.push(`**/${pattern}`);\n } else if (pattern.startsWith('*.')) {\n // Extension pattern: '*.min.js' → '**/*.min.js'\n result.push(`**/${pattern}`);\n } else if (!pattern.includes('/') && !pattern.includes('*')) {\n // Simple directory name: 'node_modules' → '**/node_modules/**'\n result.push(`**/${pattern}/**`);\n } else {\n // Keep as-is (might be a specific path pattern)\n result.push(pattern);\n }\n }\n\n return result;\n}\n\n/**\n * Parsed patterns optimized for fs.readdir scanning.\n */\nexport interface ScanningPatterns {\n /** Directory names to skip during traversal (e.g., 'node_modules', '.git') */\n dirs: Set<string>;\n /** Predicate functions to test if a filename should be ignored (e.g., for '*.min.js') */\n fileMatchers: Array<(filename: string) => boolean>;\n}\n\n/**\n * Parse patterns into structures optimized for fs.readdir filtering.\n *\n * This is more efficient than glob matching for directory traversal since\n * it allows early termination when encountering ignored directories.\n *\n * @param patterns - User-provided patterns from config\n * @param includeDefaults - Whether to include DEFAULT_IGNORE_DIRS (default: true)\n */\nexport function parseIgnorePatternsForScanning(\n patterns: readonly string[],\n includeDefaults = true\n): ScanningPatterns {\n const dirs = new Set<string>();\n const fileMatchers: Array<(filename: string) => boolean> = [];\n\n // Add defaults first\n if (includeDefaults) {\n for (const dir of DEFAULT_IGNORE_DIRS) {\n dirs.add(dir);\n }\n }\n\n // Process user patterns\n for (const pattern of patterns) {\n if (pattern.startsWith('**/') && pattern.endsWith('/**')) {\n // Glob format: '**/node_modules/**' → extract 'node_modules'\n const inner = pattern.slice(3, -3);\n if (!inner.includes('/') && !inner.includes('*')) {\n dirs.add(inner);\n }\n } else if (pattern.endsWith('/**')) {\n // Directory pattern: 'node_modules/**' → 'node_modules'\n dirs.add(pattern.slice(0, -3));\n } else if (pattern.startsWith('*.')) {\n // Extension pattern: '*.min.js' → matches files ending with '.min.js'\n const ext = pattern.slice(1); // Remove leading '*'\n fileMatchers.push((filename) => filename.endsWith(ext));\n } else if (!pattern.includes('/') && !pattern.includes('*')) {\n // Simple directory name: 'node_modules' → treat as directory\n dirs.add(pattern);\n }\n // Note: Complex patterns like 'src/**/*.test.ts' are not supported for scanning\n // They would require full glob matching which defeats the purpose of fast scanning\n }\n\n return { dirs, fileMatchers };\n}\n","/**\n * Model Compatibility Validation\n *\n * Guards against searching or incrementally indexing stores with mismatched embedding models.\n * Ensures stores are only queried with the same model they were indexed with.\n */\n\nimport type { Store } from '../types/store.js';\n\nexport interface ModelValidationContext {\n currentModelId: string;\n}\n\n/**\n * Validates that a store's embedding model matches the current configuration.\n *\n * @throws Error if store was indexed with a different model or has no model tracking\n */\nexport function validateStoreModelCompatibility(store: Store, ctx: ModelValidationContext): void {\n // Stores without modelId (schemaVersion < 2) must be reindexed\n if (!store.modelId) {\n throw new Error(\n `Store \"${store.name}\" has no model tracking (schema v1). ` +\n `Reindex required: /bluera-knowledge:index ${store.name}`\n );\n }\n\n if (store.modelId !== ctx.currentModelId) {\n throw new Error(\n `Model mismatch: Store \"${store.name}\" was indexed with \"${store.modelId}\", ` +\n `but current config uses \"${ctx.currentModelId}\". ` +\n `Reindex required: /bluera-knowledge:index ${store.name}`\n );\n }\n}\n\n/**\n * Check if a store's model matches the current configuration without throwing.\n *\n * @returns Object with compatibility status and details\n */\nexport function checkStoreModelCompatibility(\n store: Store,\n ctx: ModelValidationContext\n): {\n compatible: boolean;\n modelId: string | undefined;\n reason?: string;\n} {\n if (!store.modelId) {\n return {\n compatible: false,\n modelId: undefined,\n reason: 'Store has no model tracking (schema v1)',\n };\n }\n\n if (store.modelId !== ctx.currentModelId) {\n return {\n compatible: false,\n modelId: store.modelId,\n reason: `Indexed with different model: ${store.modelId}`,\n };\n }\n\n return {\n compatible: true,\n modelId: store.modelId,\n };\n}\n"],"mappings":"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","names":[]}
|