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.
- package/README.md +2 -2
- package/dist/cli/app.d.ts +3 -0
- package/dist/cli/app.js +100 -102
- package/dist/cli/commands/handlers.d.ts +8 -6
- package/dist/cli/commands/handlers.js +90 -32
- package/dist/cli/commands/useCommands.d.ts +20 -0
- package/dist/cli/commands/useCommands.js +189 -0
- package/dist/cli/commands/useRagCommands.d.ts +2 -5
- package/dist/cli/commands/useRagCommands.js +11 -18
- package/dist/cli/components/InitWizard.js +66 -27
- package/dist/cli/components/McpSetupWizard.js +23 -4
- package/dist/cli/components/SlotRow.d.ts +22 -0
- package/dist/cli/components/SlotRow.js +55 -0
- package/dist/cli/components/StatusBar.d.ts +14 -0
- package/dist/cli/components/StatusBar.js +156 -0
- package/dist/cli/contexts/DaemonStatusContext.d.ts +38 -0
- package/dist/cli/contexts/DaemonStatusContext.js +106 -0
- package/dist/cli/hooks/useStatusPolling.d.ts +34 -0
- package/dist/cli/hooks/useStatusPolling.js +121 -0
- package/dist/cli/store/app/selectors.d.ts +87 -0
- package/dist/cli/store/app/selectors.js +28 -0
- package/dist/cli/store/app/slice.d.ts +1013 -0
- package/dist/cli/store/app/slice.js +112 -0
- package/dist/cli/store/hooks.d.ts +22 -0
- package/dist/cli/store/hooks.js +17 -0
- package/dist/cli/store/store.d.ts +17 -0
- package/dist/cli/store/store.js +18 -0
- package/dist/cli/store/wizard/selectors.d.ts +115 -0
- package/dist/cli/store/wizard/selectors.js +36 -0
- package/dist/cli/store/wizard/slice.d.ts +523 -0
- package/dist/cli/store/wizard/slice.js +119 -0
- package/dist/cli/utils/error-handler.d.ts +55 -0
- package/dist/cli/utils/error-handler.js +92 -0
- package/dist/client/auto-start.d.ts +42 -0
- package/dist/client/auto-start.js +250 -0
- package/dist/client/connection.d.ts +48 -0
- package/dist/client/connection.js +200 -0
- package/dist/client/index.d.ts +93 -0
- package/dist/client/index.js +209 -0
- package/dist/client/types.d.ts +105 -0
- package/dist/client/types.js +7 -0
- package/dist/common/components/SlotRow.d.ts +22 -0
- package/dist/common/components/SlotRow.js +53 -0
- package/dist/common/components/StatusBar.js +82 -31
- package/dist/common/types.d.ts +12 -13
- package/dist/daemon/handlers.d.ts +15 -0
- package/dist/daemon/handlers.js +157 -0
- package/dist/daemon/index.d.ts +21 -0
- package/dist/daemon/index.js +123 -0
- package/dist/daemon/lib/chunker/bounded-channel.d.ts +51 -0
- package/dist/daemon/lib/chunker/bounded-channel.js +138 -0
- package/dist/daemon/lib/chunker/index.d.ts +135 -0
- package/dist/daemon/lib/chunker/index.js +1370 -0
- package/dist/daemon/lib/chunker/types.d.ts +77 -0
- package/dist/daemon/lib/chunker/types.js +50 -0
- package/dist/daemon/lib/config.d.ts +73 -0
- package/dist/daemon/lib/config.js +149 -0
- package/dist/daemon/lib/constants.d.ts +75 -0
- package/dist/daemon/lib/constants.js +114 -0
- package/dist/daemon/lib/gitignore.d.ts +57 -0
- package/dist/daemon/lib/gitignore.js +246 -0
- package/dist/daemon/lib/logger.d.ts +51 -0
- package/dist/daemon/lib/logger.js +167 -0
- package/dist/daemon/lib/manifest.d.ts +58 -0
- package/dist/daemon/lib/manifest.js +116 -0
- package/dist/daemon/lib/merkle/diff.d.ts +32 -0
- package/dist/daemon/lib/merkle/diff.js +107 -0
- package/dist/daemon/lib/merkle/hash.d.ts +40 -0
- package/dist/daemon/lib/merkle/hash.js +180 -0
- package/dist/daemon/lib/merkle/index.d.ts +71 -0
- package/dist/daemon/lib/merkle/index.js +309 -0
- package/dist/daemon/lib/merkle/node.d.ts +55 -0
- package/dist/daemon/lib/merkle/node.js +82 -0
- package/dist/daemon/lifecycle.d.ts +50 -0
- package/dist/daemon/lifecycle.js +142 -0
- package/dist/daemon/owner.d.ts +175 -0
- package/dist/daemon/owner.js +609 -0
- package/dist/daemon/protocol.d.ts +100 -0
- package/dist/daemon/protocol.js +163 -0
- package/dist/daemon/providers/api-utils.d.ts +130 -0
- package/dist/daemon/providers/api-utils.js +248 -0
- package/dist/daemon/providers/gemini.d.ts +39 -0
- package/dist/daemon/providers/gemini.js +205 -0
- package/dist/daemon/providers/index.d.ts +14 -0
- package/dist/daemon/providers/index.js +14 -0
- package/dist/daemon/providers/local-4b.d.ts +28 -0
- package/dist/daemon/providers/local-4b.js +51 -0
- package/dist/daemon/providers/local.d.ts +36 -0
- package/dist/daemon/providers/local.js +166 -0
- package/dist/daemon/providers/mistral.d.ts +35 -0
- package/dist/daemon/providers/mistral.js +160 -0
- package/dist/daemon/providers/mock.d.ts +35 -0
- package/dist/daemon/providers/mock.js +69 -0
- package/dist/daemon/providers/openai.d.ts +41 -0
- package/dist/daemon/providers/openai.js +190 -0
- package/dist/daemon/providers/types.d.ts +68 -0
- package/dist/daemon/providers/types.js +6 -0
- package/dist/daemon/providers/validate.d.ts +30 -0
- package/dist/daemon/providers/validate.js +162 -0
- package/dist/daemon/server.d.ts +79 -0
- package/dist/daemon/server.js +293 -0
- package/dist/daemon/services/index.d.ts +11 -0
- package/dist/daemon/services/index.js +16 -0
- package/dist/daemon/services/indexing.d.ts +117 -0
- package/dist/daemon/services/indexing.js +573 -0
- package/dist/daemon/services/search/filters.d.ts +21 -0
- package/dist/daemon/services/search/filters.js +106 -0
- package/dist/daemon/services/search/fts.d.ts +32 -0
- package/dist/daemon/services/search/fts.js +61 -0
- package/dist/daemon/services/search/hybrid.d.ts +17 -0
- package/dist/daemon/services/search/hybrid.js +58 -0
- package/dist/daemon/services/search/index.d.ts +108 -0
- package/dist/daemon/services/search/index.js +417 -0
- package/dist/daemon/services/search/types.d.ts +126 -0
- package/dist/daemon/services/search/types.js +4 -0
- package/dist/daemon/services/search/vector.d.ts +25 -0
- package/dist/daemon/services/search/vector.js +44 -0
- package/dist/daemon/services/storage/index.d.ts +110 -0
- package/dist/daemon/services/storage/index.js +378 -0
- package/dist/daemon/services/storage/schema.d.ts +24 -0
- package/dist/daemon/services/storage/schema.js +51 -0
- package/dist/daemon/services/storage/types.d.ts +105 -0
- package/dist/daemon/services/storage/types.js +71 -0
- package/dist/daemon/services/types.d.ts +192 -0
- package/dist/daemon/services/types.js +53 -0
- package/dist/daemon/services/watcher.d.ts +98 -0
- package/dist/daemon/services/watcher.js +386 -0
- package/dist/daemon/state.d.ts +119 -0
- package/dist/daemon/state.js +161 -0
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +44 -60
- package/dist/mcp/server.d.ts +10 -14
- package/dist/mcp/server.js +75 -74
- package/dist/mcp/services/lazy-loader.d.ts +23 -0
- package/dist/mcp/services/lazy-loader.js +34 -0
- package/dist/mcp/warmup.d.ts +3 -3
- package/dist/mcp/warmup.js +39 -40
- package/dist/mcp/watcher.d.ts +5 -7
- package/dist/mcp/watcher.js +73 -64
- package/dist/rag/config/index.d.ts +2 -0
- package/dist/rag/constants.d.ts +30 -0
- package/dist/rag/constants.js +38 -0
- package/dist/rag/embeddings/api-utils.d.ts +121 -0
- package/dist/rag/embeddings/api-utils.js +259 -0
- package/dist/rag/embeddings/gemini.d.ts +4 -12
- package/dist/rag/embeddings/gemini.js +22 -72
- package/dist/rag/embeddings/index.d.ts +5 -3
- package/dist/rag/embeddings/index.js +5 -2
- package/dist/rag/embeddings/local-4b.d.ts +2 -2
- package/dist/rag/embeddings/local-4b.js +1 -1
- package/dist/rag/embeddings/local.d.ts +10 -3
- package/dist/rag/embeddings/local.js +58 -12
- package/dist/rag/embeddings/mistral.d.ts +4 -12
- package/dist/rag/embeddings/mistral.js +22 -72
- package/dist/rag/embeddings/mock.d.ts +35 -0
- package/dist/rag/embeddings/mock.js +69 -0
- package/dist/rag/embeddings/openai.d.ts +11 -13
- package/dist/rag/embeddings/openai.js +47 -75
- package/dist/rag/embeddings/types.d.ts +27 -1
- package/dist/rag/embeddings/validate.d.ts +9 -1
- package/dist/rag/embeddings/validate.js +17 -4
- package/dist/rag/index.d.ts +2 -2
- package/dist/rag/index.js +1 -1
- package/dist/rag/indexer/bounded-channel.d.ts +51 -0
- package/dist/rag/indexer/bounded-channel.js +138 -0
- package/dist/rag/indexer/indexer.d.ts +4 -14
- package/dist/rag/indexer/indexer.js +246 -169
- package/dist/rag/indexer/types.d.ts +1 -0
- package/dist/rag/logger/index.d.ts +22 -0
- package/dist/rag/logger/index.js +78 -1
- package/dist/rag/manifest/index.js +1 -2
- package/dist/rag/search/index.js +1 -1
- package/dist/rag/storage/schema.d.ts +2 -4
- package/dist/rag/storage/schema.js +3 -5
- package/dist/store/app/selectors.d.ts +87 -0
- package/dist/store/app/selectors.js +28 -0
- package/dist/store/app/slice.d.ts +1013 -0
- package/dist/store/app/slice.js +112 -0
- package/dist/store/hooks.d.ts +22 -0
- package/dist/store/hooks.js +17 -0
- package/dist/store/index.d.ts +12 -0
- package/dist/store/index.js +18 -0
- package/dist/store/indexing/listeners.d.ts +25 -0
- package/dist/store/indexing/listeners.js +46 -0
- package/dist/store/indexing/selectors.d.ts +195 -0
- package/dist/store/indexing/selectors.js +69 -0
- package/dist/store/indexing/slice.d.ts +309 -0
- package/dist/store/indexing/slice.js +113 -0
- package/dist/store/slot-progress/listeners.d.ts +23 -0
- package/dist/store/slot-progress/listeners.js +33 -0
- package/dist/store/slot-progress/selectors.d.ts +67 -0
- package/dist/store/slot-progress/selectors.js +36 -0
- package/dist/store/slot-progress/slice.d.ts +246 -0
- package/dist/store/slot-progress/slice.js +70 -0
- package/dist/store/store.d.ts +17 -0
- package/dist/store/store.js +18 -0
- package/dist/store/warmup/selectors.d.ts +109 -0
- package/dist/store/warmup/selectors.js +44 -0
- package/dist/store/warmup/slice.d.ts +137 -0
- package/dist/store/warmup/slice.js +72 -0
- package/dist/store/watcher/selectors.d.ts +115 -0
- package/dist/store/watcher/selectors.js +52 -0
- package/dist/store/watcher/slice.d.ts +269 -0
- package/dist/store/watcher/slice.js +100 -0
- package/dist/store/wizard/selectors.d.ts +115 -0
- package/dist/store/wizard/selectors.js +36 -0
- package/dist/store/wizard/slice.d.ts +523 -0
- package/dist/store/wizard/slice.js +119 -0
- 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
|
+
}
|