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,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gitignore - File filtering based on .gitignore patterns.
|
|
3
|
+
*
|
|
4
|
+
* Uses the `ignore` package to parse .gitignore files and filter paths.
|
|
5
|
+
* This replaces the hardcoded excludePatterns approach.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs/promises';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { createRequire } from 'node:module';
|
|
10
|
+
// ignore is a CJS module, use createRequire to import it
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
12
|
+
const ignore = require('ignore');
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Always-Ignored Patterns
|
|
15
|
+
// ============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Patterns that should always be ignored, regardless of .gitignore.
|
|
18
|
+
* These are internal/system directories that should never be indexed.
|
|
19
|
+
*/
|
|
20
|
+
const ALWAYS_IGNORED = [
|
|
21
|
+
'.git',
|
|
22
|
+
'.viberag',
|
|
23
|
+
'node_modules', // Fallback in case not in .gitignore
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Lock files that should always be ignored.
|
|
27
|
+
* These are machine-generated and provide no value for code search.
|
|
28
|
+
*/
|
|
29
|
+
const ALWAYS_IGNORED_FILES = [
|
|
30
|
+
// JavaScript/TypeScript
|
|
31
|
+
'package-lock.json', // npm
|
|
32
|
+
'yarn.lock', // Yarn
|
|
33
|
+
'pnpm-lock.yaml', // pnpm
|
|
34
|
+
'bun.lockb', // Bun
|
|
35
|
+
// Python
|
|
36
|
+
'uv.lock', // UV
|
|
37
|
+
'poetry.lock', // Poetry
|
|
38
|
+
'Pipfile.lock', // Pipenv
|
|
39
|
+
// Ruby
|
|
40
|
+
'Gemfile.lock', // Bundler
|
|
41
|
+
// PHP
|
|
42
|
+
'composer.lock', // Composer
|
|
43
|
+
// Rust
|
|
44
|
+
'Cargo.lock', // Cargo
|
|
45
|
+
// Go
|
|
46
|
+
'go.sum', // Go modules
|
|
47
|
+
// Java/Kotlin
|
|
48
|
+
'gradle.lockfile', // Gradle
|
|
49
|
+
// C#/.NET
|
|
50
|
+
'packages.lock.json', // NuGet
|
|
51
|
+
// Dart
|
|
52
|
+
'pubspec.lock', // Pub
|
|
53
|
+
// Swift
|
|
54
|
+
'Package.resolved', // Swift PM
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* File patterns that should always be ignored.
|
|
58
|
+
* These are build artifacts with no semantic value for code search.
|
|
59
|
+
*/
|
|
60
|
+
const ALWAYS_IGNORED_PATTERNS = [
|
|
61
|
+
'*.min.js', // Minified JavaScript
|
|
62
|
+
'*.min.css', // Minified CSS
|
|
63
|
+
'*.map', // Source maps
|
|
64
|
+
'*.d.ts.map', // TypeScript declaration maps
|
|
65
|
+
];
|
|
66
|
+
// ============================================================================
|
|
67
|
+
// Cache
|
|
68
|
+
// ============================================================================
|
|
69
|
+
/**
|
|
70
|
+
* Cache of Ignore instances per project root.
|
|
71
|
+
*/
|
|
72
|
+
const ignoreCache = new Map();
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Core Functions
|
|
75
|
+
// ============================================================================
|
|
76
|
+
/**
|
|
77
|
+
* Load and parse .gitignore file from project root.
|
|
78
|
+
* Returns an Ignore instance that can filter paths.
|
|
79
|
+
*
|
|
80
|
+
* @param projectRoot - Project root directory
|
|
81
|
+
* @returns Ignore instance for filtering
|
|
82
|
+
*/
|
|
83
|
+
export async function loadGitignore(projectRoot) {
|
|
84
|
+
// Check cache first
|
|
85
|
+
const cached = ignoreCache.get(projectRoot);
|
|
86
|
+
if (cached) {
|
|
87
|
+
return cached;
|
|
88
|
+
}
|
|
89
|
+
const ig = ignore();
|
|
90
|
+
// Add always-ignored patterns (directories)
|
|
91
|
+
ig.add(ALWAYS_IGNORED);
|
|
92
|
+
// Add always-ignored files (lock files)
|
|
93
|
+
ig.add(ALWAYS_IGNORED_FILES);
|
|
94
|
+
// Add always-ignored file patterns (minified, maps)
|
|
95
|
+
ig.add(ALWAYS_IGNORED_PATTERNS);
|
|
96
|
+
// Try to load .gitignore
|
|
97
|
+
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
98
|
+
try {
|
|
99
|
+
const content = await fs.readFile(gitignorePath, 'utf-8');
|
|
100
|
+
ig.add(content);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// .gitignore doesn't exist, that's fine
|
|
104
|
+
}
|
|
105
|
+
// Cache the instance
|
|
106
|
+
ignoreCache.set(projectRoot, ig);
|
|
107
|
+
return ig;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Check if a path should be ignored based on .gitignore rules.
|
|
111
|
+
*
|
|
112
|
+
* @param projectRoot - Project root directory
|
|
113
|
+
* @param relativePath - Path relative to project root
|
|
114
|
+
* @returns true if the path should be ignored
|
|
115
|
+
*/
|
|
116
|
+
export async function shouldIgnore(projectRoot, relativePath) {
|
|
117
|
+
const ig = await loadGitignore(projectRoot);
|
|
118
|
+
return ig.ignores(relativePath);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Create a filter function for use with file listing.
|
|
122
|
+
* The filter returns true for files that should be INCLUDED (not ignored).
|
|
123
|
+
*
|
|
124
|
+
* @param projectRoot - Project root directory
|
|
125
|
+
* @returns Filter function that returns true for non-ignored files
|
|
126
|
+
*/
|
|
127
|
+
export async function createGitignoreFilter(projectRoot) {
|
|
128
|
+
const ig = await loadGitignore(projectRoot);
|
|
129
|
+
return (relativePath) => !ig.ignores(relativePath);
|
|
130
|
+
}
|
|
131
|
+
// ============================================================================
|
|
132
|
+
// Cache Management
|
|
133
|
+
// ============================================================================
|
|
134
|
+
/**
|
|
135
|
+
* Clear the cache for a specific project root.
|
|
136
|
+
* Call this if .gitignore has been modified.
|
|
137
|
+
*
|
|
138
|
+
* @param projectRoot - Project root directory
|
|
139
|
+
*/
|
|
140
|
+
export function clearGitignoreCache(projectRoot) {
|
|
141
|
+
ignoreCache.delete(projectRoot);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Clear all cached Ignore instances.
|
|
145
|
+
*/
|
|
146
|
+
export function clearAllGitignoreCache() {
|
|
147
|
+
ignoreCache.clear();
|
|
148
|
+
}
|
|
149
|
+
// ============================================================================
|
|
150
|
+
// Glob Pattern Conversion
|
|
151
|
+
// ============================================================================
|
|
152
|
+
/**
|
|
153
|
+
* Convert gitignore patterns to fast-glob ignore patterns.
|
|
154
|
+
* This allows fast-glob to skip directories upfront instead of
|
|
155
|
+
* scanning them and filtering later.
|
|
156
|
+
*
|
|
157
|
+
* @param projectRoot - Project root directory
|
|
158
|
+
* @returns Array of fast-glob compatible ignore patterns
|
|
159
|
+
*/
|
|
160
|
+
export async function getGlobIgnorePatterns(projectRoot) {
|
|
161
|
+
const patterns = [];
|
|
162
|
+
// Always exclude these directories (same as ALWAYS_IGNORED)
|
|
163
|
+
patterns.push('**/.git/**', '**/.viberag/**', '**/node_modules/**');
|
|
164
|
+
// Always exclude lock files (same as ALWAYS_IGNORED_FILES)
|
|
165
|
+
for (const file of ALWAYS_IGNORED_FILES) {
|
|
166
|
+
patterns.push(`**/${file}`);
|
|
167
|
+
}
|
|
168
|
+
// Always exclude file patterns (minified, maps)
|
|
169
|
+
for (const pattern of ALWAYS_IGNORED_PATTERNS) {
|
|
170
|
+
patterns.push(`**/${pattern}`);
|
|
171
|
+
}
|
|
172
|
+
// Try to load .gitignore
|
|
173
|
+
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
174
|
+
try {
|
|
175
|
+
const content = await fs.readFile(gitignorePath, 'utf-8');
|
|
176
|
+
const lines = content.split('\n');
|
|
177
|
+
for (const line of lines) {
|
|
178
|
+
const trimmed = line.trim();
|
|
179
|
+
// Skip empty lines and comments
|
|
180
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
// Skip negation patterns (fast-glob handles these differently)
|
|
184
|
+
if (trimmed.startsWith('!')) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
// Convert gitignore pattern to fast-glob pattern
|
|
188
|
+
const globPattern = gitignoreToGlob(trimmed);
|
|
189
|
+
if (globPattern) {
|
|
190
|
+
patterns.push(globPattern);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// .gitignore doesn't exist, that's fine
|
|
196
|
+
}
|
|
197
|
+
return patterns;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Convert a single gitignore pattern to a fast-glob pattern.
|
|
201
|
+
*
|
|
202
|
+
* Gitignore patterns:
|
|
203
|
+
* - `foo` matches `foo` anywhere
|
|
204
|
+
* - `foo/` matches directory `foo` anywhere
|
|
205
|
+
* - `/foo` matches `foo` only at root
|
|
206
|
+
* - `*.log` matches `*.log` anywhere
|
|
207
|
+
*
|
|
208
|
+
* Fast-glob patterns:
|
|
209
|
+
* - Need double-star-slash prefix to match anywhere
|
|
210
|
+
* - Need "/**" suffix to match directory contents
|
|
211
|
+
*/
|
|
212
|
+
function gitignoreToGlob(pattern) {
|
|
213
|
+
let result = pattern;
|
|
214
|
+
// Handle rooted patterns (start with /)
|
|
215
|
+
const isRooted = result.startsWith('/');
|
|
216
|
+
if (isRooted) {
|
|
217
|
+
result = result.slice(1);
|
|
218
|
+
}
|
|
219
|
+
// Handle directory patterns (end with /)
|
|
220
|
+
const isDirectory = result.endsWith('/');
|
|
221
|
+
if (isDirectory) {
|
|
222
|
+
result = result.slice(0, -1);
|
|
223
|
+
}
|
|
224
|
+
// Skip patterns that are already glob-like with **
|
|
225
|
+
const hasDoublestar = result.includes('**');
|
|
226
|
+
// Build the glob pattern
|
|
227
|
+
if (isRooted) {
|
|
228
|
+
// Rooted: match only at project root
|
|
229
|
+
result = isDirectory ? `${result}/**` : result;
|
|
230
|
+
}
|
|
231
|
+
else if (!hasDoublestar) {
|
|
232
|
+
// Non-rooted: match anywhere in tree
|
|
233
|
+
result = isDirectory ? `**/${result}/**` : `**/${result}`;
|
|
234
|
+
// If it doesn't look like a directory name (has extension or glob),
|
|
235
|
+
// don't add trailing /**
|
|
236
|
+
if (!isDirectory &&
|
|
237
|
+
(result.includes('.') || result.includes('*') || result.includes('?'))) {
|
|
238
|
+
// Keep as-is, it's likely a file pattern
|
|
239
|
+
}
|
|
240
|
+
else if (!isDirectory) {
|
|
241
|
+
// Bare name like "node_modules" - treat as directory
|
|
242
|
+
result = `**/${pattern}/**`;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger - File-based logging with daily and hourly rotation.
|
|
3
|
+
*
|
|
4
|
+
* Provides multiple logger implementations:
|
|
5
|
+
* - createLogger: Daily log files in .viberag/logs/
|
|
6
|
+
* - createDebugLogger: Single debug.log file (deprecated)
|
|
7
|
+
* - createServiceLogger: Per-service hourly rotation
|
|
8
|
+
* - createNullLogger: No-op for testing
|
|
9
|
+
*/
|
|
10
|
+
import { type ServiceName } from './constants.js';
|
|
11
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
12
|
+
export interface Logger {
|
|
13
|
+
debug(component: string, message: string, data?: object): void;
|
|
14
|
+
info(component: string, message: string, data?: object): void;
|
|
15
|
+
warn(component: string, message: string, data?: object): void;
|
|
16
|
+
error(component: string, message: string, error?: Error): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get the path to today's log file.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getLogPath(projectRoot: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Create a logger that writes to daily log files.
|
|
24
|
+
* Log files are created in the .viberag/logs/ directory.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createLogger(projectRoot: string): Logger;
|
|
27
|
+
/**
|
|
28
|
+
* Create a no-op logger for testing or when logging is disabled.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createNullLogger(): Logger;
|
|
31
|
+
/**
|
|
32
|
+
* Create a debug logger that writes to .viberag/debug.log.
|
|
33
|
+
* This is always-on logging for troubleshooting.
|
|
34
|
+
* @deprecated Use createServiceLogger instead for per-service logging.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createDebugLogger(projectRoot: string): Logger;
|
|
37
|
+
/**
|
|
38
|
+
* Create a service-specific logger with hourly rotation.
|
|
39
|
+
*
|
|
40
|
+
* Logs are written to: .viberag/logs/{service}/YYYY-MM-DD-HH.log
|
|
41
|
+
*
|
|
42
|
+
* @param projectRoot - Project root directory
|
|
43
|
+
* @param service - Service name (daemon, mcp, cli, indexer)
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* const logger = createServiceLogger('/path/to/project', 'daemon');
|
|
47
|
+
* logger.error('Handler', 'Request failed', error);
|
|
48
|
+
* // Writes to: .viberag/logs/daemon/2024-01-11-15.log
|
|
49
|
+
*/
|
|
50
|
+
export declare function createServiceLogger(projectRoot: string, service: ServiceName): Logger;
|
|
51
|
+
export type { ServiceName };
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger - File-based logging with daily and hourly rotation.
|
|
3
|
+
*
|
|
4
|
+
* Provides multiple logger implementations:
|
|
5
|
+
* - createLogger: Daily log files in .viberag/logs/
|
|
6
|
+
* - createDebugLogger: Single debug.log file (deprecated)
|
|
7
|
+
* - createServiceLogger: Per-service hourly rotation
|
|
8
|
+
* - createNullLogger: No-op for testing
|
|
9
|
+
*/
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { getLogsDir, getDebugLogPath, getViberagDir, getServiceLogsDir, getServiceLogPath, } from './constants.js';
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Formatting
|
|
15
|
+
// ============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Get the path to today's log file.
|
|
18
|
+
*/
|
|
19
|
+
export function getLogPath(projectRoot) {
|
|
20
|
+
const logsDir = getLogsDir(projectRoot);
|
|
21
|
+
const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
|
22
|
+
return path.join(logsDir, `${date}.log`);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Format a log entry.
|
|
26
|
+
*/
|
|
27
|
+
function formatEntry(level, component, message, extra) {
|
|
28
|
+
const timestamp = new Date().toISOString();
|
|
29
|
+
const levelStr = level.toUpperCase().padEnd(5);
|
|
30
|
+
let entry = `[${timestamp}] [${levelStr}] ${component}: ${message}`;
|
|
31
|
+
if (extra) {
|
|
32
|
+
if (extra instanceof Error) {
|
|
33
|
+
entry += `\n Error: ${extra.message}`;
|
|
34
|
+
if (extra.stack) {
|
|
35
|
+
entry += `\n Stack: ${extra.stack}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
entry += `\n ${JSON.stringify(extra)}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return entry;
|
|
43
|
+
}
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// Logger Implementations
|
|
46
|
+
// ============================================================================
|
|
47
|
+
/**
|
|
48
|
+
* Create a logger that writes to daily log files.
|
|
49
|
+
* Log files are created in the .viberag/logs/ directory.
|
|
50
|
+
*/
|
|
51
|
+
export function createLogger(projectRoot) {
|
|
52
|
+
const logsDir = getLogsDir(projectRoot);
|
|
53
|
+
let initialized = false;
|
|
54
|
+
function ensureDir() {
|
|
55
|
+
if (!initialized) {
|
|
56
|
+
fs.mkdirSync(logsDir, { recursive: true });
|
|
57
|
+
initialized = true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function write(entry) {
|
|
61
|
+
ensureDir();
|
|
62
|
+
const logPath = getLogPath(projectRoot);
|
|
63
|
+
fs.appendFileSync(logPath, entry + '\n');
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
debug(component, message, data) {
|
|
67
|
+
write(formatEntry('debug', component, message, data));
|
|
68
|
+
},
|
|
69
|
+
info(component, message, data) {
|
|
70
|
+
write(formatEntry('info', component, message, data));
|
|
71
|
+
},
|
|
72
|
+
warn(component, message, data) {
|
|
73
|
+
write(formatEntry('warn', component, message, data));
|
|
74
|
+
},
|
|
75
|
+
error(component, message, error) {
|
|
76
|
+
write(formatEntry('error', component, message, error));
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Create a no-op logger for testing or when logging is disabled.
|
|
82
|
+
*/
|
|
83
|
+
export function createNullLogger() {
|
|
84
|
+
return {
|
|
85
|
+
debug() { },
|
|
86
|
+
info() { },
|
|
87
|
+
warn() { },
|
|
88
|
+
error() { },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a debug logger that writes to .viberag/debug.log.
|
|
93
|
+
* This is always-on logging for troubleshooting.
|
|
94
|
+
* @deprecated Use createServiceLogger instead for per-service logging.
|
|
95
|
+
*/
|
|
96
|
+
export function createDebugLogger(projectRoot) {
|
|
97
|
+
const viberagDir = getViberagDir(projectRoot);
|
|
98
|
+
let initialized = false;
|
|
99
|
+
function ensureDir() {
|
|
100
|
+
if (!initialized) {
|
|
101
|
+
fs.mkdirSync(viberagDir, { recursive: true });
|
|
102
|
+
initialized = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function write(entry) {
|
|
106
|
+
ensureDir();
|
|
107
|
+
const logPath = getDebugLogPath(projectRoot);
|
|
108
|
+
fs.appendFileSync(logPath, entry + '\n');
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
debug(component, message, data) {
|
|
112
|
+
write(formatEntry('debug', component, message, data));
|
|
113
|
+
},
|
|
114
|
+
info(component, message, data) {
|
|
115
|
+
write(formatEntry('info', component, message, data));
|
|
116
|
+
},
|
|
117
|
+
warn(component, message, data) {
|
|
118
|
+
write(formatEntry('warn', component, message, data));
|
|
119
|
+
},
|
|
120
|
+
error(component, message, error) {
|
|
121
|
+
write(formatEntry('error', component, message, error));
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Create a service-specific logger with hourly rotation.
|
|
127
|
+
*
|
|
128
|
+
* Logs are written to: .viberag/logs/{service}/YYYY-MM-DD-HH.log
|
|
129
|
+
*
|
|
130
|
+
* @param projectRoot - Project root directory
|
|
131
|
+
* @param service - Service name (daemon, mcp, cli, indexer)
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* const logger = createServiceLogger('/path/to/project', 'daemon');
|
|
135
|
+
* logger.error('Handler', 'Request failed', error);
|
|
136
|
+
* // Writes to: .viberag/logs/daemon/2024-01-11-15.log
|
|
137
|
+
*/
|
|
138
|
+
export function createServiceLogger(projectRoot, service) {
|
|
139
|
+
function write(entry) {
|
|
140
|
+
try {
|
|
141
|
+
// Always ensure directory exists before writing
|
|
142
|
+
// (handles case where .viberag/ was deleted during reinit)
|
|
143
|
+
const serviceDir = getServiceLogsDir(projectRoot, service);
|
|
144
|
+
fs.mkdirSync(serviceDir, { recursive: true });
|
|
145
|
+
// Get current hourly log path (recalculated each write for rotation)
|
|
146
|
+
const logPath = getServiceLogPath(projectRoot, service);
|
|
147
|
+
fs.appendFileSync(logPath, entry + '\n');
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Silently ignore logging failures - don't crash the app for logging
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
debug(component, message, data) {
|
|
155
|
+
write(formatEntry('debug', component, message, data));
|
|
156
|
+
},
|
|
157
|
+
info(component, message, data) {
|
|
158
|
+
write(formatEntry('info', component, message, data));
|
|
159
|
+
},
|
|
160
|
+
warn(component, message, data) {
|
|
161
|
+
write(formatEntry('warn', component, message, data));
|
|
162
|
+
},
|
|
163
|
+
error(component, message, error) {
|
|
164
|
+
write(formatEntry('error', component, message, error));
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest - Index manifest for tracking Merkle tree and stats.
|
|
3
|
+
*
|
|
4
|
+
* The manifest persists indexing state between runs:
|
|
5
|
+
* - Merkle tree for incremental change detection
|
|
6
|
+
* - Stats for status display
|
|
7
|
+
* - Schema version for migration detection
|
|
8
|
+
*/
|
|
9
|
+
export interface ManifestStats {
|
|
10
|
+
totalFiles: number;
|
|
11
|
+
totalChunks: number;
|
|
12
|
+
}
|
|
13
|
+
export interface Manifest {
|
|
14
|
+
version: number;
|
|
15
|
+
schemaVersion: number;
|
|
16
|
+
createdAt: string;
|
|
17
|
+
updatedAt: string;
|
|
18
|
+
tree: object | null;
|
|
19
|
+
stats: ManifestStats;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create an empty manifest with current schema version.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createEmptyManifest(): Manifest;
|
|
25
|
+
/**
|
|
26
|
+
* Check if manifest schema version is current.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isSchemaVersionCurrent(manifest: Manifest): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Get schema version mismatch info for display.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getSchemaVersionInfo(manifest: Manifest): {
|
|
33
|
+
current: number;
|
|
34
|
+
required: number;
|
|
35
|
+
needsReindex: boolean;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Load manifest from disk.
|
|
39
|
+
* Returns an empty manifest if no file exists.
|
|
40
|
+
*/
|
|
41
|
+
export declare function loadManifest(projectRoot: string): Promise<Manifest>;
|
|
42
|
+
/**
|
|
43
|
+
* Save manifest to disk.
|
|
44
|
+
* Creates the .viberag directory if it doesn't exist.
|
|
45
|
+
*/
|
|
46
|
+
export declare function saveManifest(projectRoot: string, manifest: Manifest): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Check if a manifest file exists.
|
|
49
|
+
*/
|
|
50
|
+
export declare function manifestExists(projectRoot: string): Promise<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* Update manifest stats.
|
|
53
|
+
*/
|
|
54
|
+
export declare function updateManifestStats(manifest: Manifest, stats: ManifestStats): Manifest;
|
|
55
|
+
/**
|
|
56
|
+
* Update manifest tree.
|
|
57
|
+
*/
|
|
58
|
+
export declare function updateManifestTree(manifest: Manifest, tree: object | null): Manifest;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest - Index manifest for tracking Merkle tree and stats.
|
|
3
|
+
*
|
|
4
|
+
* The manifest persists indexing state between runs:
|
|
5
|
+
* - Merkle tree for incremental change detection
|
|
6
|
+
* - Stats for status display
|
|
7
|
+
* - Schema version for migration detection
|
|
8
|
+
*/
|
|
9
|
+
import fs from 'node:fs/promises';
|
|
10
|
+
import { getManifestPath, getViberagDir, SCHEMA_VERSION } from './constants.js';
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Factory
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Create an empty manifest with current schema version.
|
|
16
|
+
*/
|
|
17
|
+
export function createEmptyManifest() {
|
|
18
|
+
const now = new Date().toISOString();
|
|
19
|
+
return {
|
|
20
|
+
version: 1,
|
|
21
|
+
schemaVersion: SCHEMA_VERSION,
|
|
22
|
+
createdAt: now,
|
|
23
|
+
updatedAt: now,
|
|
24
|
+
tree: null,
|
|
25
|
+
stats: {
|
|
26
|
+
totalFiles: 0,
|
|
27
|
+
totalChunks: 0,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// Schema Version
|
|
33
|
+
// ============================================================================
|
|
34
|
+
/**
|
|
35
|
+
* Check if manifest schema version is current.
|
|
36
|
+
*/
|
|
37
|
+
export function isSchemaVersionCurrent(manifest) {
|
|
38
|
+
return manifest.schemaVersion === SCHEMA_VERSION;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get schema version mismatch info for display.
|
|
42
|
+
*/
|
|
43
|
+
export function getSchemaVersionInfo(manifest) {
|
|
44
|
+
return {
|
|
45
|
+
current: manifest.schemaVersion ?? 1, // Default to 1 for old manifests
|
|
46
|
+
required: SCHEMA_VERSION,
|
|
47
|
+
needsReindex: (manifest.schemaVersion ?? 1) < SCHEMA_VERSION,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// I/O
|
|
52
|
+
// ============================================================================
|
|
53
|
+
/**
|
|
54
|
+
* Load manifest from disk.
|
|
55
|
+
* Returns an empty manifest if no file exists.
|
|
56
|
+
*/
|
|
57
|
+
export async function loadManifest(projectRoot) {
|
|
58
|
+
const manifestPath = getManifestPath(projectRoot);
|
|
59
|
+
try {
|
|
60
|
+
const content = await fs.readFile(manifestPath, 'utf-8');
|
|
61
|
+
return JSON.parse(content);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return createEmptyManifest();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Save manifest to disk.
|
|
69
|
+
* Creates the .viberag directory if it doesn't exist.
|
|
70
|
+
*/
|
|
71
|
+
export async function saveManifest(projectRoot, manifest) {
|
|
72
|
+
const viberagDir = getViberagDir(projectRoot);
|
|
73
|
+
await fs.mkdir(viberagDir, { recursive: true });
|
|
74
|
+
const manifestPath = getManifestPath(projectRoot);
|
|
75
|
+
const updated = {
|
|
76
|
+
...manifest,
|
|
77
|
+
updatedAt: new Date().toISOString(),
|
|
78
|
+
};
|
|
79
|
+
await fs.writeFile(manifestPath, JSON.stringify(updated, null, '\t') + '\n');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Check if a manifest file exists.
|
|
83
|
+
*/
|
|
84
|
+
export async function manifestExists(projectRoot) {
|
|
85
|
+
const manifestPath = getManifestPath(projectRoot);
|
|
86
|
+
try {
|
|
87
|
+
await fs.access(manifestPath);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// ============================================================================
|
|
95
|
+
// Updates
|
|
96
|
+
// ============================================================================
|
|
97
|
+
/**
|
|
98
|
+
* Update manifest stats.
|
|
99
|
+
*/
|
|
100
|
+
export function updateManifestStats(manifest, stats) {
|
|
101
|
+
return {
|
|
102
|
+
...manifest,
|
|
103
|
+
stats,
|
|
104
|
+
updatedAt: new Date().toISOString(),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Update manifest tree.
|
|
109
|
+
*/
|
|
110
|
+
export function updateManifestTree(manifest, tree) {
|
|
111
|
+
return {
|
|
112
|
+
...manifest,
|
|
113
|
+
tree,
|
|
114
|
+
updatedAt: new Date().toISOString(),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
import type { MerkleNode } from './node.js';
|
|
8
|
+
/**
|
|
9
|
+
* Result of comparing two Merkle trees.
|
|
10
|
+
*/
|
|
11
|
+
export interface TreeDiff {
|
|
12
|
+
/** Paths of new files */
|
|
13
|
+
new: string[];
|
|
14
|
+
/** Paths of modified files */
|
|
15
|
+
modified: string[];
|
|
16
|
+
/** Paths of deleted files */
|
|
17
|
+
deleted: string[];
|
|
18
|
+
/** Whether there are any changes */
|
|
19
|
+
hasChanges: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create an empty TreeDiff.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createEmptyDiff(): TreeDiff;
|
|
25
|
+
/**
|
|
26
|
+
* Compare two Merkle trees and return the differences.
|
|
27
|
+
*
|
|
28
|
+
* @param oldRoot - The previous tree's root node (or null if no previous tree)
|
|
29
|
+
* @param newRoot - The current tree's root node
|
|
30
|
+
* @returns TreeDiff with new, modified, and deleted file paths
|
|
31
|
+
*/
|
|
32
|
+
export declare function compareTrees(oldRoot: MerkleNode | null, newRoot: MerkleNode | null): TreeDiff;
|