viberag 0.3.2 → 0.4.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 (209) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/app.d.ts +3 -0
  3. package/dist/cli/app.js +100 -102
  4. package/dist/cli/commands/handlers.d.ts +8 -6
  5. package/dist/cli/commands/handlers.js +90 -32
  6. package/dist/cli/commands/useCommands.d.ts +20 -0
  7. package/dist/cli/commands/useCommands.js +189 -0
  8. package/dist/cli/commands/useRagCommands.d.ts +2 -5
  9. package/dist/cli/commands/useRagCommands.js +11 -18
  10. package/dist/cli/components/InitWizard.js +66 -27
  11. package/dist/cli/components/McpSetupWizard.js +23 -4
  12. package/dist/cli/components/SlotRow.d.ts +22 -0
  13. package/dist/cli/components/SlotRow.js +55 -0
  14. package/dist/cli/components/StatusBar.d.ts +14 -0
  15. package/dist/cli/components/StatusBar.js +156 -0
  16. package/dist/cli/contexts/DaemonStatusContext.d.ts +38 -0
  17. package/dist/cli/contexts/DaemonStatusContext.js +106 -0
  18. package/dist/cli/hooks/useStatusPolling.d.ts +34 -0
  19. package/dist/cli/hooks/useStatusPolling.js +121 -0
  20. package/dist/cli/store/app/selectors.d.ts +87 -0
  21. package/dist/cli/store/app/selectors.js +28 -0
  22. package/dist/cli/store/app/slice.d.ts +1013 -0
  23. package/dist/cli/store/app/slice.js +112 -0
  24. package/dist/cli/store/hooks.d.ts +22 -0
  25. package/dist/cli/store/hooks.js +17 -0
  26. package/dist/cli/store/store.d.ts +17 -0
  27. package/dist/cli/store/store.js +18 -0
  28. package/dist/cli/store/wizard/selectors.d.ts +115 -0
  29. package/dist/cli/store/wizard/selectors.js +36 -0
  30. package/dist/cli/store/wizard/slice.d.ts +523 -0
  31. package/dist/cli/store/wizard/slice.js +119 -0
  32. package/dist/cli/utils/error-handler.d.ts +55 -0
  33. package/dist/cli/utils/error-handler.js +92 -0
  34. package/dist/client/auto-start.d.ts +42 -0
  35. package/dist/client/auto-start.js +250 -0
  36. package/dist/client/connection.d.ts +48 -0
  37. package/dist/client/connection.js +200 -0
  38. package/dist/client/index.d.ts +93 -0
  39. package/dist/client/index.js +209 -0
  40. package/dist/client/types.d.ts +105 -0
  41. package/dist/client/types.js +7 -0
  42. package/dist/common/components/SlotRow.d.ts +22 -0
  43. package/dist/common/components/SlotRow.js +53 -0
  44. package/dist/common/components/StatusBar.js +82 -31
  45. package/dist/common/types.d.ts +12 -13
  46. package/dist/daemon/handlers.d.ts +15 -0
  47. package/dist/daemon/handlers.js +157 -0
  48. package/dist/daemon/index.d.ts +21 -0
  49. package/dist/daemon/index.js +123 -0
  50. package/dist/daemon/lib/chunker/bounded-channel.d.ts +51 -0
  51. package/dist/daemon/lib/chunker/bounded-channel.js +138 -0
  52. package/dist/daemon/lib/chunker/index.d.ts +135 -0
  53. package/dist/daemon/lib/chunker/index.js +1370 -0
  54. package/dist/daemon/lib/chunker/types.d.ts +77 -0
  55. package/dist/daemon/lib/chunker/types.js +50 -0
  56. package/dist/daemon/lib/config.d.ts +73 -0
  57. package/dist/daemon/lib/config.js +149 -0
  58. package/dist/daemon/lib/constants.d.ts +75 -0
  59. package/dist/daemon/lib/constants.js +114 -0
  60. package/dist/daemon/lib/gitignore.d.ts +57 -0
  61. package/dist/daemon/lib/gitignore.js +246 -0
  62. package/dist/daemon/lib/logger.d.ts +51 -0
  63. package/dist/daemon/lib/logger.js +167 -0
  64. package/dist/daemon/lib/manifest.d.ts +58 -0
  65. package/dist/daemon/lib/manifest.js +116 -0
  66. package/dist/daemon/lib/merkle/diff.d.ts +32 -0
  67. package/dist/daemon/lib/merkle/diff.js +107 -0
  68. package/dist/daemon/lib/merkle/hash.d.ts +40 -0
  69. package/dist/daemon/lib/merkle/hash.js +180 -0
  70. package/dist/daemon/lib/merkle/index.d.ts +71 -0
  71. package/dist/daemon/lib/merkle/index.js +309 -0
  72. package/dist/daemon/lib/merkle/node.d.ts +55 -0
  73. package/dist/daemon/lib/merkle/node.js +82 -0
  74. package/dist/daemon/lifecycle.d.ts +50 -0
  75. package/dist/daemon/lifecycle.js +142 -0
  76. package/dist/daemon/owner.d.ts +175 -0
  77. package/dist/daemon/owner.js +609 -0
  78. package/dist/daemon/protocol.d.ts +100 -0
  79. package/dist/daemon/protocol.js +163 -0
  80. package/dist/daemon/providers/api-utils.d.ts +130 -0
  81. package/dist/daemon/providers/api-utils.js +248 -0
  82. package/dist/daemon/providers/gemini.d.ts +39 -0
  83. package/dist/daemon/providers/gemini.js +205 -0
  84. package/dist/daemon/providers/index.d.ts +14 -0
  85. package/dist/daemon/providers/index.js +14 -0
  86. package/dist/daemon/providers/local-4b.d.ts +28 -0
  87. package/dist/daemon/providers/local-4b.js +51 -0
  88. package/dist/daemon/providers/local.d.ts +36 -0
  89. package/dist/daemon/providers/local.js +166 -0
  90. package/dist/daemon/providers/mistral.d.ts +35 -0
  91. package/dist/daemon/providers/mistral.js +160 -0
  92. package/dist/daemon/providers/mock.d.ts +35 -0
  93. package/dist/daemon/providers/mock.js +69 -0
  94. package/dist/daemon/providers/openai.d.ts +41 -0
  95. package/dist/daemon/providers/openai.js +190 -0
  96. package/dist/daemon/providers/types.d.ts +68 -0
  97. package/dist/daemon/providers/types.js +6 -0
  98. package/dist/daemon/providers/validate.d.ts +30 -0
  99. package/dist/daemon/providers/validate.js +162 -0
  100. package/dist/daemon/server.d.ts +79 -0
  101. package/dist/daemon/server.js +293 -0
  102. package/dist/daemon/services/index.d.ts +11 -0
  103. package/dist/daemon/services/index.js +16 -0
  104. package/dist/daemon/services/indexing.d.ts +117 -0
  105. package/dist/daemon/services/indexing.js +573 -0
  106. package/dist/daemon/services/search/filters.d.ts +21 -0
  107. package/dist/daemon/services/search/filters.js +106 -0
  108. package/dist/daemon/services/search/fts.d.ts +32 -0
  109. package/dist/daemon/services/search/fts.js +61 -0
  110. package/dist/daemon/services/search/hybrid.d.ts +17 -0
  111. package/dist/daemon/services/search/hybrid.js +58 -0
  112. package/dist/daemon/services/search/index.d.ts +108 -0
  113. package/dist/daemon/services/search/index.js +417 -0
  114. package/dist/daemon/services/search/types.d.ts +126 -0
  115. package/dist/daemon/services/search/types.js +4 -0
  116. package/dist/daemon/services/search/vector.d.ts +25 -0
  117. package/dist/daemon/services/search/vector.js +44 -0
  118. package/dist/daemon/services/storage/index.d.ts +110 -0
  119. package/dist/daemon/services/storage/index.js +378 -0
  120. package/dist/daemon/services/storage/schema.d.ts +24 -0
  121. package/dist/daemon/services/storage/schema.js +51 -0
  122. package/dist/daemon/services/storage/types.d.ts +105 -0
  123. package/dist/daemon/services/storage/types.js +71 -0
  124. package/dist/daemon/services/types.d.ts +192 -0
  125. package/dist/daemon/services/types.js +53 -0
  126. package/dist/daemon/services/watcher.d.ts +98 -0
  127. package/dist/daemon/services/watcher.js +386 -0
  128. package/dist/daemon/state.d.ts +119 -0
  129. package/dist/daemon/state.js +161 -0
  130. package/dist/mcp/index.d.ts +1 -1
  131. package/dist/mcp/index.js +44 -60
  132. package/dist/mcp/server.d.ts +10 -14
  133. package/dist/mcp/server.js +75 -74
  134. package/dist/mcp/services/lazy-loader.d.ts +23 -0
  135. package/dist/mcp/services/lazy-loader.js +34 -0
  136. package/dist/mcp/warmup.d.ts +3 -3
  137. package/dist/mcp/warmup.js +39 -40
  138. package/dist/mcp/watcher.d.ts +5 -7
  139. package/dist/mcp/watcher.js +73 -64
  140. package/dist/rag/config/index.d.ts +2 -0
  141. package/dist/rag/constants.d.ts +30 -0
  142. package/dist/rag/constants.js +38 -0
  143. package/dist/rag/embeddings/api-utils.d.ts +121 -0
  144. package/dist/rag/embeddings/api-utils.js +259 -0
  145. package/dist/rag/embeddings/gemini.d.ts +4 -12
  146. package/dist/rag/embeddings/gemini.js +22 -72
  147. package/dist/rag/embeddings/index.d.ts +5 -3
  148. package/dist/rag/embeddings/index.js +5 -2
  149. package/dist/rag/embeddings/local-4b.d.ts +2 -2
  150. package/dist/rag/embeddings/local-4b.js +1 -1
  151. package/dist/rag/embeddings/local.d.ts +10 -3
  152. package/dist/rag/embeddings/local.js +58 -12
  153. package/dist/rag/embeddings/mistral.d.ts +4 -12
  154. package/dist/rag/embeddings/mistral.js +22 -72
  155. package/dist/rag/embeddings/mock.d.ts +35 -0
  156. package/dist/rag/embeddings/mock.js +69 -0
  157. package/dist/rag/embeddings/openai.d.ts +11 -13
  158. package/dist/rag/embeddings/openai.js +47 -75
  159. package/dist/rag/embeddings/types.d.ts +27 -1
  160. package/dist/rag/embeddings/validate.d.ts +9 -1
  161. package/dist/rag/embeddings/validate.js +17 -4
  162. package/dist/rag/index.d.ts +2 -2
  163. package/dist/rag/index.js +1 -1
  164. package/dist/rag/indexer/bounded-channel.d.ts +51 -0
  165. package/dist/rag/indexer/bounded-channel.js +138 -0
  166. package/dist/rag/indexer/indexer.d.ts +4 -14
  167. package/dist/rag/indexer/indexer.js +246 -169
  168. package/dist/rag/indexer/types.d.ts +1 -0
  169. package/dist/rag/logger/index.d.ts +22 -0
  170. package/dist/rag/logger/index.js +78 -1
  171. package/dist/rag/manifest/index.js +1 -2
  172. package/dist/rag/search/index.js +1 -1
  173. package/dist/rag/storage/schema.d.ts +2 -4
  174. package/dist/rag/storage/schema.js +3 -5
  175. package/dist/store/app/selectors.d.ts +87 -0
  176. package/dist/store/app/selectors.js +28 -0
  177. package/dist/store/app/slice.d.ts +1013 -0
  178. package/dist/store/app/slice.js +112 -0
  179. package/dist/store/hooks.d.ts +22 -0
  180. package/dist/store/hooks.js +17 -0
  181. package/dist/store/index.d.ts +12 -0
  182. package/dist/store/index.js +18 -0
  183. package/dist/store/indexing/listeners.d.ts +25 -0
  184. package/dist/store/indexing/listeners.js +46 -0
  185. package/dist/store/indexing/selectors.d.ts +195 -0
  186. package/dist/store/indexing/selectors.js +69 -0
  187. package/dist/store/indexing/slice.d.ts +309 -0
  188. package/dist/store/indexing/slice.js +113 -0
  189. package/dist/store/slot-progress/listeners.d.ts +23 -0
  190. package/dist/store/slot-progress/listeners.js +33 -0
  191. package/dist/store/slot-progress/selectors.d.ts +67 -0
  192. package/dist/store/slot-progress/selectors.js +36 -0
  193. package/dist/store/slot-progress/slice.d.ts +246 -0
  194. package/dist/store/slot-progress/slice.js +70 -0
  195. package/dist/store/store.d.ts +17 -0
  196. package/dist/store/store.js +18 -0
  197. package/dist/store/warmup/selectors.d.ts +109 -0
  198. package/dist/store/warmup/selectors.js +44 -0
  199. package/dist/store/warmup/slice.d.ts +137 -0
  200. package/dist/store/warmup/slice.js +72 -0
  201. package/dist/store/watcher/selectors.d.ts +115 -0
  202. package/dist/store/watcher/selectors.js +52 -0
  203. package/dist/store/watcher/slice.d.ts +269 -0
  204. package/dist/store/watcher/slice.js +100 -0
  205. package/dist/store/wizard/selectors.d.ts +115 -0
  206. package/dist/store/wizard/selectors.js +36 -0
  207. package/dist/store/wizard/slice.d.ts +523 -0
  208. package/dist/store/wizard/slice.js +119 -0
  209. package/package.json +10 -2
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Merkle Diff - Tree comparison for change detection.
3
+ *
4
+ * Compares two Merkle trees to find new, modified, and deleted files.
5
+ * Uses hash comparison for efficient subtree comparison.
6
+ */
7
+ // ============================================================================
8
+ // Factory
9
+ // ============================================================================
10
+ /**
11
+ * Create an empty TreeDiff.
12
+ */
13
+ export function createEmptyDiff() {
14
+ return {
15
+ new: [],
16
+ modified: [],
17
+ deleted: [],
18
+ hasChanges: false,
19
+ };
20
+ }
21
+ // ============================================================================
22
+ // Tree Comparison
23
+ // ============================================================================
24
+ /**
25
+ * Collect all file paths from a node (recursively).
26
+ */
27
+ function collectAllFiles(node, paths) {
28
+ if (node.type === 'file') {
29
+ paths.push(node.path);
30
+ }
31
+ else if (node.children) {
32
+ for (const child of node.children.values()) {
33
+ collectAllFiles(child, paths);
34
+ }
35
+ }
36
+ }
37
+ /**
38
+ * Compare two Merkle nodes and populate the diff.
39
+ */
40
+ function compareNodes(oldNode, newNode, diff) {
41
+ // Quick check: if hashes match, entire subtree unchanged
42
+ if (oldNode.hash === newNode.hash) {
43
+ return;
44
+ }
45
+ // File modified
46
+ if (oldNode.type === 'file' && newNode.type === 'file') {
47
+ diff.modified.push(newNode.path);
48
+ return;
49
+ }
50
+ // Type changed (file→dir or dir→file)
51
+ if (oldNode.type !== newNode.type) {
52
+ collectAllFiles(oldNode, diff.deleted);
53
+ collectAllFiles(newNode, diff.new);
54
+ return;
55
+ }
56
+ // Both directories: compare children
57
+ const oldChildren = oldNode.children ?? new Map();
58
+ const newChildren = newNode.children ?? new Map();
59
+ // Find new entries (in new but not in old)
60
+ for (const [name, child] of newChildren) {
61
+ if (!oldChildren.has(name)) {
62
+ collectAllFiles(child, diff.new);
63
+ }
64
+ }
65
+ // Find deleted entries (in old but not in new)
66
+ for (const [name, child] of oldChildren) {
67
+ if (!newChildren.has(name)) {
68
+ collectAllFiles(child, diff.deleted);
69
+ }
70
+ }
71
+ // Recurse into shared entries
72
+ for (const [name, newChild] of newChildren) {
73
+ const oldChild = oldChildren.get(name);
74
+ if (oldChild) {
75
+ compareNodes(oldChild, newChild, diff);
76
+ }
77
+ }
78
+ }
79
+ /**
80
+ * Compare two Merkle trees and return the differences.
81
+ *
82
+ * @param oldRoot - The previous tree's root node (or null if no previous tree)
83
+ * @param newRoot - The current tree's root node
84
+ * @returns TreeDiff with new, modified, and deleted file paths
85
+ */
86
+ export function compareTrees(oldRoot, newRoot) {
87
+ const diff = createEmptyDiff();
88
+ // No old tree - everything is new
89
+ if (!oldRoot) {
90
+ if (newRoot) {
91
+ collectAllFiles(newRoot, diff.new);
92
+ }
93
+ diff.hasChanges = diff.new.length > 0;
94
+ return diff;
95
+ }
96
+ // No new tree - everything is deleted
97
+ if (!newRoot) {
98
+ collectAllFiles(oldRoot, diff.deleted);
99
+ diff.hasChanges = diff.deleted.length > 0;
100
+ return diff;
101
+ }
102
+ // Both trees exist - compare them
103
+ compareNodes(oldRoot, newRoot, diff);
104
+ diff.hasChanges =
105
+ diff.new.length > 0 || diff.modified.length > 0 || diff.deleted.length > 0;
106
+ return diff;
107
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Merkle Hash - Hashing utilities for Merkle tree construction.
3
+ *
4
+ * Provides functions for computing SHA256 hashes of files,
5
+ * directories, and strings.
6
+ */
7
+ import type { MerkleNode } from './node.js';
8
+ /**
9
+ * Compute SHA256 hash of a file's content.
10
+ */
11
+ export declare function computeFileHash(filepath: string): Promise<string>;
12
+ /**
13
+ * Compute SHA256 hash of a string.
14
+ */
15
+ export declare function computeStringHash(content: string): string;
16
+ /**
17
+ * Compute SHA256 hash of a directory based on its children.
18
+ *
19
+ * Hash = SHA256(sorted child name+hash pairs)
20
+ * Format: "name1:hash1\nname2:hash2\n..."
21
+ */
22
+ export declare function computeDirectoryHash(children: Map<string, MerkleNode>): string;
23
+ /**
24
+ * Check if a file is likely binary based on extension.
25
+ * Falls back to checking for null bytes in the first chunk.
26
+ */
27
+ export declare function isBinaryFile(filepath: string): Promise<boolean>;
28
+ /**
29
+ * Check if a path should be excluded based on patterns.
30
+ *
31
+ * Supported pattern types:
32
+ * - "node_modules" - matches any path containing a "node_modules" segment
33
+ * - "*.pyc" - matches any file ending with .pyc
34
+ * - ".git" - matches any path containing a ".git" segment
35
+ */
36
+ export declare function shouldExclude(relativePath: string, excludePatterns: string[]): boolean;
37
+ /**
38
+ * Check if a file has a supported extension.
39
+ */
40
+ export declare function hasValidExtension(filepath: string, extensions: string[]): boolean;
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Merkle Hash - Hashing utilities for Merkle tree construction.
3
+ *
4
+ * Provides functions for computing SHA256 hashes of files,
5
+ * directories, and strings.
6
+ */
7
+ import { createHash } from 'node:crypto';
8
+ import fs from 'node:fs/promises';
9
+ // ============================================================================
10
+ // Hash Functions
11
+ // ============================================================================
12
+ /**
13
+ * Compute SHA256 hash of a file's content.
14
+ */
15
+ export async function computeFileHash(filepath) {
16
+ const content = await fs.readFile(filepath);
17
+ return createHash('sha256').update(content).digest('hex');
18
+ }
19
+ /**
20
+ * Compute SHA256 hash of a string.
21
+ */
22
+ export function computeStringHash(content) {
23
+ return createHash('sha256').update(content).digest('hex');
24
+ }
25
+ /**
26
+ * Compute SHA256 hash of a directory based on its children.
27
+ *
28
+ * Hash = SHA256(sorted child name+hash pairs)
29
+ * Format: "name1:hash1\nname2:hash2\n..."
30
+ */
31
+ export function computeDirectoryHash(children) {
32
+ // Sort children by name for deterministic hashing
33
+ const sortedNames = [...children.keys()].sort();
34
+ // Build content string from name:hash pairs
35
+ const content = sortedNames
36
+ .map(name => {
37
+ const child = children.get(name);
38
+ return `${name}:${child.hash}`;
39
+ })
40
+ .join('\n');
41
+ return createHash('sha256').update(content).digest('hex');
42
+ }
43
+ // ============================================================================
44
+ // Binary Detection
45
+ // ============================================================================
46
+ /**
47
+ * Known binary file extensions.
48
+ */
49
+ const BINARY_EXTENSIONS = new Set([
50
+ // Images
51
+ '.png',
52
+ '.jpg',
53
+ '.jpeg',
54
+ '.gif',
55
+ '.bmp',
56
+ '.ico',
57
+ '.webp',
58
+ '.svg',
59
+ '.tiff',
60
+ '.tif',
61
+ // Audio/Video
62
+ '.mp3',
63
+ '.mp4',
64
+ '.wav',
65
+ '.avi',
66
+ '.mov',
67
+ '.webm',
68
+ '.flac',
69
+ '.ogg',
70
+ // Archives
71
+ '.zip',
72
+ '.tar',
73
+ '.gz',
74
+ '.bz2',
75
+ '.7z',
76
+ '.rar',
77
+ // Documents
78
+ '.pdf',
79
+ '.doc',
80
+ '.docx',
81
+ '.xls',
82
+ '.xlsx',
83
+ '.ppt',
84
+ '.pptx',
85
+ // Executables
86
+ '.exe',
87
+ '.dll',
88
+ '.so',
89
+ '.dylib',
90
+ '.bin',
91
+ // Fonts
92
+ '.ttf',
93
+ '.otf',
94
+ '.woff',
95
+ '.woff2',
96
+ '.eot',
97
+ // Other
98
+ '.wasm',
99
+ '.node',
100
+ '.pyc',
101
+ '.pyo',
102
+ '.class',
103
+ '.o',
104
+ '.a',
105
+ ]);
106
+ /**
107
+ * Check if a file is likely binary based on extension.
108
+ * Falls back to checking for null bytes in the first chunk.
109
+ */
110
+ export async function isBinaryFile(filepath) {
111
+ // Check extension first (fast path)
112
+ const ext = filepath.slice(filepath.lastIndexOf('.')).toLowerCase();
113
+ if (BINARY_EXTENSIONS.has(ext)) {
114
+ return true;
115
+ }
116
+ // Check for null bytes in first 8KB
117
+ try {
118
+ const handle = await fs.open(filepath, 'r');
119
+ try {
120
+ const buffer = Buffer.alloc(8192);
121
+ const { bytesRead } = await handle.read(buffer, 0, 8192, 0);
122
+ // Check for null bytes (common in binary files)
123
+ for (let i = 0; i < bytesRead; i++) {
124
+ if (buffer[i] === 0) {
125
+ return true;
126
+ }
127
+ }
128
+ return false;
129
+ }
130
+ finally {
131
+ await handle.close();
132
+ }
133
+ }
134
+ catch {
135
+ // If we can't read the file, assume it's not binary
136
+ return false;
137
+ }
138
+ }
139
+ // ============================================================================
140
+ // Path Filtering
141
+ // ============================================================================
142
+ /**
143
+ * Check if a path should be excluded based on patterns.
144
+ *
145
+ * Supported pattern types:
146
+ * - "node_modules" - matches any path containing a "node_modules" segment
147
+ * - "*.pyc" - matches any file ending with .pyc
148
+ * - ".git" - matches any path containing a ".git" segment
149
+ */
150
+ export function shouldExclude(relativePath, excludePatterns) {
151
+ // Split path into segments
152
+ const segments = relativePath.split('/');
153
+ const filename = segments[segments.length - 1] ?? '';
154
+ for (const pattern of excludePatterns) {
155
+ // Glob pattern: *.ext matches files with that extension
156
+ if (pattern.startsWith('*.')) {
157
+ const ext = pattern.slice(1); // ".pyc"
158
+ if (filename.endsWith(ext)) {
159
+ return true;
160
+ }
161
+ continue;
162
+ }
163
+ // Check if any segment matches the pattern exactly
164
+ if (segments.includes(pattern)) {
165
+ return true;
166
+ }
167
+ // Also check if the path starts with the pattern (for top-level exclusions)
168
+ if (relativePath.startsWith(pattern + '/') || relativePath === pattern) {
169
+ return true;
170
+ }
171
+ }
172
+ return false;
173
+ }
174
+ /**
175
+ * Check if a file has a supported extension.
176
+ */
177
+ export function hasValidExtension(filepath, extensions) {
178
+ const ext = filepath.slice(filepath.lastIndexOf('.'));
179
+ return extensions.includes(ext);
180
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Merkle Tree - Efficient codebase change detection.
3
+ *
4
+ * The tree is content-addressed: if a file's content doesn't change,
5
+ * its hash stays the same. Directory hashes are computed from their
6
+ * children's hashes, so unchanged subtrees have unchanged hashes.
7
+ *
8
+ * This enables O(1) comparison of unchanged directories, making
9
+ * incremental indexing efficient even for large codebases.
10
+ */
11
+ import { type MerkleNode, type SerializedNode } from './node.js';
12
+ import { type TreeDiff } from './diff.js';
13
+ /**
14
+ * Statistics from building a Merkle tree.
15
+ */
16
+ export interface BuildStats {
17
+ /** Total files scanned (before filtering) */
18
+ filesScanned: number;
19
+ /** Files indexed (after filtering) */
20
+ filesIndexed: number;
21
+ /** Hash cache hits (mtime optimization) */
22
+ cacheHits: number;
23
+ /** Hash cache misses (computed hash) */
24
+ cacheMisses: number;
25
+ /** Files skipped (binary, symlink, errors) */
26
+ filesSkipped: number;
27
+ }
28
+ /**
29
+ * A Merkle tree for efficient codebase change detection.
30
+ */
31
+ export declare class MerkleTree {
32
+ /** Root node of the tree */
33
+ readonly root: MerkleNode | null;
34
+ /** Total number of files in the tree */
35
+ readonly fileCount: number;
36
+ /** Build statistics (populated after build) */
37
+ readonly buildStats: BuildStats;
38
+ private constructor();
39
+ /**
40
+ * Build a Merkle tree from the filesystem.
41
+ *
42
+ * Uses .gitignore for exclusions instead of hardcoded patterns.
43
+ * If extensions is provided, only files with those extensions are included.
44
+ * If extensions is empty/undefined, all text files are included.
45
+ *
46
+ * @param projectRoot - Absolute path to project root
47
+ * @param extensions - File extensions to include (e.g., [".py", ".ts"]), or empty for all
48
+ * @param _excludePatterns - DEPRECATED: Use .gitignore instead. This parameter is ignored.
49
+ * @param previousTree - Previous tree for mtime optimization
50
+ */
51
+ static build(projectRoot: string, extensions: string[], _excludePatterns: string[], previousTree?: MerkleTree): Promise<MerkleTree>;
52
+ /**
53
+ * Compare this tree with another tree.
54
+ *
55
+ * @param other - The other tree (usually the new/current tree)
56
+ * @returns TreeDiff with new, modified, and deleted files
57
+ */
58
+ compare(other: MerkleTree): TreeDiff;
59
+ /**
60
+ * Serialize the tree to a plain object for JSON storage.
61
+ */
62
+ toJSON(): SerializedNode | null;
63
+ /**
64
+ * Deserialize a tree from a plain object.
65
+ */
66
+ static fromJSON(data: SerializedNode | null): MerkleTree;
67
+ /**
68
+ * Create an empty tree.
69
+ */
70
+ static empty(): MerkleTree;
71
+ }