@soulcraft/brainy 4.3.2 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +117 -0
- package/dist/augmentations/intelligentImport/handlers/csvHandler.js +33 -1
- package/dist/augmentations/intelligentImport/handlers/excelHandler.js +48 -2
- package/dist/augmentations/intelligentImport/handlers/pdfHandler.js +37 -0
- package/dist/augmentations/intelligentImport/types.d.ts +33 -0
- package/dist/brainy.d.ts +43 -3
- package/dist/brainy.js +83 -12
- package/dist/cli/commands/core.d.ts +3 -0
- package/dist/cli/commands/core.js +21 -3
- package/dist/cli/commands/import.js +69 -34
- package/dist/importers/SmartCSVImporter.js +35 -1
- package/dist/importers/SmartDOCXImporter.js +12 -0
- package/dist/importers/SmartExcelImporter.js +37 -1
- package/dist/importers/SmartJSONImporter.js +18 -0
- package/dist/importers/SmartMarkdownImporter.js +25 -2
- package/dist/importers/SmartPDFImporter.js +37 -1
- package/dist/importers/SmartYAMLImporter.js +12 -0
- package/dist/types/brainy.types.d.ts +98 -0
- package/dist/utils/import-progress-tracker.d.ts +140 -0
- package/dist/utils/import-progress-tracker.js +444 -0
- package/dist/vfs/PathResolver.js +2 -2
- package/dist/vfs/VirtualFileSystem.js +37 -9
- package/dist/vfs/semantic/projections/AuthorProjection.js +6 -3
- package/dist/vfs/semantic/projections/TagProjection.js +6 -3
- package/dist/vfs/semantic/projections/TemporalProjection.js +4 -2
- package/dist/vfs/types.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import Progress Tracker (v4.5.0)
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive progress tracking for imports with:
|
|
5
|
+
* - Multi-dimensional progress (bytes, entities, stages, timing)
|
|
6
|
+
* - Smart estimation (entity count, time remaining)
|
|
7
|
+
* - Stage-specific metrics (bytes/sec vs entities/sec)
|
|
8
|
+
* - Throttled callbacks (avoid spam)
|
|
9
|
+
* - Weighted overall progress
|
|
10
|
+
*
|
|
11
|
+
* @since v4.5.0
|
|
12
|
+
*/
|
|
13
|
+
import { ImportProgress, ImportStage, StageWeights, ImportProgressCallback } from '../types/brainy.types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Progress tracker for imports
|
|
16
|
+
*/
|
|
17
|
+
export declare class ImportProgressTracker {
|
|
18
|
+
private readonly stageWeights;
|
|
19
|
+
private readonly throttleMs;
|
|
20
|
+
private readonly callback?;
|
|
21
|
+
private startTime;
|
|
22
|
+
private lastEmitTime;
|
|
23
|
+
private currentStage;
|
|
24
|
+
private completedStages;
|
|
25
|
+
private totalBytes;
|
|
26
|
+
private bytesProcessed;
|
|
27
|
+
private entitiesExtracted;
|
|
28
|
+
private entitiesIndexed;
|
|
29
|
+
private parseStartTime?;
|
|
30
|
+
private extractStartTime?;
|
|
31
|
+
private indexStartTime?;
|
|
32
|
+
private lastBytesCheckpoint;
|
|
33
|
+
private lastBytesCheckpointTime;
|
|
34
|
+
private lastEntitiesCheckpoint;
|
|
35
|
+
private lastEntitiesCheckpointTime;
|
|
36
|
+
private currentItem?;
|
|
37
|
+
private currentFile?;
|
|
38
|
+
private fileNumber?;
|
|
39
|
+
private totalFiles?;
|
|
40
|
+
private peakMemoryMB;
|
|
41
|
+
constructor(options?: {
|
|
42
|
+
totalBytes?: number;
|
|
43
|
+
stageWeights?: Partial<StageWeights>;
|
|
44
|
+
throttleMs?: number;
|
|
45
|
+
callback?: ImportProgressCallback;
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* Set total file size (if known later)
|
|
49
|
+
*/
|
|
50
|
+
setTotalBytes(bytes: number): void;
|
|
51
|
+
/**
|
|
52
|
+
* Update current stage
|
|
53
|
+
*/
|
|
54
|
+
setStage(stage: ImportStage, message?: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* Update bytes processed
|
|
57
|
+
*/
|
|
58
|
+
updateBytes(bytes: number): void;
|
|
59
|
+
/**
|
|
60
|
+
* Increment bytes processed
|
|
61
|
+
*/
|
|
62
|
+
addBytes(bytes: number): void;
|
|
63
|
+
/**
|
|
64
|
+
* Update entities extracted
|
|
65
|
+
*/
|
|
66
|
+
updateEntitiesExtracted(count: number): void;
|
|
67
|
+
/**
|
|
68
|
+
* Increment entities extracted
|
|
69
|
+
*/
|
|
70
|
+
addEntitiesExtracted(count: number): void;
|
|
71
|
+
/**
|
|
72
|
+
* Update entities indexed
|
|
73
|
+
*/
|
|
74
|
+
updateEntitiesIndexed(count: number): void;
|
|
75
|
+
/**
|
|
76
|
+
* Increment entities indexed
|
|
77
|
+
*/
|
|
78
|
+
addEntitiesIndexed(count: number): void;
|
|
79
|
+
/**
|
|
80
|
+
* Set context information
|
|
81
|
+
*/
|
|
82
|
+
setContext(context: {
|
|
83
|
+
currentItem?: string;
|
|
84
|
+
currentFile?: string;
|
|
85
|
+
fileNumber?: number;
|
|
86
|
+
totalFiles?: number;
|
|
87
|
+
}): void;
|
|
88
|
+
/**
|
|
89
|
+
* Set stage message
|
|
90
|
+
*/
|
|
91
|
+
private setStageMessage;
|
|
92
|
+
/**
|
|
93
|
+
* Calculate stage progress (0-100 within current stage)
|
|
94
|
+
*/
|
|
95
|
+
private calculateStageProgress;
|
|
96
|
+
/**
|
|
97
|
+
* Calculate overall progress (0-100 weighted across all stages)
|
|
98
|
+
*/
|
|
99
|
+
private calculateOverallProgress;
|
|
100
|
+
/**
|
|
101
|
+
* Calculate bytes per second
|
|
102
|
+
*/
|
|
103
|
+
private calculateBytesPerSecond;
|
|
104
|
+
/**
|
|
105
|
+
* Calculate entities per second
|
|
106
|
+
*/
|
|
107
|
+
private calculateEntitiesPerSecond;
|
|
108
|
+
/**
|
|
109
|
+
* Estimate total entities
|
|
110
|
+
*/
|
|
111
|
+
private estimateTotalEntities;
|
|
112
|
+
/**
|
|
113
|
+
* Estimate remaining time
|
|
114
|
+
*/
|
|
115
|
+
private estimateRemainingTime;
|
|
116
|
+
/**
|
|
117
|
+
* Get current memory usage
|
|
118
|
+
*/
|
|
119
|
+
private getCurrentMemoryMB;
|
|
120
|
+
/**
|
|
121
|
+
* Build complete progress object
|
|
122
|
+
*/
|
|
123
|
+
private buildProgress;
|
|
124
|
+
/**
|
|
125
|
+
* Emit progress (throttled)
|
|
126
|
+
*/
|
|
127
|
+
private emit;
|
|
128
|
+
/**
|
|
129
|
+
* Force emit (for completion or critical updates)
|
|
130
|
+
*/
|
|
131
|
+
forceEmit(): void;
|
|
132
|
+
/**
|
|
133
|
+
* Get current progress (without emitting)
|
|
134
|
+
*/
|
|
135
|
+
getProgress(): ImportProgress;
|
|
136
|
+
/**
|
|
137
|
+
* Mark import as complete
|
|
138
|
+
*/
|
|
139
|
+
complete(): ImportProgress;
|
|
140
|
+
}
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import Progress Tracker (v4.5.0)
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive progress tracking for imports with:
|
|
5
|
+
* - Multi-dimensional progress (bytes, entities, stages, timing)
|
|
6
|
+
* - Smart estimation (entity count, time remaining)
|
|
7
|
+
* - Stage-specific metrics (bytes/sec vs entities/sec)
|
|
8
|
+
* - Throttled callbacks (avoid spam)
|
|
9
|
+
* - Weighted overall progress
|
|
10
|
+
*
|
|
11
|
+
* @since v4.5.0
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Default stage weights (reflect typical time distribution)
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_STAGE_WEIGHTS = {
|
|
17
|
+
detecting: 0.01, // 1% - very fast
|
|
18
|
+
reading: 0.05, // 5% - reading file
|
|
19
|
+
parsing: 0.10, // 10% - parsing structure
|
|
20
|
+
extracting: 0.60, // 60% - AI extraction (slowest!)
|
|
21
|
+
indexing: 0.20, // 20% - creating graph
|
|
22
|
+
completing: 0.04 // 4% - cleanup
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Stage ordering for progress calculation
|
|
26
|
+
*/
|
|
27
|
+
const STAGE_ORDER = [
|
|
28
|
+
'detecting',
|
|
29
|
+
'reading',
|
|
30
|
+
'parsing',
|
|
31
|
+
'extracting',
|
|
32
|
+
'indexing',
|
|
33
|
+
'completing'
|
|
34
|
+
];
|
|
35
|
+
/**
|
|
36
|
+
* Progress tracker for imports
|
|
37
|
+
*/
|
|
38
|
+
export class ImportProgressTracker {
|
|
39
|
+
constructor(options = {}) {
|
|
40
|
+
this.lastEmitTime = 0;
|
|
41
|
+
this.currentStage = 'detecting';
|
|
42
|
+
this.completedStages = new Set();
|
|
43
|
+
// Metrics
|
|
44
|
+
this.totalBytes = 0;
|
|
45
|
+
this.bytesProcessed = 0;
|
|
46
|
+
this.entitiesExtracted = 0;
|
|
47
|
+
this.entitiesIndexed = 0;
|
|
48
|
+
// Estimation
|
|
49
|
+
this.lastBytesCheckpoint = 0;
|
|
50
|
+
this.lastBytesCheckpointTime = 0;
|
|
51
|
+
this.lastEntitiesCheckpoint = 0;
|
|
52
|
+
this.lastEntitiesCheckpointTime = 0;
|
|
53
|
+
// Memory tracking
|
|
54
|
+
this.peakMemoryMB = 0;
|
|
55
|
+
this.stageWeights = { ...DEFAULT_STAGE_WEIGHTS, ...options.stageWeights };
|
|
56
|
+
this.throttleMs = options.throttleMs ?? 100; // 100ms default
|
|
57
|
+
this.callback = options.callback;
|
|
58
|
+
this.totalBytes = options.totalBytes ?? 0;
|
|
59
|
+
this.startTime = Date.now();
|
|
60
|
+
this.lastBytesCheckpointTime = this.startTime;
|
|
61
|
+
this.lastEntitiesCheckpointTime = this.startTime;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Set total file size (if known later)
|
|
65
|
+
*/
|
|
66
|
+
setTotalBytes(bytes) {
|
|
67
|
+
this.totalBytes = bytes;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Update current stage
|
|
71
|
+
*/
|
|
72
|
+
setStage(stage, message) {
|
|
73
|
+
// Mark previous stage as complete
|
|
74
|
+
if (this.currentStage !== stage) {
|
|
75
|
+
this.completedStages.add(this.currentStage);
|
|
76
|
+
}
|
|
77
|
+
this.currentStage = stage;
|
|
78
|
+
if (message) {
|
|
79
|
+
this.setStageMessage(message);
|
|
80
|
+
}
|
|
81
|
+
// Track stage start times
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
switch (stage) {
|
|
84
|
+
case 'parsing':
|
|
85
|
+
this.parseStartTime = now;
|
|
86
|
+
break;
|
|
87
|
+
case 'extracting':
|
|
88
|
+
this.extractStartTime = now;
|
|
89
|
+
break;
|
|
90
|
+
case 'indexing':
|
|
91
|
+
this.indexStartTime = now;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
// Force emit on stage change
|
|
95
|
+
this.emit(true);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Update bytes processed
|
|
99
|
+
*/
|
|
100
|
+
updateBytes(bytes) {
|
|
101
|
+
this.bytesProcessed = bytes;
|
|
102
|
+
this.emit();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Increment bytes processed
|
|
106
|
+
*/
|
|
107
|
+
addBytes(bytes) {
|
|
108
|
+
this.bytesProcessed += bytes;
|
|
109
|
+
this.emit();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Update entities extracted
|
|
113
|
+
*/
|
|
114
|
+
updateEntitiesExtracted(count) {
|
|
115
|
+
this.entitiesExtracted = count;
|
|
116
|
+
this.emit();
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Increment entities extracted
|
|
120
|
+
*/
|
|
121
|
+
addEntitiesExtracted(count) {
|
|
122
|
+
this.entitiesExtracted += count;
|
|
123
|
+
this.emit();
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Update entities indexed
|
|
127
|
+
*/
|
|
128
|
+
updateEntitiesIndexed(count) {
|
|
129
|
+
this.entitiesIndexed = count;
|
|
130
|
+
this.emit();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Increment entities indexed
|
|
134
|
+
*/
|
|
135
|
+
addEntitiesIndexed(count) {
|
|
136
|
+
this.entitiesIndexed += count;
|
|
137
|
+
this.emit();
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Set context information
|
|
141
|
+
*/
|
|
142
|
+
setContext(context) {
|
|
143
|
+
if (context.currentItem !== undefined)
|
|
144
|
+
this.currentItem = context.currentItem;
|
|
145
|
+
if (context.currentFile !== undefined)
|
|
146
|
+
this.currentFile = context.currentFile;
|
|
147
|
+
if (context.fileNumber !== undefined)
|
|
148
|
+
this.fileNumber = context.fileNumber;
|
|
149
|
+
if (context.totalFiles !== undefined)
|
|
150
|
+
this.totalFiles = context.totalFiles;
|
|
151
|
+
this.emit();
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Set stage message
|
|
155
|
+
*/
|
|
156
|
+
setStageMessage(message) {
|
|
157
|
+
this.currentItem = message;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Calculate stage progress (0-100 within current stage)
|
|
161
|
+
*/
|
|
162
|
+
calculateStageProgress() {
|
|
163
|
+
switch (this.currentStage) {
|
|
164
|
+
case 'detecting':
|
|
165
|
+
case 'completing':
|
|
166
|
+
// These are quick, assume 100% once started
|
|
167
|
+
return 100;
|
|
168
|
+
case 'reading':
|
|
169
|
+
case 'parsing':
|
|
170
|
+
// Use bytes as proxy for progress
|
|
171
|
+
if (this.totalBytes === 0)
|
|
172
|
+
return 0;
|
|
173
|
+
return Math.min(100, (this.bytesProcessed / this.totalBytes) * 100);
|
|
174
|
+
case 'extracting':
|
|
175
|
+
// Extraction progress is hard to estimate (AI is unpredictable)
|
|
176
|
+
// We can't reliably say % complete, so return 0
|
|
177
|
+
return 0;
|
|
178
|
+
case 'indexing':
|
|
179
|
+
// If we have estimated total entities, use that
|
|
180
|
+
if (this.entitiesExtracted > 0) {
|
|
181
|
+
return Math.min(100, (this.entitiesIndexed / this.entitiesExtracted) * 100);
|
|
182
|
+
}
|
|
183
|
+
return 0;
|
|
184
|
+
default:
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Calculate overall progress (0-100 weighted across all stages)
|
|
190
|
+
*/
|
|
191
|
+
calculateOverallProgress() {
|
|
192
|
+
// Calculate progress of completed stages
|
|
193
|
+
let completedWeight = 0;
|
|
194
|
+
for (const stage of this.completedStages) {
|
|
195
|
+
completedWeight += this.stageWeights[stage];
|
|
196
|
+
}
|
|
197
|
+
// Calculate progress of current stage
|
|
198
|
+
const stageProgress = this.calculateStageProgress();
|
|
199
|
+
const currentStageContribution = this.stageWeights[this.currentStage] * (stageProgress / 100);
|
|
200
|
+
// Overall = completed stages + current stage contribution
|
|
201
|
+
const overall = (completedWeight + currentStageContribution) * 100;
|
|
202
|
+
return Math.min(100, Math.max(0, overall));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Calculate bytes per second
|
|
206
|
+
*/
|
|
207
|
+
calculateBytesPerSecond() {
|
|
208
|
+
const now = Date.now();
|
|
209
|
+
const elapsed = now - this.lastBytesCheckpointTime;
|
|
210
|
+
// Need at least 1 second of data
|
|
211
|
+
if (elapsed < 1000)
|
|
212
|
+
return undefined;
|
|
213
|
+
const bytesDelta = this.bytesProcessed - this.lastBytesCheckpoint;
|
|
214
|
+
const bytesPerSec = (bytesDelta / elapsed) * 1000;
|
|
215
|
+
// Update checkpoint
|
|
216
|
+
this.lastBytesCheckpoint = this.bytesProcessed;
|
|
217
|
+
this.lastBytesCheckpointTime = now;
|
|
218
|
+
return bytesPerSec > 0 ? bytesPerSec : undefined;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Calculate entities per second
|
|
222
|
+
*/
|
|
223
|
+
calculateEntitiesPerSecond() {
|
|
224
|
+
const now = Date.now();
|
|
225
|
+
const elapsed = now - this.lastEntitiesCheckpointTime;
|
|
226
|
+
// Need at least 1 second of data
|
|
227
|
+
if (elapsed < 1000)
|
|
228
|
+
return undefined;
|
|
229
|
+
// Use appropriate counter based on stage
|
|
230
|
+
const currentCount = this.currentStage === 'indexing'
|
|
231
|
+
? this.entitiesIndexed
|
|
232
|
+
: this.entitiesExtracted;
|
|
233
|
+
const entitiesDelta = currentCount - this.lastEntitiesCheckpoint;
|
|
234
|
+
const entitiesPerSec = (entitiesDelta / elapsed) * 1000;
|
|
235
|
+
// Update checkpoint
|
|
236
|
+
this.lastEntitiesCheckpoint = currentCount;
|
|
237
|
+
this.lastEntitiesCheckpointTime = now;
|
|
238
|
+
return entitiesPerSec > 0 ? entitiesPerSec : undefined;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Estimate total entities
|
|
242
|
+
*/
|
|
243
|
+
estimateTotalEntities() {
|
|
244
|
+
// Only estimate if we've processed some bytes and extracted some entities
|
|
245
|
+
if (this.bytesProcessed === 0 || this.entitiesExtracted === 0 || this.totalBytes === 0) {
|
|
246
|
+
return undefined;
|
|
247
|
+
}
|
|
248
|
+
// Estimate based on entities per byte
|
|
249
|
+
const bytesPercentage = this.bytesProcessed / this.totalBytes;
|
|
250
|
+
const estimatedTotal = Math.ceil(this.entitiesExtracted / bytesPercentage);
|
|
251
|
+
// Confidence increases with more data
|
|
252
|
+
const confidence = Math.min(0.95, bytesPercentage);
|
|
253
|
+
return { count: estimatedTotal, confidence };
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Estimate remaining time
|
|
257
|
+
*/
|
|
258
|
+
estimateRemainingTime() {
|
|
259
|
+
const now = Date.now();
|
|
260
|
+
const elapsed = now - this.startTime;
|
|
261
|
+
// Need at least 5 seconds of data for reasonable estimate
|
|
262
|
+
if (elapsed < 5000)
|
|
263
|
+
return undefined;
|
|
264
|
+
const overallProgress = this.calculateOverallProgress();
|
|
265
|
+
if (overallProgress === 0)
|
|
266
|
+
return undefined;
|
|
267
|
+
// Estimate total time based on current progress
|
|
268
|
+
const estimatedTotalMs = (elapsed / overallProgress) * 100;
|
|
269
|
+
const remainingMs = estimatedTotalMs - elapsed;
|
|
270
|
+
return remainingMs > 0 ? remainingMs : undefined;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get current memory usage
|
|
274
|
+
*/
|
|
275
|
+
getCurrentMemoryMB() {
|
|
276
|
+
if (typeof process === 'undefined' || !process.memoryUsage)
|
|
277
|
+
return undefined;
|
|
278
|
+
const usage = process.memoryUsage();
|
|
279
|
+
const currentMB = usage.heapUsed / 1024 / 1024;
|
|
280
|
+
// Track peak
|
|
281
|
+
this.peakMemoryMB = Math.max(this.peakMemoryMB, currentMB);
|
|
282
|
+
return currentMB;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Build complete progress object
|
|
286
|
+
*/
|
|
287
|
+
buildProgress() {
|
|
288
|
+
const now = Date.now();
|
|
289
|
+
const elapsed = now - this.startTime;
|
|
290
|
+
const stageProgress = this.calculateStageProgress();
|
|
291
|
+
const overallProgress = this.calculateOverallProgress();
|
|
292
|
+
const bytesPerSec = this.calculateBytesPerSecond();
|
|
293
|
+
const entitiesPerSec = this.calculateEntitiesPerSecond();
|
|
294
|
+
const entityEstimate = this.estimateTotalEntities();
|
|
295
|
+
const remainingMs = this.estimateRemainingTime();
|
|
296
|
+
const currentMemoryMB = this.getCurrentMemoryMB();
|
|
297
|
+
// Determine overall status
|
|
298
|
+
let overallStatus;
|
|
299
|
+
if (overallProgress === 0) {
|
|
300
|
+
overallStatus = 'starting';
|
|
301
|
+
}
|
|
302
|
+
else if (overallProgress === 100) {
|
|
303
|
+
overallStatus = 'done';
|
|
304
|
+
}
|
|
305
|
+
else if (this.currentStage === 'completing') {
|
|
306
|
+
overallStatus = 'completing';
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
overallStatus = 'processing';
|
|
310
|
+
}
|
|
311
|
+
// Stage message
|
|
312
|
+
let stageMessage;
|
|
313
|
+
if (this.currentItem) {
|
|
314
|
+
stageMessage = this.currentItem;
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
// Default messages
|
|
318
|
+
switch (this.currentStage) {
|
|
319
|
+
case 'detecting':
|
|
320
|
+
stageMessage = 'Detecting file format...';
|
|
321
|
+
break;
|
|
322
|
+
case 'reading':
|
|
323
|
+
stageMessage = 'Reading file...';
|
|
324
|
+
break;
|
|
325
|
+
case 'parsing':
|
|
326
|
+
stageMessage = 'Parsing file structure...';
|
|
327
|
+
break;
|
|
328
|
+
case 'extracting':
|
|
329
|
+
stageMessage = 'Extracting entities using AI...';
|
|
330
|
+
break;
|
|
331
|
+
case 'indexing':
|
|
332
|
+
stageMessage = 'Creating graph nodes...';
|
|
333
|
+
break;
|
|
334
|
+
case 'completing':
|
|
335
|
+
stageMessage = 'Finalizing import...';
|
|
336
|
+
break;
|
|
337
|
+
default:
|
|
338
|
+
stageMessage = 'Processing...';
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
// Calculate bytes percentage
|
|
342
|
+
const bytesPercentage = this.totalBytes > 0
|
|
343
|
+
? (this.bytesProcessed / this.totalBytes) * 100
|
|
344
|
+
: 0;
|
|
345
|
+
// Build metrics object
|
|
346
|
+
const metrics = {
|
|
347
|
+
parsing_rate_mbps: this.currentStage === 'parsing' && bytesPerSec
|
|
348
|
+
? bytesPerSec / 1000000
|
|
349
|
+
: undefined,
|
|
350
|
+
extraction_rate_entities_per_sec: this.currentStage === 'extracting'
|
|
351
|
+
? entitiesPerSec
|
|
352
|
+
: undefined,
|
|
353
|
+
indexing_rate_entities_per_sec: this.currentStage === 'indexing'
|
|
354
|
+
? entitiesPerSec
|
|
355
|
+
: undefined,
|
|
356
|
+
memory_usage_mb: currentMemoryMB,
|
|
357
|
+
peak_memory_mb: this.peakMemoryMB > 0 ? this.peakMemoryMB : undefined
|
|
358
|
+
};
|
|
359
|
+
const progress = {
|
|
360
|
+
// Overall
|
|
361
|
+
overall_progress: overallProgress,
|
|
362
|
+
overall_status: overallStatus,
|
|
363
|
+
// Stage
|
|
364
|
+
stage: this.currentStage,
|
|
365
|
+
stage_progress: stageProgress,
|
|
366
|
+
stage_message: stageMessage,
|
|
367
|
+
// Bytes
|
|
368
|
+
bytes_processed: this.bytesProcessed,
|
|
369
|
+
total_bytes: this.totalBytes,
|
|
370
|
+
bytes_percentage: bytesPercentage,
|
|
371
|
+
bytes_per_second: bytesPerSec,
|
|
372
|
+
// Entities
|
|
373
|
+
entities_extracted: this.entitiesExtracted,
|
|
374
|
+
entities_indexed: this.entitiesIndexed,
|
|
375
|
+
entities_per_second: entitiesPerSec,
|
|
376
|
+
estimated_total_entities: entityEstimate?.count,
|
|
377
|
+
estimation_confidence: entityEstimate?.confidence,
|
|
378
|
+
// Timing
|
|
379
|
+
elapsed_ms: elapsed,
|
|
380
|
+
estimated_remaining_ms: remainingMs,
|
|
381
|
+
estimated_total_ms: remainingMs ? elapsed + remainingMs : undefined,
|
|
382
|
+
// Context
|
|
383
|
+
current_item: this.currentItem,
|
|
384
|
+
current_file: this.currentFile,
|
|
385
|
+
file_number: this.fileNumber,
|
|
386
|
+
total_files: this.totalFiles,
|
|
387
|
+
// Metrics
|
|
388
|
+
metrics,
|
|
389
|
+
// Backwards compatibility
|
|
390
|
+
current: this.entitiesIndexed,
|
|
391
|
+
total: entityEstimate?.count ?? 0
|
|
392
|
+
};
|
|
393
|
+
return progress;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Emit progress (throttled)
|
|
397
|
+
*/
|
|
398
|
+
emit(force = false) {
|
|
399
|
+
if (!this.callback)
|
|
400
|
+
return;
|
|
401
|
+
const now = Date.now();
|
|
402
|
+
const timeSinceLastEmit = now - this.lastEmitTime;
|
|
403
|
+
// Throttle unless forced
|
|
404
|
+
if (!force && timeSinceLastEmit < this.throttleMs) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const progress = this.buildProgress();
|
|
408
|
+
// Handle both callback types (legacy and new)
|
|
409
|
+
if (this.callback.length === 2) {
|
|
410
|
+
// Legacy callback: (current, total) => void
|
|
411
|
+
;
|
|
412
|
+
this.callback(progress.current, progress.total);
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
// New callback: (progress: ImportProgress) => void
|
|
416
|
+
;
|
|
417
|
+
this.callback(progress);
|
|
418
|
+
}
|
|
419
|
+
this.lastEmitTime = now;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Force emit (for completion or critical updates)
|
|
423
|
+
*/
|
|
424
|
+
forceEmit() {
|
|
425
|
+
this.emit(true);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Get current progress (without emitting)
|
|
429
|
+
*/
|
|
430
|
+
getProgress() {
|
|
431
|
+
return this.buildProgress();
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Mark import as complete
|
|
435
|
+
*/
|
|
436
|
+
complete() {
|
|
437
|
+
this.currentStage = 'completing';
|
|
438
|
+
this.completedStages.add('completing');
|
|
439
|
+
const progress = this.buildProgress();
|
|
440
|
+
this.forceEmit();
|
|
441
|
+
return progress;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
//# sourceMappingURL=import-progress-tracker.js.map
|
package/dist/vfs/PathResolver.js
CHANGED
|
@@ -156,14 +156,14 @@ export class PathResolver {
|
|
|
156
156
|
* Uses proper graph relationships to traverse the tree
|
|
157
157
|
*/
|
|
158
158
|
async getChildren(dirId) {
|
|
159
|
-
// Use
|
|
159
|
+
// Production-ready: Use graph relationships (VFS creates these in mkdir/writeFile)
|
|
160
160
|
const relations = await this.brain.getRelations({
|
|
161
161
|
from: dirId,
|
|
162
162
|
type: VerbType.Contains
|
|
163
163
|
});
|
|
164
164
|
const validChildren = [];
|
|
165
165
|
const childNames = new Set();
|
|
166
|
-
// Fetch all child entities
|
|
166
|
+
// Fetch all child entities via relationships
|
|
167
167
|
for (const relation of relations) {
|
|
168
168
|
const entity = await this.brain.get(relation.to);
|
|
169
169
|
if (entity && entity.metadata?.vfsType && entity.metadata?.name) {
|