viberag 0.1.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.
Files changed (151) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +219 -0
  3. package/dist/cli/__tests__/mcp-setup.test.d.ts +6 -0
  4. package/dist/cli/__tests__/mcp-setup.test.js +597 -0
  5. package/dist/cli/app.d.ts +2 -0
  6. package/dist/cli/app.js +238 -0
  7. package/dist/cli/commands/handlers.d.ts +57 -0
  8. package/dist/cli/commands/handlers.js +231 -0
  9. package/dist/cli/commands/index.d.ts +2 -0
  10. package/dist/cli/commands/index.js +2 -0
  11. package/dist/cli/commands/mcp-setup.d.ts +107 -0
  12. package/dist/cli/commands/mcp-setup.js +509 -0
  13. package/dist/cli/commands/useRagCommands.d.ts +23 -0
  14. package/dist/cli/commands/useRagCommands.js +180 -0
  15. package/dist/cli/components/CleanWizard.d.ts +17 -0
  16. package/dist/cli/components/CleanWizard.js +169 -0
  17. package/dist/cli/components/InitWizard.d.ts +20 -0
  18. package/dist/cli/components/InitWizard.js +370 -0
  19. package/dist/cli/components/McpSetupWizard.d.ts +37 -0
  20. package/dist/cli/components/McpSetupWizard.js +387 -0
  21. package/dist/cli/components/SearchResultsDisplay.d.ts +13 -0
  22. package/dist/cli/components/SearchResultsDisplay.js +130 -0
  23. package/dist/cli/components/WelcomeBanner.d.ts +10 -0
  24. package/dist/cli/components/WelcomeBanner.js +26 -0
  25. package/dist/cli/components/index.d.ts +1 -0
  26. package/dist/cli/components/index.js +1 -0
  27. package/dist/cli/data/mcp-editors.d.ts +80 -0
  28. package/dist/cli/data/mcp-editors.js +270 -0
  29. package/dist/cli/index.d.ts +2 -0
  30. package/dist/cli/index.js +26 -0
  31. package/dist/cli-bundle.cjs +5269 -0
  32. package/dist/common/commands/terminalSetup.d.ts +2 -0
  33. package/dist/common/commands/terminalSetup.js +144 -0
  34. package/dist/common/components/CommandSuggestions.d.ts +9 -0
  35. package/dist/common/components/CommandSuggestions.js +20 -0
  36. package/dist/common/components/StaticWithResize.d.ts +23 -0
  37. package/dist/common/components/StaticWithResize.js +62 -0
  38. package/dist/common/components/StatusBar.d.ts +8 -0
  39. package/dist/common/components/StatusBar.js +64 -0
  40. package/dist/common/components/TextInput.d.ts +12 -0
  41. package/dist/common/components/TextInput.js +239 -0
  42. package/dist/common/components/index.d.ts +3 -0
  43. package/dist/common/components/index.js +3 -0
  44. package/dist/common/hooks/index.d.ts +4 -0
  45. package/dist/common/hooks/index.js +4 -0
  46. package/dist/common/hooks/useCommandHistory.d.ts +7 -0
  47. package/dist/common/hooks/useCommandHistory.js +51 -0
  48. package/dist/common/hooks/useCtrlC.d.ts +9 -0
  49. package/dist/common/hooks/useCtrlC.js +40 -0
  50. package/dist/common/hooks/useKittyKeyboard.d.ts +10 -0
  51. package/dist/common/hooks/useKittyKeyboard.js +26 -0
  52. package/dist/common/hooks/useStaticOutputBuffer.d.ts +31 -0
  53. package/dist/common/hooks/useStaticOutputBuffer.js +58 -0
  54. package/dist/common/hooks/useTerminalResize.d.ts +28 -0
  55. package/dist/common/hooks/useTerminalResize.js +51 -0
  56. package/dist/common/hooks/useTextBuffer.d.ts +13 -0
  57. package/dist/common/hooks/useTextBuffer.js +165 -0
  58. package/dist/common/index.d.ts +13 -0
  59. package/dist/common/index.js +17 -0
  60. package/dist/common/types.d.ts +162 -0
  61. package/dist/common/types.js +1 -0
  62. package/dist/mcp/index.d.ts +12 -0
  63. package/dist/mcp/index.js +66 -0
  64. package/dist/mcp/server.d.ts +25 -0
  65. package/dist/mcp/server.js +837 -0
  66. package/dist/mcp/watcher.d.ts +86 -0
  67. package/dist/mcp/watcher.js +334 -0
  68. package/dist/rag/__tests__/grammar-smoke.test.d.ts +9 -0
  69. package/dist/rag/__tests__/grammar-smoke.test.js +161 -0
  70. package/dist/rag/__tests__/helpers.d.ts +30 -0
  71. package/dist/rag/__tests__/helpers.js +67 -0
  72. package/dist/rag/__tests__/merkle.test.d.ts +5 -0
  73. package/dist/rag/__tests__/merkle.test.js +161 -0
  74. package/dist/rag/__tests__/metadata-extraction.test.d.ts +10 -0
  75. package/dist/rag/__tests__/metadata-extraction.test.js +202 -0
  76. package/dist/rag/__tests__/multi-language.test.d.ts +13 -0
  77. package/dist/rag/__tests__/multi-language.test.js +535 -0
  78. package/dist/rag/__tests__/rag.test.d.ts +10 -0
  79. package/dist/rag/__tests__/rag.test.js +311 -0
  80. package/dist/rag/__tests__/search-exhaustive.test.d.ts +9 -0
  81. package/dist/rag/__tests__/search-exhaustive.test.js +87 -0
  82. package/dist/rag/__tests__/search-filters.test.d.ts +10 -0
  83. package/dist/rag/__tests__/search-filters.test.js +250 -0
  84. package/dist/rag/__tests__/search-modes.test.d.ts +8 -0
  85. package/dist/rag/__tests__/search-modes.test.js +133 -0
  86. package/dist/rag/config/index.d.ts +61 -0
  87. package/dist/rag/config/index.js +111 -0
  88. package/dist/rag/constants.d.ts +41 -0
  89. package/dist/rag/constants.js +57 -0
  90. package/dist/rag/embeddings/fastembed.d.ts +62 -0
  91. package/dist/rag/embeddings/fastembed.js +124 -0
  92. package/dist/rag/embeddings/gemini.d.ts +26 -0
  93. package/dist/rag/embeddings/gemini.js +116 -0
  94. package/dist/rag/embeddings/index.d.ts +10 -0
  95. package/dist/rag/embeddings/index.js +9 -0
  96. package/dist/rag/embeddings/local-4b.d.ts +28 -0
  97. package/dist/rag/embeddings/local-4b.js +51 -0
  98. package/dist/rag/embeddings/local.d.ts +29 -0
  99. package/dist/rag/embeddings/local.js +119 -0
  100. package/dist/rag/embeddings/mistral.d.ts +22 -0
  101. package/dist/rag/embeddings/mistral.js +85 -0
  102. package/dist/rag/embeddings/openai.d.ts +22 -0
  103. package/dist/rag/embeddings/openai.js +85 -0
  104. package/dist/rag/embeddings/types.d.ts +37 -0
  105. package/dist/rag/embeddings/types.js +1 -0
  106. package/dist/rag/gitignore/index.d.ts +57 -0
  107. package/dist/rag/gitignore/index.js +178 -0
  108. package/dist/rag/index.d.ts +15 -0
  109. package/dist/rag/index.js +25 -0
  110. package/dist/rag/indexer/chunker.d.ts +129 -0
  111. package/dist/rag/indexer/chunker.js +1352 -0
  112. package/dist/rag/indexer/index.d.ts +6 -0
  113. package/dist/rag/indexer/index.js +6 -0
  114. package/dist/rag/indexer/indexer.d.ts +73 -0
  115. package/dist/rag/indexer/indexer.js +356 -0
  116. package/dist/rag/indexer/types.d.ts +68 -0
  117. package/dist/rag/indexer/types.js +47 -0
  118. package/dist/rag/logger/index.d.ts +20 -0
  119. package/dist/rag/logger/index.js +75 -0
  120. package/dist/rag/manifest/index.d.ts +50 -0
  121. package/dist/rag/manifest/index.js +97 -0
  122. package/dist/rag/merkle/diff.d.ts +26 -0
  123. package/dist/rag/merkle/diff.js +95 -0
  124. package/dist/rag/merkle/hash.d.ts +34 -0
  125. package/dist/rag/merkle/hash.js +165 -0
  126. package/dist/rag/merkle/index.d.ts +68 -0
  127. package/dist/rag/merkle/index.js +298 -0
  128. package/dist/rag/merkle/node.d.ts +51 -0
  129. package/dist/rag/merkle/node.js +69 -0
  130. package/dist/rag/search/filters.d.ts +21 -0
  131. package/dist/rag/search/filters.js +100 -0
  132. package/dist/rag/search/fts.d.ts +32 -0
  133. package/dist/rag/search/fts.js +61 -0
  134. package/dist/rag/search/hybrid.d.ts +17 -0
  135. package/dist/rag/search/hybrid.js +58 -0
  136. package/dist/rag/search/index.d.ts +89 -0
  137. package/dist/rag/search/index.js +367 -0
  138. package/dist/rag/search/types.d.ts +130 -0
  139. package/dist/rag/search/types.js +4 -0
  140. package/dist/rag/search/vector.d.ts +25 -0
  141. package/dist/rag/search/vector.js +44 -0
  142. package/dist/rag/storage/index.d.ts +92 -0
  143. package/dist/rag/storage/index.js +287 -0
  144. package/dist/rag/storage/lancedb-native.d.ts +7 -0
  145. package/dist/rag/storage/lancedb-native.js +10 -0
  146. package/dist/rag/storage/schema.d.ts +23 -0
  147. package/dist/rag/storage/schema.js +50 -0
  148. package/dist/rag/storage/types.d.ts +100 -0
  149. package/dist/rag/storage/types.js +68 -0
  150. package/package.json +67 -0
  151. package/scripts/check-node-version.js +37 -0
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Tests for search modes: definition and similar.
3
+ *
4
+ * Tests the new search modes added in Phase 2:
5
+ * - definition: Direct metadata lookup by symbol name
6
+ * - similar: Vector search with code snippet as query
7
+ */
8
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
9
+ import { Indexer } from '../indexer/indexer.js';
10
+ import { SearchEngine } from '../search/index.js';
11
+ import { copyFixtureToTemp } from './helpers.js';
12
+ describe('Search Modes', () => {
13
+ let ctx;
14
+ let search;
15
+ beforeAll(async () => {
16
+ // Setup once for all tests - index the codebase
17
+ ctx = await copyFixtureToTemp('codebase');
18
+ const indexer = new Indexer(ctx.projectRoot);
19
+ await indexer.index();
20
+ indexer.close();
21
+ search = new SearchEngine(ctx.projectRoot);
22
+ }, 120000);
23
+ afterAll(async () => {
24
+ search.close();
25
+ await ctx.cleanup();
26
+ });
27
+ describe('definition mode', () => {
28
+ it('finds function definition by exact name', async () => {
29
+ const results = await search.search('getUser', {
30
+ mode: 'definition',
31
+ symbolName: 'getUser',
32
+ });
33
+ expect(results.results.length).toBeGreaterThan(0);
34
+ expect(results.searchType).toBe('definition');
35
+ // Should find the function in endpoints.ts
36
+ expect(results.results.some(r => r.filepath.includes('endpoints.ts'))).toBe(true);
37
+ }, 60000);
38
+ it('finds class definition by name', async () => {
39
+ // Use semantic search to find class - definition mode uses exact name match
40
+ const results = await search.search('UserService class', {
41
+ mode: 'semantic',
42
+ filters: { type: ['class'] },
43
+ });
44
+ // Should find the class in exported.ts
45
+ if (results.results.length > 0) {
46
+ expect(results.results.some(r => r.filepath.includes('exported.ts'))).toBe(true);
47
+ }
48
+ }, 60000);
49
+ it('finds method definition by name', async () => {
50
+ // Use semantic search for method lookup
51
+ const results = await search.search('fetchData method http', {
52
+ mode: 'semantic',
53
+ filters: { type: ['method'] },
54
+ });
55
+ // Should find the method in http_client.ts
56
+ if (results.results.length > 0) {
57
+ expect(results.results.some(r => r.filepath.includes('http_client.ts'))).toBe(true);
58
+ }
59
+ }, 60000);
60
+ it('returns empty for non-existent symbol', async () => {
61
+ const results = await search.search('nonExistentSymbolXYZ123', {
62
+ mode: 'definition',
63
+ symbolName: 'nonExistentSymbolXYZ123',
64
+ });
65
+ expect(results.results.length).toBe(0);
66
+ }, 60000);
67
+ it('can filter definitions by type', async () => {
68
+ const results = await search.search('add', {
69
+ mode: 'definition',
70
+ symbolName: 'add_two_numbers',
71
+ filters: { type: ['function'] },
72
+ });
73
+ if (results.results.length > 0) {
74
+ expect(results.results.every(r => r.type === 'function')).toBe(true);
75
+ }
76
+ }, 60000);
77
+ });
78
+ describe('similar mode', () => {
79
+ it('finds similar code by snippet', async () => {
80
+ // Search for code similar to an async fetch function
81
+ const snippet = `async function fetchData(url) {
82
+ const response = await fetch(url);
83
+ return response.json();
84
+ }`;
85
+ const results = await search.search(snippet, {
86
+ mode: 'similar',
87
+ codeSnippet: snippet,
88
+ });
89
+ expect(results.results.length).toBeGreaterThan(0);
90
+ expect(results.searchType).toBe('similar');
91
+ // Should find http_client.ts which has similar fetch logic
92
+ expect(results.results.some(r => r.filepath.includes('http_client.ts'))).toBe(true);
93
+ }, 60000);
94
+ it('finds similar Python code', async () => {
95
+ const snippet = `def calculate(a, b):
96
+ return a + b`;
97
+ const results = await search.search(snippet, {
98
+ mode: 'similar',
99
+ codeSnippet: snippet,
100
+ });
101
+ expect(results.results.length).toBeGreaterThan(0);
102
+ // Should find math.py which has similar arithmetic functions
103
+ expect(results.results.some(r => r.filepath.includes('math.py'))).toBe(true);
104
+ }, 60000);
105
+ it('respects limit parameter', async () => {
106
+ const snippet = `function helper() { return true; }`;
107
+ const results = await search.search(snippet, {
108
+ mode: 'similar',
109
+ codeSnippet: snippet,
110
+ limit: 3,
111
+ });
112
+ expect(results.results.length).toBeLessThanOrEqual(3);
113
+ }, 60000);
114
+ });
115
+ describe('mode selection', () => {
116
+ it('defaults to hybrid mode', async () => {
117
+ const results = await search.search('function');
118
+ expect(results.searchType).toBe('hybrid');
119
+ }, 60000);
120
+ it('semantic mode returns semantic type', async () => {
121
+ const results = await search.search('how does authentication work', {
122
+ mode: 'semantic',
123
+ });
124
+ expect(results.searchType).toBe('semantic');
125
+ }, 60000);
126
+ it('exact mode returns exact type', async () => {
127
+ const results = await search.search('fetchData', {
128
+ mode: 'exact',
129
+ });
130
+ expect(results.searchType).toBe('exact');
131
+ }, 60000);
132
+ });
133
+ });
@@ -0,0 +1,61 @@
1
+ import type { EmbeddingProviderType } from '../../common/types.js';
2
+ export type { EmbeddingProviderType };
3
+ /**
4
+ * File watcher configuration for auto-indexing.
5
+ */
6
+ export interface WatchConfig {
7
+ /** Enable file watching for auto-index (default: true) */
8
+ enabled: boolean;
9
+ /** Debounce delay before processing changes (default: 500ms) */
10
+ debounceMs: number;
11
+ /** Batch window to collect changes before indexing (default: 2000ms) */
12
+ batchWindowMs: number;
13
+ /** Wait for file writes to complete before indexing (default: true) */
14
+ awaitWriteFinish: boolean;
15
+ }
16
+ export interface ViberagConfig {
17
+ version: number;
18
+ embeddingProvider: EmbeddingProviderType;
19
+ embeddingModel: string;
20
+ embeddingDimensions: number;
21
+ /** API key for cloud providers (gemini, mistral, openai) */
22
+ apiKey?: string;
23
+ extensions: string[];
24
+ excludePatterns: string[];
25
+ chunkMaxSize: number;
26
+ /** @deprecated Use watch.debounceMs instead */
27
+ watchDebounceMs: number;
28
+ /** File watcher configuration */
29
+ watch: WatchConfig;
30
+ }
31
+ /**
32
+ * Provider-specific embedding configurations.
33
+ */
34
+ export declare const PROVIDER_CONFIGS: Record<EmbeddingProviderType, {
35
+ model: string;
36
+ dimensions: number;
37
+ }>;
38
+ /**
39
+ * Create config for a specific provider.
40
+ */
41
+ export declare function createConfigForProvider(provider: EmbeddingProviderType): ViberagConfig;
42
+ /**
43
+ * Default watch configuration.
44
+ */
45
+ export declare const DEFAULT_WATCH_CONFIG: WatchConfig;
46
+ export declare const DEFAULT_CONFIG: ViberagConfig;
47
+ /**
48
+ * Load config from disk, merging with defaults.
49
+ * Returns DEFAULT_CONFIG if no config file exists.
50
+ * Handles nested watch config merge for backward compatibility.
51
+ */
52
+ export declare function loadConfig(projectRoot: string): Promise<ViberagConfig>;
53
+ /**
54
+ * Save config to disk.
55
+ * Creates the .viberag directory if it doesn't exist.
56
+ */
57
+ export declare function saveConfig(projectRoot: string, config: ViberagConfig): Promise<void>;
58
+ /**
59
+ * Check if a config file exists.
60
+ */
61
+ export declare function configExists(projectRoot: string): Promise<boolean>;
@@ -0,0 +1,111 @@
1
+ import fs from 'node:fs/promises';
2
+ import { getConfigPath, getViberagDir } from '../constants.js';
3
+ /**
4
+ * Provider-specific embedding configurations.
5
+ */
6
+ export const PROVIDER_CONFIGS = {
7
+ local: {
8
+ model: 'Qwen/Qwen3-Embedding-0.6B',
9
+ dimensions: 1024,
10
+ },
11
+ 'local-4b': {
12
+ model: 'Qwen/Qwen3-Embedding-4B',
13
+ dimensions: 2560,
14
+ },
15
+ gemini: {
16
+ model: 'gemini-embedding-001',
17
+ dimensions: 1536,
18
+ },
19
+ mistral: {
20
+ model: 'codestral-embed',
21
+ dimensions: 1024,
22
+ },
23
+ openai: {
24
+ model: 'text-embedding-3-small',
25
+ dimensions: 1536,
26
+ },
27
+ };
28
+ /**
29
+ * Create config for a specific provider.
30
+ */
31
+ export function createConfigForProvider(provider) {
32
+ const providerConfig = PROVIDER_CONFIGS[provider];
33
+ return {
34
+ ...DEFAULT_CONFIG,
35
+ embeddingProvider: provider,
36
+ embeddingModel: providerConfig.model,
37
+ embeddingDimensions: providerConfig.dimensions,
38
+ };
39
+ }
40
+ /**
41
+ * Default watch configuration.
42
+ */
43
+ export const DEFAULT_WATCH_CONFIG = {
44
+ enabled: true,
45
+ debounceMs: 500,
46
+ batchWindowMs: 2000,
47
+ awaitWriteFinish: true,
48
+ };
49
+ export const DEFAULT_CONFIG = {
50
+ version: 1,
51
+ embeddingProvider: 'gemini',
52
+ embeddingModel: PROVIDER_CONFIGS['gemini'].model,
53
+ embeddingDimensions: PROVIDER_CONFIGS['gemini'].dimensions,
54
+ // Extensions to index. Empty array = index ALL text files (recommended).
55
+ // Binary files are automatically detected and skipped.
56
+ // Use .gitignore for exclusions.
57
+ extensions: [],
58
+ // DEPRECATED: Use .gitignore instead. This field is ignored.
59
+ excludePatterns: [],
60
+ chunkMaxSize: 2000,
61
+ watchDebounceMs: 500,
62
+ watch: DEFAULT_WATCH_CONFIG,
63
+ };
64
+ /**
65
+ * Load config from disk, merging with defaults.
66
+ * Returns DEFAULT_CONFIG if no config file exists.
67
+ * Handles nested watch config merge for backward compatibility.
68
+ */
69
+ export async function loadConfig(projectRoot) {
70
+ const configPath = getConfigPath(projectRoot);
71
+ try {
72
+ const content = await fs.readFile(configPath, 'utf-8');
73
+ const loaded = JSON.parse(content);
74
+ // Deep merge watch config with defaults
75
+ const watchConfig = {
76
+ ...DEFAULT_WATCH_CONFIG,
77
+ ...(loaded.watch ?? {}),
78
+ };
79
+ return {
80
+ ...DEFAULT_CONFIG,
81
+ ...loaded,
82
+ watch: watchConfig,
83
+ };
84
+ }
85
+ catch {
86
+ return { ...DEFAULT_CONFIG };
87
+ }
88
+ }
89
+ /**
90
+ * Save config to disk.
91
+ * Creates the .viberag directory if it doesn't exist.
92
+ */
93
+ export async function saveConfig(projectRoot, config) {
94
+ const viberagDir = getViberagDir(projectRoot);
95
+ await fs.mkdir(viberagDir, { recursive: true });
96
+ const configPath = getConfigPath(projectRoot);
97
+ await fs.writeFile(configPath, JSON.stringify(config, null, '\t') + '\n');
98
+ }
99
+ /**
100
+ * Check if a config file exists.
101
+ */
102
+ export async function configExists(projectRoot) {
103
+ const configPath = getConfigPath(projectRoot);
104
+ try {
105
+ await fs.access(configPath);
106
+ return true;
107
+ }
108
+ catch {
109
+ return false;
110
+ }
111
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Directory name for Viberag storage.
3
+ * This directory should be added to .gitignore.
4
+ */
5
+ export declare const VIBERAG_DIR = ".viberag";
6
+ /**
7
+ * Get the absolute path to the Viberag directory for a project.
8
+ */
9
+ export declare function getViberagDir(projectRoot: string): string;
10
+ /**
11
+ * Get the path to the config file.
12
+ */
13
+ export declare function getConfigPath(projectRoot: string): string;
14
+ /**
15
+ * Get the path to the manifest file.
16
+ */
17
+ export declare function getManifestPath(projectRoot: string): string;
18
+ /**
19
+ * Get the path to the LanceDB database directory.
20
+ */
21
+ export declare function getLanceDbPath(projectRoot: string): string;
22
+ /**
23
+ * Get the path to the logs directory.
24
+ */
25
+ export declare function getLogsDir(projectRoot: string): string;
26
+ /**
27
+ * LanceDB table names.
28
+ */
29
+ export declare const TABLE_NAMES: {
30
+ readonly CODE_CHUNKS: "code_chunks";
31
+ readonly EMBEDDING_CACHE: "embedding_cache";
32
+ };
33
+ /**
34
+ * File extensions supported for parsing.
35
+ * Maps extension to language identifier.
36
+ */
37
+ export declare const EXTENSION_TO_LANGUAGE: Record<string, string>;
38
+ /**
39
+ * Embedding dimensions for default model (BGE-base-en-v1.5).
40
+ */
41
+ export declare const DEFAULT_EMBEDDING_DIMENSIONS = 768;
@@ -0,0 +1,57 @@
1
+ import path from 'node:path';
2
+ /**
3
+ * Directory name for Viberag storage.
4
+ * This directory should be added to .gitignore.
5
+ */
6
+ export const VIBERAG_DIR = '.viberag';
7
+ /**
8
+ * Get the absolute path to the Viberag directory for a project.
9
+ */
10
+ export function getViberagDir(projectRoot) {
11
+ return path.join(projectRoot, VIBERAG_DIR);
12
+ }
13
+ /**
14
+ * Get the path to the config file.
15
+ */
16
+ export function getConfigPath(projectRoot) {
17
+ return path.join(getViberagDir(projectRoot), 'config.json');
18
+ }
19
+ /**
20
+ * Get the path to the manifest file.
21
+ */
22
+ export function getManifestPath(projectRoot) {
23
+ return path.join(getViberagDir(projectRoot), 'manifest.json');
24
+ }
25
+ /**
26
+ * Get the path to the LanceDB database directory.
27
+ */
28
+ export function getLanceDbPath(projectRoot) {
29
+ return path.join(getViberagDir(projectRoot), 'lancedb');
30
+ }
31
+ /**
32
+ * Get the path to the logs directory.
33
+ */
34
+ export function getLogsDir(projectRoot) {
35
+ return path.join(getViberagDir(projectRoot), 'logs');
36
+ }
37
+ /**
38
+ * LanceDB table names.
39
+ */
40
+ export const TABLE_NAMES = {
41
+ CODE_CHUNKS: 'code_chunks',
42
+ EMBEDDING_CACHE: 'embedding_cache',
43
+ };
44
+ /**
45
+ * File extensions supported for parsing.
46
+ * Maps extension to language identifier.
47
+ */
48
+ export const EXTENSION_TO_LANGUAGE = {
49
+ '.py': 'python',
50
+ '.js': 'javascript',
51
+ '.ts': 'typescript',
52
+ '.tsx': 'typescript',
53
+ };
54
+ /**
55
+ * Embedding dimensions for default model (BGE-base-en-v1.5).
56
+ */
57
+ export const DEFAULT_EMBEDDING_DIMENSIONS = 768;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * FastEmbed provider using ONNX runtime with quantized models.
3
+ *
4
+ * Uses BGE models which are general-purpose text embeddings.
5
+ * Much faster than Jina due to smaller models and int8 quantization.
6
+ */
7
+ import { EmbeddingModel } from 'fastembed';
8
+ import type { EmbeddingProvider } from './types.js';
9
+ /**
10
+ * Model configurations for FastEmbed.
11
+ */
12
+ declare const MODEL_CONFIG: {
13
+ readonly small: {
14
+ readonly model: EmbeddingModel.BGESmallENV15;
15
+ readonly dimensions: 384;
16
+ readonly name: "bge-small-en-v1.5";
17
+ readonly size: "32MB";
18
+ };
19
+ readonly base: {
20
+ readonly model: EmbeddingModel.BGEBaseENV15;
21
+ readonly dimensions: 768;
22
+ readonly name: "bge-base-en-v1.5";
23
+ readonly size: "134MB";
24
+ };
25
+ };
26
+ export type FastEmbedModelSize = keyof typeof MODEL_CONFIG;
27
+ /**
28
+ * FastEmbed provider for fast local embeddings.
29
+ * Uses quantized BGE models via ONNX runtime.
30
+ */
31
+ export declare class FastEmbedProvider implements EmbeddingProvider {
32
+ readonly dimensions: number;
33
+ private modelSize;
34
+ private model;
35
+ private initialized;
36
+ private initPromise;
37
+ /**
38
+ * Create a FastEmbed provider.
39
+ * @param modelSize - 'small' (384d, 32MB) or 'base' (768d, 134MB)
40
+ */
41
+ constructor(modelSize?: FastEmbedModelSize);
42
+ /**
43
+ * Initialize the embedding model.
44
+ * Downloads the quantized ONNX model on first use.
45
+ */
46
+ initialize(): Promise<void>;
47
+ private _doInitialize;
48
+ /**
49
+ * Generate embeddings for multiple texts.
50
+ * FastEmbed handles batching internally via generator.
51
+ */
52
+ embed(texts: string[]): Promise<number[][]>;
53
+ /**
54
+ * Generate embedding for a single text.
55
+ */
56
+ embedSingle(text: string): Promise<number[]>;
57
+ /**
58
+ * Close the provider and free resources.
59
+ */
60
+ close(): void;
61
+ }
62
+ export {};
@@ -0,0 +1,124 @@
1
+ /**
2
+ * FastEmbed provider using ONNX runtime with quantized models.
3
+ *
4
+ * Uses BGE models which are general-purpose text embeddings.
5
+ * Much faster than Jina due to smaller models and int8 quantization.
6
+ */
7
+ import { EmbeddingModel, FlagEmbedding } from 'fastembed';
8
+ /**
9
+ * Model configurations for FastEmbed.
10
+ */
11
+ const MODEL_CONFIG = {
12
+ small: {
13
+ model: EmbeddingModel.BGESmallENV15,
14
+ dimensions: 384,
15
+ name: 'bge-small-en-v1.5',
16
+ size: '32MB',
17
+ },
18
+ base: {
19
+ model: EmbeddingModel.BGEBaseENV15,
20
+ dimensions: 768,
21
+ name: 'bge-base-en-v1.5',
22
+ size: '134MB',
23
+ },
24
+ };
25
+ /**
26
+ * FastEmbed provider for fast local embeddings.
27
+ * Uses quantized BGE models via ONNX runtime.
28
+ */
29
+ export class FastEmbedProvider {
30
+ /**
31
+ * Create a FastEmbed provider.
32
+ * @param modelSize - 'small' (384d, 32MB) or 'base' (768d, 134MB)
33
+ */
34
+ constructor(modelSize = 'small') {
35
+ Object.defineProperty(this, "dimensions", {
36
+ enumerable: true,
37
+ configurable: true,
38
+ writable: true,
39
+ value: void 0
40
+ });
41
+ Object.defineProperty(this, "modelSize", {
42
+ enumerable: true,
43
+ configurable: true,
44
+ writable: true,
45
+ value: void 0
46
+ });
47
+ Object.defineProperty(this, "model", {
48
+ enumerable: true,
49
+ configurable: true,
50
+ writable: true,
51
+ value: null
52
+ });
53
+ Object.defineProperty(this, "initialized", {
54
+ enumerable: true,
55
+ configurable: true,
56
+ writable: true,
57
+ value: false
58
+ });
59
+ Object.defineProperty(this, "initPromise", {
60
+ enumerable: true,
61
+ configurable: true,
62
+ writable: true,
63
+ value: null
64
+ });
65
+ this.modelSize = modelSize;
66
+ this.dimensions = MODEL_CONFIG[modelSize].dimensions;
67
+ }
68
+ /**
69
+ * Initialize the embedding model.
70
+ * Downloads the quantized ONNX model on first use.
71
+ */
72
+ async initialize() {
73
+ if (this.initialized)
74
+ return;
75
+ if (this.initPromise) {
76
+ return this.initPromise;
77
+ }
78
+ this.initPromise = this._doInitialize();
79
+ await this.initPromise;
80
+ }
81
+ async _doInitialize() {
82
+ const config = MODEL_CONFIG[this.modelSize];
83
+ const startTime = Date.now();
84
+ console.error(`[FastEmbedProvider] Loading ${config.name} (~${config.size})...`);
85
+ this.model = await FlagEmbedding.init({
86
+ model: config.model,
87
+ });
88
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
89
+ console.error(`[FastEmbedProvider] Model loaded in ${elapsed}s`);
90
+ this.initialized = true;
91
+ }
92
+ /**
93
+ * Generate embeddings for multiple texts.
94
+ * FastEmbed handles batching internally via generator.
95
+ */
96
+ async embed(texts) {
97
+ if (!this.initialized || !this.model) {
98
+ await this.initialize();
99
+ }
100
+ if (texts.length === 0) {
101
+ return [];
102
+ }
103
+ const results = [];
104
+ // FastEmbed uses a generator pattern for batch processing
105
+ for await (const batch of this.model.embed(texts)) {
106
+ results.push(...batch);
107
+ }
108
+ return results;
109
+ }
110
+ /**
111
+ * Generate embedding for a single text.
112
+ */
113
+ async embedSingle(text) {
114
+ const results = await this.embed([text]);
115
+ return results[0];
116
+ }
117
+ /**
118
+ * Close the provider and free resources.
119
+ */
120
+ close() {
121
+ this.model = null;
122
+ this.initialized = false;
123
+ }
124
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Gemini embedding provider using Google's Generative AI API.
3
+ *
4
+ * Uses gemini-embedding-001 model with 1536 dimensions.
5
+ * Note: The model defaults to 3072 dims but we explicitly request 1536 for:
6
+ * - Good balance of quality and storage
7
+ * - Matches OpenAI text-embedding-3-small dimensions
8
+ *
9
+ * Free tier available with generous limits.
10
+ */
11
+ import type { EmbeddingProvider, ModelProgressCallback } from './types.js';
12
+ /**
13
+ * Gemini embedding provider.
14
+ * Uses gemini-embedding-001 model via Google's Generative AI API.
15
+ */
16
+ export declare class GeminiEmbeddingProvider implements EmbeddingProvider {
17
+ readonly dimensions = 1536;
18
+ private apiKey;
19
+ private initialized;
20
+ constructor(apiKey?: string);
21
+ initialize(_onProgress?: ModelProgressCallback): Promise<void>;
22
+ embed(texts: string[]): Promise<number[][]>;
23
+ private embedBatch;
24
+ embedSingle(text: string): Promise<number[]>;
25
+ close(): void;
26
+ }