bluera-knowledge 0.28.0 → 0.29.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 CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
4
4
 
5
+ ## [0.29.0](https://github.com/blueraai/bluera-knowledge/compare/v0.28.0...v0.29.0) (2026-02-20)
6
+
7
+
8
+ ### Features
9
+
10
+ * search infrastructure, benchmark framework, and model registry ([285ff2f](https://github.com/blueraai/bluera-knowledge/commit/285ff2f5574c4d53b61b31e84fdec43553364e98))
11
+ * training pipeline, evaluation gate, and experiment docs ([d90b395](https://github.com/blueraai/bluera-knowledge/commit/d90b395a330f4ab09ac6d71db77d659c415aa87d))
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * **config:** wire BK_MODEL env var override in ConfigService.load() ([be56426](https://github.com/blueraai/bluera-knowledge/commit/be564263176410c3eb1441bf85c4fdce48ddc7c4))
17
+ * **mcp:** prevent browser postinstall from crashing bootstrap ([e27fe02](https://github.com/blueraai/bluera-knowledge/commit/e27fe021bdb34c8ca5b8bf93720a176435e7973c))
18
+
19
+ ## [0.28.1](https://github.com/blueraai/bluera-knowledge/compare/v0.28.0...v0.28.1) (2026-02-12)
20
+
5
21
  ## [0.28.0](https://github.com/blueraai/bluera-knowledge/compare/v0.27.3...v0.28.0) (2026-02-10)
6
22
 
7
23
 
package/README.md CHANGED
@@ -452,18 +452,200 @@ Combine canonical library code with project-specific patterns:
452
452
 
453
453
  ## 🔧 Troubleshooting
454
454
 
455
- Run `/bluera-knowledge:doctor` for quick diagnostics (works even when MCP is broken).
456
-
457
- **Common issues:** See [docs/troubleshooting.md](docs/troubleshooting.md) for solutions to:
458
- - Command not found or not recognized
459
- - MCP server failures
460
- - Web crawling issues
461
- - Search returning no results
462
- - Model mismatch errors
463
- - Native module compilation (Node.js v24)
464
- - Linux build tool requirements
465
- - Slow indexing
466
- - Log viewing and debugging
455
+ ### Quick Diagnostics
456
+
457
+ Run `/bluera-knowledge:doctor` to diagnose common issues. This checks:
458
+ - Build tools (make/gcc) - required for native modules
459
+ - Node.js installation
460
+ - Plugin dependencies (node_modules)
461
+ - MCP wrapper installation
462
+ - Python 3 (optional, for embeddings)
463
+ - Playwright browser (optional, for web crawling)
464
+
465
+ Works even when MCP is broken (uses Bash tool directly).
466
+
467
+ <details>
468
+ <summary><b>❌ Command not found or not recognized</b></summary>
469
+
470
+ Ensure the plugin is installed and enabled:
471
+
472
+ ```bash
473
+ /plugin list
474
+ /plugin enable bluera-knowledge
475
+ ```
476
+
477
+ If the plugin isn't listed, install it:
478
+
479
+ ```bash
480
+ /plugin marketplace add blueraai/bluera-marketplace
481
+ /plugin install bluera-knowledge@bluera
482
+ ```
483
+ </details>
484
+
485
+ <details>
486
+ <summary><b>🔌 MCP server shows as "failed" in /plugin</b></summary>
487
+
488
+ If the MCP server shows as failed after installation:
489
+
490
+ 1. **Run `/bluera-knowledge:doctor`** - This diagnoses the most common issues
491
+ 2. **Restart Claude Code** - MCP servers require a restart to initialize
492
+ 3. **Check logs:** Run `/logs errors` to see recent errors or `/logs module bootstrap` for startup logs
493
+ 4. **Check status:** Run `/mcp` to see connection status
494
+ 5. **Reinstall:** Try `/plugin uninstall bluera-knowledge` then `/plugin install bluera-knowledge@bluera`
495
+
496
+ **Common MCP failure causes:**
497
+
498
+ | Symptom | Cause | Fix |
499
+ |---------|-------|-----|
500
+ | `npm ERR! ERESOLVE` in logs | Peer dependency conflict | Fixed in v0.22.6+ with npm flag |
501
+ | Old plugin version running | Multiple cached versions | Fixed in v0.22.7+ (version sorting) |
502
+ | `make not found` | Missing build tools | Install `build-essential` (Linux) |
503
+ | Compilation errors on Node 24 | V8 API changes | Use Node.js v20.x or v22.x |
504
+
505
+ If the issue persists, check that Claude Code is v2.0.65 or later (earlier versions had MCP loading bugs).
506
+ </details>
507
+
508
+ <details>
509
+ <summary><b>🌐 Web crawling fails</b></summary>
510
+
511
+ Check Playwright browser installation:
512
+
513
+ ```bash
514
+ npx playwright install chromium
515
+ ```
516
+
517
+ The plugin attempts to auto-install Playwright browsers on first use, but manual installation may be needed in some environments.
518
+ </details>
519
+
520
+ <details>
521
+ <summary><b>🔍 Search returns no results</b></summary>
522
+
523
+ 1. Verify store exists: `/bluera-knowledge:stores`
524
+ 2. Check store is indexed: `/bluera-knowledge:index <store-name>`
525
+ 3. Try broader search terms
526
+ 4. Verify you're searching the correct store with `--stores=<name>`
527
+ </details>
528
+
529
+ <details>
530
+ <summary><b>⚠️ "Model mismatch" error</b></summary>
531
+
532
+ This error occurs when a store was indexed with a different embedding model than the current configuration. As of v0.20+, stores are indexed with `bge-small-en-v1.5` (previously `all-MiniLM-L6-v2`).
533
+
534
+ **Solution:** Reindex the affected store:
535
+
536
+ ```bash
537
+ /bluera-knowledge:index <store-name>
538
+ ```
539
+
540
+ **Check model status for all stores:**
541
+
542
+ ```bash
543
+ # Via MCP execute command
544
+ execute stores:check-models
545
+ ```
546
+
547
+ This lists all stores with their embedding model and flags any that need reindexing.
548
+ </details>
549
+
550
+ <details>
551
+ <summary><b>❓ "Store not found" error</b></summary>
552
+
553
+ List all stores to see available names and IDs:
554
+
555
+ ```bash
556
+ /bluera-knowledge:stores
557
+ ```
558
+
559
+ Use the exact store name or ID shown in the table.
560
+ </details>
561
+
562
+ <details>
563
+ <summary><b>🔨 Native module compilation fails (Node.js v24)</b></summary>
564
+
565
+ tree-sitter and lancedb require native module compilation. Node.js v24 introduced V8 API changes that break these modules.
566
+
567
+ **Solution:** Use Node.js v20.x or v22.x (LTS versions):
568
+
569
+ ```bash
570
+ # Using nvm
571
+ nvm install 22
572
+ nvm use 22
573
+ ```
574
+
575
+ Run `/bluera-knowledge:doctor` to verify your environment.
576
+ </details>
577
+
578
+ <details>
579
+ <summary><b>🐧 Linux: "make not found" or build errors</b></summary>
580
+
581
+ Native modules require build tools:
582
+
583
+ ```bash
584
+ # Debian/Ubuntu
585
+ sudo apt install build-essential
586
+
587
+ # Fedora/RHEL
588
+ sudo dnf groupinstall "Development Tools"
589
+ ```
590
+
591
+ Then restart Claude Code for auto-setup to complete.
592
+ </details>
593
+
594
+ <details>
595
+ <summary><b>⏱️ Indexing is slow or fails</b></summary>
596
+
597
+ Large repositories (10,000+ files) take longer to index. If indexing fails:
598
+
599
+ 1. Check available disk space
600
+ 2. Ensure the source repository/folder is accessible
601
+ 3. For repo stores, verify git is installed: `git --version`
602
+ 4. Check for network connectivity (for repo stores)
603
+ 5. Check logs for errors: `/logs errors` or `/logs search "index"`
604
+ </details>
605
+
606
+ <details>
607
+ <summary><b>🤖 "Claude CLI not found" during crawl</b></summary>
608
+
609
+ This means intelligent crawling is unavailable. The crawler will automatically use simple BFS mode instead.
610
+
611
+ To enable intelligent crawling with `--crawl` and `--extract`:
612
+ 1. Install Claude Code: https://claude.com/code
613
+ 2. Ensure `claude` command is in PATH: `which claude`
614
+
615
+ Simple mode still crawls effectively—it just doesn't use AI to select which pages to crawl or extract specific content.
616
+ </details>
617
+
618
+ <details>
619
+ <summary><b>📋 How to view logs for debugging</b></summary>
620
+
621
+ The plugin logs all MCP server operations to `.bluera/bluera-knowledge/logs/app.log` (relative to project root).
622
+
623
+ **View logs using the `/logs` command:**
624
+
625
+ ```bash
626
+ /logs # Watch logs in real-time (tail -f)
627
+ /logs view 50 # View last 50 log entries
628
+ /logs errors # Show only error-level logs
629
+ /logs module mcp-store # Filter by module (mcp-server, mcp-store, mcp-execute, mcp-job, mcp-sync, bootstrap)
630
+ /logs search "pattern" # Search for a pattern
631
+ ```
632
+
633
+ **Log modules:**
634
+ - `bootstrap` - MCP server startup and dependency installation
635
+ - `mcp-server` - Core MCP server operations
636
+ - `mcp-store` - Store create/list/delete operations
637
+ - `mcp-search` - Search queries and results
638
+ - `mcp-execute` - Meta-tool command execution
639
+ - `mcp-job` - Background job status
640
+ - `mcp-sync` - Store sync operations
641
+
642
+ **Manual access:**
643
+ ```bash
644
+ tail -f .bluera/bluera-knowledge/logs/app.log
645
+ ```
646
+
647
+ Logs are JSON formatted (NDJSON) and can be processed with `jq` for pretty-printing.
648
+ </details>
467
649
 
468
650
  ---
469
651
 
@@ -645,7 +827,6 @@ This ensures:
645
827
  | [Commands Reference](docs/commands.md) | All slash commands with parameters and examples |
646
828
  | [Crawler Architecture](docs/crawler-architecture.md) | How the intelligent web crawler works |
647
829
  | [Token Efficiency](docs/token-efficiency.md) | How BK reduces token consumption vs web search |
648
- | [Troubleshooting](docs/troubleshooting.md) | Common issues and solutions |
649
830
  | [CONTRIBUTING](CONTRIBUTING.md) | Development setup, testing, and release process |
650
831
 
651
832
  ---
@@ -2,13 +2,83 @@
2
2
  import { watch } from "chokidar";
3
3
 
4
4
  // src/utils/ignore-patterns.ts
5
- var DEFAULT_IGNORE_DIRS = ["node_modules", ".git", ".bluera", "dist", "build"];
5
+ var DEFAULT_IGNORE_DIRS = [
6
+ // Version control
7
+ ".git",
8
+ ".svn",
9
+ ".hg",
10
+ ".bzr",
11
+ // Package managers & dependencies
12
+ "node_modules",
13
+ "bower_components",
14
+ "jspm_packages",
15
+ "vendor",
16
+ // Build outputs
17
+ "dist",
18
+ "build",
19
+ "out",
20
+ "target",
21
+ // Python
22
+ "__pycache__",
23
+ ".venv",
24
+ "venv",
25
+ ".tox",
26
+ ".mypy_cache",
27
+ ".ruff_cache",
28
+ // Testing & coverage
29
+ ".pytest_cache",
30
+ ".nyc_output",
31
+ "coverage",
32
+ "htmlcov",
33
+ // IDE/editor
34
+ ".idea",
35
+ ".vscode",
36
+ ".vs",
37
+ ".fleet",
38
+ // Framework caches
39
+ ".next",
40
+ ".nuxt",
41
+ ".svelte-kit",
42
+ ".parcel-cache",
43
+ ".turbo",
44
+ // Project-specific
45
+ ".bluera"
46
+ ];
47
+ var DEFAULT_IGNORE_FILE_PATTERNS = [
48
+ // Lock files — conservative set (largest offenders only)
49
+ "package-lock.json",
50
+ "yarn.lock",
51
+ "pnpm-lock.yaml",
52
+ "bun.lockb",
53
+ // Source maps
54
+ "*.map",
55
+ // Test snapshots
56
+ "*.snap",
57
+ // TypeScript build info
58
+ "*.tsbuildinfo",
59
+ // Temp/backup
60
+ "*.tmp",
61
+ "*.temp",
62
+ "*.swp",
63
+ "*.bak",
64
+ "*.orig",
65
+ // OS artifacts
66
+ ".DS_Store",
67
+ "Thumbs.db"
68
+ ];
6
69
  function normalizeGlobPatterns(patterns, includeDefaults = true) {
7
70
  const result = [];
8
71
  if (includeDefaults) {
9
72
  for (const dir of DEFAULT_IGNORE_DIRS) {
10
73
  result.push(`**/${dir}/**`);
11
74
  }
75
+ for (const pattern of DEFAULT_IGNORE_FILE_PATTERNS) {
76
+ if (pattern.startsWith("*")) {
77
+ result.push(`**/${pattern}`);
78
+ } else {
79
+ result.push(`**/${pattern}`);
80
+ }
81
+ }
12
82
  }
13
83
  for (const pattern of patterns) {
14
84
  if (pattern.startsWith("**/") && pattern.endsWith("/**")) {
@@ -32,6 +102,14 @@ function parseIgnorePatternsForScanning(patterns, includeDefaults = true) {
32
102
  for (const dir of DEFAULT_IGNORE_DIRS) {
33
103
  dirs.add(dir);
34
104
  }
105
+ for (const pattern of DEFAULT_IGNORE_FILE_PATTERNS) {
106
+ if (pattern.startsWith("*")) {
107
+ const ext = pattern.slice(1);
108
+ fileMatchers.push((filename) => filename.endsWith(ext));
109
+ } else {
110
+ fileMatchers.push((filename) => filename === pattern);
111
+ }
112
+ }
35
113
  }
36
114
  for (const pattern of patterns) {
37
115
  if (pattern.startsWith("**/") && pattern.endsWith("/**")) {
@@ -178,4 +256,4 @@ export {
178
256
  checkStoreModelCompatibility,
179
257
  WatchService
180
258
  };
181
- //# sourceMappingURL=chunk-H25AEF47.js.map
259
+ //# sourceMappingURL=chunk-7JTPAQFO.js.map
@@ -0,0 +1 @@
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 = [\n // Version control\n '.git',\n '.svn',\n '.hg',\n '.bzr',\n // Package managers & dependencies\n 'node_modules',\n 'bower_components',\n 'jspm_packages',\n 'vendor',\n // Build outputs\n 'dist',\n 'build',\n 'out',\n 'target',\n // Python\n '__pycache__',\n '.venv',\n 'venv',\n '.tox',\n '.mypy_cache',\n '.ruff_cache',\n // Testing & coverage\n '.pytest_cache',\n '.nyc_output',\n 'coverage',\n 'htmlcov',\n // IDE/editor\n '.idea',\n '.vscode',\n '.vs',\n '.fleet',\n // Framework caches\n '.next',\n '.nuxt',\n '.svelte-kit',\n '.parcel-cache',\n '.turbo',\n // Project-specific\n '.bluera',\n] as const;\n\n/**\n * Default file patterns to always ignore.\n * Exact names (no wildcard) match by equality; glob patterns (*.ext) match by extension.\n *\n * Note: Language-specific lock files (Pipfile.lock, poetry.lock, Gemfile.lock,\n * composer.lock, Cargo.lock, go.sum) are intentionally excluded from defaults —\n * they may provide useful dependency context for some stores.\n * Users can add them via per-store excludeGlobs.\n */\nexport const DEFAULT_IGNORE_FILE_PATTERNS = [\n // Lock files — conservative set (largest offenders only)\n 'package-lock.json',\n 'yarn.lock',\n 'pnpm-lock.yaml',\n 'bun.lockb',\n // Source maps\n '*.map',\n // Test snapshots\n '*.snap',\n // TypeScript build info\n '*.tsbuildinfo',\n // Temp/backup\n '*.tmp',\n '*.temp',\n '*.swp',\n '*.bak',\n '*.orig',\n // OS artifacts\n '.DS_Store',\n 'Thumbs.db',\n] 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 // Add default file patterns as file globs (not directory globs)\n for (const pattern of DEFAULT_IGNORE_FILE_PATTERNS) {\n if (pattern.startsWith('*')) {\n // Glob pattern: '*.map' → '**/*.map'\n result.push(`**/${pattern}`);\n } else {\n // Exact filename: 'package-lock.json' → '**/package-lock.json'\n result.push(`**/${pattern}`);\n }\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 // Add default file patterns via dedicated exact-file matcher path\n // (do NOT feed through the directory-name parser which misclassifies no-wildcard patterns)\n for (const pattern of DEFAULT_IGNORE_FILE_PATTERNS) {\n if (pattern.startsWith('*')) {\n // Glob pattern: '*.map' → endsWith matcher\n const ext = pattern.slice(1); // Remove leading '*'\n fileMatchers.push((filename) => filename.endsWith(ext));\n } else {\n // Exact filename: 'package-lock.json' → equality check\n fileMatchers.push((filename) => filename === pattern);\n }\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":[]}
@@ -2,7 +2,7 @@ import {
2
2
  createLogger,
3
3
  summarizePayload,
4
4
  truncateForLog
5
- } from "./chunk-WP2GERAJ.js";
5
+ } from "./chunk-U27UECDZ.js";
6
6
 
7
7
  // src/crawl/intelligent-crawler.ts
8
8
  import { EventEmitter } from "events";
@@ -916,4 +916,4 @@ export {
916
916
  getCrawlStrategy,
917
917
  IntelligentCrawler
918
918
  };
919
- //# sourceMappingURL=chunk-BYLIDCWD.js.map
919
+ //# sourceMappingURL=chunk-H465AZXC.js.map
@@ -9,10 +9,10 @@ import {
9
9
  isRepoStoreDefinition,
10
10
  isWebStoreDefinition,
11
11
  summarizePayload
12
- } from "./chunk-WP2GERAJ.js";
12
+ } from "./chunk-U27UECDZ.js";
13
13
  import {
14
14
  checkStoreModelCompatibility
15
- } from "./chunk-H25AEF47.js";
15
+ } from "./chunk-7JTPAQFO.js";
16
16
 
17
17
  // src/mcp/server.ts
18
18
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -2040,21 +2040,26 @@ var handleSearch = async (args, context) => {
2040
2040
  };
2041
2041
  })
2042
2042
  );
2043
- const responseJson = JSON.stringify(
2044
- {
2045
- results: enhancedResults,
2046
- totalResults: results.totalResults,
2047
- mode: results.mode,
2048
- timeMs: results.timeMs,
2049
- confidence: results.confidence,
2050
- maxRawScore: results.maxRawScore
2051
- },
2052
- null,
2053
- 2
2054
- );
2043
+ const responseData = {
2044
+ results: enhancedResults,
2045
+ totalResults: results.totalResults,
2046
+ mode: results.mode,
2047
+ timeMs: results.timeMs
2048
+ };
2049
+ if (results.confidence !== void 0) {
2050
+ responseData["confidence"] = results.confidence;
2051
+ }
2052
+ if (results.maxRawScore !== void 0) {
2053
+ responseData["maxRawScore"] = results.maxRawScore;
2054
+ }
2055
+ if (results.rerankTimeMs !== void 0) {
2056
+ responseData["rerankTimeMs"] = results.rerankTimeMs;
2057
+ }
2058
+ const responseJson = JSON.stringify(responseData, null, 2);
2055
2059
  const responseTokens = estimateTokens(responseJson);
2056
2060
  const confidenceInfo = results.confidence !== void 0 ? ` | Confidence: ${results.confidence}` : "";
2057
- const header = `Search: "${validated.query}" | Results: ${String(results.totalResults)} | ${formatTokenCount(responseTokens)} tokens | ${String(results.timeMs)}ms${confidenceInfo}
2061
+ const rerankInfo = results.rerankTimeMs !== void 0 ? ` | Rerank: ${String(results.rerankTimeMs)}ms` : "";
2062
+ const header = `Search: "${validated.query}" | Results: ${String(results.totalResults)} | ${formatTokenCount(responseTokens)} tokens | ${String(results.timeMs)}ms${confidenceInfo}${rerankInfo}
2058
2063
 
2059
2064
  `;
2060
2065
  logger8.info(
@@ -2402,4 +2407,4 @@ export {
2402
2407
  createMCPServer,
2403
2408
  runMCPServer
2404
2409
  };
2405
- //# sourceMappingURL=chunk-UXT3BCAH.js.map
2410
+ //# sourceMappingURL=chunk-T7J5RB6F.js.map