@the-magic-tower/fixhive-opencode-plugin 0.1.15 → 0.1.19
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/dist/cloud/client.d.ts.map +1 -1
- package/dist/cloud/embedding.d.ts +22 -34
- package/dist/cloud/embedding.d.ts.map +1 -1
- package/dist/core/error-detector.d.ts +15 -41
- package/dist/core/error-detector.d.ts.map +1 -1
- package/dist/core/privacy-filter.d.ts +14 -25
- package/dist/core/privacy-filter.d.ts.map +1 -1
- package/dist/index.d.ts +15 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +399 -418
- package/dist/storage/local-store.d.ts +14 -66
- package/dist/storage/local-store.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,22 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __require = import.meta.require;
|
|
19
|
-
|
|
20
2
|
// src/plugin/index.ts
|
|
21
3
|
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
22
4
|
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
@@ -175,42 +157,9 @@ var DEFAULT_FILTER_RULES = [
|
|
|
175
157
|
priority: 65
|
|
176
158
|
}
|
|
177
159
|
];
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
constructor(customRules) {
|
|
182
|
-
this.rules = [...DEFAULT_FILTER_RULES, ...customRules || []].sort((a, b) => b.priority - a.priority);
|
|
183
|
-
}
|
|
184
|
-
sanitize(content, context) {
|
|
185
|
-
let result = content;
|
|
186
|
-
const appliedFilters = [];
|
|
187
|
-
let totalRedacted = 0;
|
|
188
|
-
for (const rule of this.rules) {
|
|
189
|
-
const before = result;
|
|
190
|
-
if (typeof rule.replacement === "function") {
|
|
191
|
-
result = result.replace(rule.pattern, rule.replacement);
|
|
192
|
-
} else {
|
|
193
|
-
result = result.replace(rule.pattern, rule.replacement);
|
|
194
|
-
}
|
|
195
|
-
if (result !== before) {
|
|
196
|
-
const matches = before.match(rule.pattern);
|
|
197
|
-
if (matches) {
|
|
198
|
-
totalRedacted += matches.length;
|
|
199
|
-
appliedFilters.push(rule.name);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
if (context) {
|
|
204
|
-
result = this.generalizePaths(result, context);
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
original: content,
|
|
208
|
-
sanitized: result,
|
|
209
|
-
redactedCount: totalRedacted,
|
|
210
|
-
appliedFilters: [...new Set(appliedFilters)]
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
generalizePaths(content, context) {
|
|
160
|
+
function createPrivacyFilter(customRules) {
|
|
161
|
+
const rules = [...DEFAULT_FILTER_RULES, ...customRules || []].sort((a, b) => b.priority - a.priority);
|
|
162
|
+
function generalizePaths(content, context) {
|
|
214
163
|
let result = content;
|
|
215
164
|
if (context.projectRoot) {
|
|
216
165
|
const escapedRoot = context.projectRoot.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -224,35 +173,69 @@ class PrivacyFilter {
|
|
|
224
173
|
result = result.replace(/site-packages\/[\w.-]+\//g, "site-packages/<PKG>/");
|
|
225
174
|
return result;
|
|
226
175
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
176
|
+
return {
|
|
177
|
+
sanitize(content, context) {
|
|
178
|
+
let result = content;
|
|
179
|
+
const appliedFilters = [];
|
|
180
|
+
let totalRedacted = 0;
|
|
181
|
+
for (const rule of rules) {
|
|
182
|
+
const before = result;
|
|
183
|
+
if (typeof rule.replacement === "function") {
|
|
184
|
+
result = result.replace(rule.pattern, rule.replacement);
|
|
185
|
+
} else {
|
|
186
|
+
result = result.replace(rule.pattern, rule.replacement);
|
|
187
|
+
}
|
|
188
|
+
if (result !== before) {
|
|
189
|
+
const matches = before.match(rule.pattern);
|
|
190
|
+
if (matches) {
|
|
191
|
+
totalRedacted += matches.length;
|
|
192
|
+
appliedFilters.push(rule.name);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (context) {
|
|
197
|
+
result = generalizePaths(result, context);
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
original: content,
|
|
201
|
+
sanitized: result,
|
|
202
|
+
redactedCount: totalRedacted,
|
|
203
|
+
appliedFilters: [...new Set(appliedFilters)]
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
addRule(rule) {
|
|
207
|
+
rules.push(rule);
|
|
208
|
+
rules.sort((a, b) => b.priority - a.priority);
|
|
209
|
+
},
|
|
210
|
+
removeRule(name) {
|
|
211
|
+
const index = rules.findIndex((r) => r.name === name);
|
|
212
|
+
if (index !== -1) {
|
|
213
|
+
rules.splice(index, 1);
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
return false;
|
|
217
|
+
},
|
|
218
|
+
getRules() {
|
|
219
|
+
return rules;
|
|
220
|
+
},
|
|
221
|
+
containsSensitiveData(content) {
|
|
222
|
+
for (const rule of rules) {
|
|
223
|
+
if (rule.category === "secret") {
|
|
224
|
+
rule.pattern.lastIndex = 0;
|
|
225
|
+
const hasSensitiveData = rule.pattern.test(content);
|
|
226
|
+
rule.pattern.lastIndex = 0;
|
|
227
|
+
if (hasSensitiveData) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
250
230
|
}
|
|
251
231
|
}
|
|
232
|
+
return false;
|
|
252
233
|
}
|
|
253
|
-
|
|
254
|
-
}
|
|
234
|
+
};
|
|
255
235
|
}
|
|
236
|
+
var PrivacyFilter = {
|
|
237
|
+
create: createPrivacyFilter
|
|
238
|
+
};
|
|
256
239
|
function createFilterContext(projectDirectory) {
|
|
257
240
|
const homeDir = process.env.HOME || process.env.USERPROFILE || "~";
|
|
258
241
|
return {
|
|
@@ -267,7 +250,7 @@ function createFilterContext(projectDirectory) {
|
|
|
267
250
|
])
|
|
268
251
|
};
|
|
269
252
|
}
|
|
270
|
-
var defaultPrivacyFilter =
|
|
253
|
+
var defaultPrivacyFilter = createPrivacyFilter();
|
|
271
254
|
|
|
272
255
|
// src/core/error-detector.ts
|
|
273
256
|
var ERROR_PATTERNS = {
|
|
@@ -345,70 +328,12 @@ var EXIT_CODE_SEVERITY = {
|
|
|
345
328
|
139: "critical",
|
|
346
329
|
143: "warning"
|
|
347
330
|
};
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
constructor(privacyFilter) {
|
|
352
|
-
this.privacyFilter = privacyFilter || new PrivacyFilter;
|
|
353
|
-
}
|
|
354
|
-
detect(toolOutput) {
|
|
355
|
-
const signals = [];
|
|
356
|
-
const combinedOutput = `${toolOutput.output || ""}
|
|
357
|
-
${toolOutput.stderr || ""}`;
|
|
358
|
-
if (toolOutput.exitCode !== undefined && toolOutput.exitCode !== 0) {
|
|
359
|
-
const severity2 = EXIT_CODE_SEVERITY[toolOutput.exitCode] || "error";
|
|
360
|
-
signals.push({
|
|
361
|
-
type: "exit_code",
|
|
362
|
-
weight: 0.9,
|
|
363
|
-
value: toolOutput.exitCode,
|
|
364
|
-
description: `Non-zero exit code: ${toolOutput.exitCode} (${severity2})`
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
if (toolOutput.stderr && toolOutput.stderr.trim().length > 0) {
|
|
368
|
-
const hasErrorKeywords = this.containsErrorKeywords(toolOutput.stderr);
|
|
369
|
-
const stderrWeight = hasErrorKeywords ? 0.85 : 0.4;
|
|
370
|
-
signals.push({
|
|
371
|
-
type: "stderr",
|
|
372
|
-
weight: stderrWeight,
|
|
373
|
-
value: toolOutput.stderr.substring(0, 500),
|
|
374
|
-
description: hasErrorKeywords ? "Stderr with error keywords" : "Stderr output present"
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
const patternMatches = this.detectErrorPatterns(combinedOutput);
|
|
378
|
-
signals.push(...patternMatches);
|
|
379
|
-
const stackTrace = this.detectStackTrace(combinedOutput);
|
|
380
|
-
if (stackTrace.hasStackTrace) {
|
|
381
|
-
signals.push({
|
|
382
|
-
type: "stack_trace",
|
|
383
|
-
weight: 0.95,
|
|
384
|
-
value: stackTrace.frames.slice(0, 5).join(`
|
|
385
|
-
`),
|
|
386
|
-
description: `${stackTrace.language} stack trace detected`
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
const confidence = this.calculateConfidence(signals);
|
|
390
|
-
const detected = confidence >= 0.5;
|
|
391
|
-
const errorType = this.classifyErrorType(signals, combinedOutput);
|
|
392
|
-
const severity = this.determineSeverity(signals, toolOutput.exitCode);
|
|
393
|
-
const { message, stack } = this.extractErrorDetails(combinedOutput);
|
|
394
|
-
const sanitizedMessage = this.privacyFilter.sanitize(message);
|
|
395
|
-
const sanitizedStack = stack ? this.privacyFilter.sanitize(stack) : undefined;
|
|
396
|
-
const sanitizedOutput = this.privacyFilter.sanitize(combinedOutput.substring(0, 5000));
|
|
397
|
-
return {
|
|
398
|
-
detected,
|
|
399
|
-
confidence,
|
|
400
|
-
errorType,
|
|
401
|
-
severity,
|
|
402
|
-
signals,
|
|
403
|
-
errorMessage: sanitizedMessage.sanitized,
|
|
404
|
-
errorStack: sanitizedStack?.sanitized,
|
|
405
|
-
rawOutput: sanitizedOutput.sanitized
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
containsErrorKeywords(content) {
|
|
331
|
+
function createErrorDetector(privacyFilter) {
|
|
332
|
+
const filter = privacyFilter || createPrivacyFilter();
|
|
333
|
+
function containsErrorKeywords(content) {
|
|
409
334
|
return ERROR_PATTERNS.universal.some((p) => p.test(content));
|
|
410
335
|
}
|
|
411
|
-
detectErrorPatterns(content) {
|
|
336
|
+
function detectErrorPatterns(content) {
|
|
412
337
|
const signals = [];
|
|
413
338
|
const weights = {
|
|
414
339
|
prefixed: 0.85,
|
|
@@ -436,7 +361,7 @@ ${toolOutput.stderr || ""}`;
|
|
|
436
361
|
}
|
|
437
362
|
return signals;
|
|
438
363
|
}
|
|
439
|
-
detectStackTrace(content) {
|
|
364
|
+
function detectStackTrace(content) {
|
|
440
365
|
for (const [language, pattern] of Object.entries(STACK_TRACE_PATTERNS)) {
|
|
441
366
|
const globalPattern = new RegExp(pattern.source, "gm");
|
|
442
367
|
const matches = content.match(globalPattern);
|
|
@@ -454,7 +379,7 @@ ${toolOutput.stderr || ""}`;
|
|
|
454
379
|
frames: []
|
|
455
380
|
};
|
|
456
381
|
}
|
|
457
|
-
calculateConfidence(signals) {
|
|
382
|
+
function calculateConfidence(signals) {
|
|
458
383
|
if (signals.length === 0)
|
|
459
384
|
return 0;
|
|
460
385
|
const totalWeight = signals.reduce((sum, s) => sum + s.weight, 0);
|
|
@@ -462,7 +387,7 @@ ${toolOutput.stderr || ""}`;
|
|
|
462
387
|
const multiplier = Math.min(1.2, 1 + signals.length * 0.05);
|
|
463
388
|
return Math.min(1, avgWeight * multiplier);
|
|
464
389
|
}
|
|
465
|
-
classifyErrorType(signals, content) {
|
|
390
|
+
function classifyErrorType(signals, content) {
|
|
466
391
|
if (ERROR_PATTERNS.build.some((p) => p.test(content)))
|
|
467
392
|
return "build";
|
|
468
393
|
if (ERROR_PATTERNS.package.some((p) => p.test(content)))
|
|
@@ -484,7 +409,7 @@ ${toolOutput.stderr || ""}`;
|
|
|
484
409
|
return "runtime";
|
|
485
410
|
return "unknown";
|
|
486
411
|
}
|
|
487
|
-
determineSeverity(signals, exitCode) {
|
|
412
|
+
function determineSeverity(signals, exitCode) {
|
|
488
413
|
if (exitCode !== undefined && EXIT_CODE_SEVERITY[exitCode]) {
|
|
489
414
|
return EXIT_CODE_SEVERITY[exitCode];
|
|
490
415
|
}
|
|
@@ -495,14 +420,18 @@ ${toolOutput.stderr || ""}`;
|
|
|
495
420
|
return "error";
|
|
496
421
|
return "warning";
|
|
497
422
|
}
|
|
498
|
-
|
|
423
|
+
function isErrorLine(line) {
|
|
424
|
+
const trimmed = line.trim();
|
|
425
|
+
return /^(Error|TypeError|ReferenceError|SyntaxError|RangeError):/i.test(trimmed) || /^(error|FAIL|fatal|panic)\b/i.test(trimmed) || /^error\[E\d+\]:/.test(trimmed) || /^error TS\d+:/.test(trimmed);
|
|
426
|
+
}
|
|
427
|
+
function extractErrorDetails(output) {
|
|
499
428
|
const lines = output.split(`
|
|
500
429
|
`);
|
|
501
430
|
let message = "";
|
|
502
431
|
let stack = "";
|
|
503
432
|
let inStack = false;
|
|
504
433
|
for (const line of lines) {
|
|
505
|
-
if (
|
|
434
|
+
if (isErrorLine(line) && !message) {
|
|
506
435
|
message = line.trim();
|
|
507
436
|
inStack = true;
|
|
508
437
|
} else if (inStack && (line.match(/^\s+at\s/) || line.match(/^\s+File\s/) || line.match(/^\s+\d+:\s/) || line.match(/^\s+from\s/))) {
|
|
@@ -523,12 +452,67 @@ ${toolOutput.stderr || ""}`;
|
|
|
523
452
|
stack: stack || undefined
|
|
524
453
|
};
|
|
525
454
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
455
|
+
return {
|
|
456
|
+
detect(toolOutput) {
|
|
457
|
+
const signals = [];
|
|
458
|
+
const combinedOutput = `${toolOutput.output || ""}
|
|
459
|
+
${toolOutput.stderr || ""}`;
|
|
460
|
+
if (toolOutput.exitCode !== undefined && toolOutput.exitCode !== 0) {
|
|
461
|
+
const severity2 = EXIT_CODE_SEVERITY[toolOutput.exitCode] || "error";
|
|
462
|
+
signals.push({
|
|
463
|
+
type: "exit_code",
|
|
464
|
+
weight: 0.9,
|
|
465
|
+
value: toolOutput.exitCode,
|
|
466
|
+
description: `Non-zero exit code: ${toolOutput.exitCode} (${severity2})`
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
if (toolOutput.stderr && toolOutput.stderr.trim().length > 0) {
|
|
470
|
+
const hasErrorKeywords = containsErrorKeywords(toolOutput.stderr);
|
|
471
|
+
const stderrWeight = hasErrorKeywords ? 0.85 : 0.4;
|
|
472
|
+
signals.push({
|
|
473
|
+
type: "stderr",
|
|
474
|
+
weight: stderrWeight,
|
|
475
|
+
value: toolOutput.stderr.substring(0, 500),
|
|
476
|
+
description: hasErrorKeywords ? "Stderr with error keywords" : "Stderr output present"
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
const patternMatches = detectErrorPatterns(combinedOutput);
|
|
480
|
+
signals.push(...patternMatches);
|
|
481
|
+
const stackTrace = detectStackTrace(combinedOutput);
|
|
482
|
+
if (stackTrace.hasStackTrace) {
|
|
483
|
+
signals.push({
|
|
484
|
+
type: "stack_trace",
|
|
485
|
+
weight: 0.95,
|
|
486
|
+
value: stackTrace.frames.slice(0, 5).join(`
|
|
487
|
+
`),
|
|
488
|
+
description: `${stackTrace.language} stack trace detected`
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
const confidence = calculateConfidence(signals);
|
|
492
|
+
const detected = confidence >= 0.5;
|
|
493
|
+
const errorType = classifyErrorType(signals, combinedOutput);
|
|
494
|
+
const severity = determineSeverity(signals, toolOutput.exitCode);
|
|
495
|
+
const { message, stack } = extractErrorDetails(combinedOutput);
|
|
496
|
+
const sanitizedMessage = filter.sanitize(message);
|
|
497
|
+
const sanitizedStack = stack ? filter.sanitize(stack) : undefined;
|
|
498
|
+
const sanitizedOutput = filter.sanitize(combinedOutput.substring(0, 5000));
|
|
499
|
+
return {
|
|
500
|
+
detected,
|
|
501
|
+
confidence,
|
|
502
|
+
errorType,
|
|
503
|
+
severity,
|
|
504
|
+
signals,
|
|
505
|
+
errorMessage: sanitizedMessage.sanitized,
|
|
506
|
+
errorStack: sanitizedStack?.sanitized,
|
|
507
|
+
rawOutput: sanitizedOutput.sanitized
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
};
|
|
530
511
|
}
|
|
531
|
-
var
|
|
512
|
+
var ErrorDetector = {
|
|
513
|
+
create: createErrorDetector
|
|
514
|
+
};
|
|
515
|
+
var defaultErrorDetector = createErrorDetector();
|
|
532
516
|
|
|
533
517
|
// src/storage/local-store.ts
|
|
534
518
|
import Database from "better-sqlite3";
|
|
@@ -669,246 +653,227 @@ var MIGRATIONS = [
|
|
|
669
653
|
];
|
|
670
654
|
|
|
671
655
|
// src/storage/local-store.ts
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
framework: data.framework || null,
|
|
705
|
-
toolName: data.toolName,
|
|
706
|
-
toolInput: JSON.stringify(data.toolInput),
|
|
707
|
-
sessionId: data.sessionId
|
|
708
|
-
});
|
|
709
|
-
this.incrementStat("total_errors");
|
|
710
|
-
return this.getErrorById(id);
|
|
711
|
-
}
|
|
712
|
-
getErrorById(id) {
|
|
713
|
-
const stmt = this.db.prepare("SELECT * FROM error_records WHERE id = ?");
|
|
714
|
-
const row = stmt.get(id);
|
|
715
|
-
return row ? this.rowToRecord(row) : null;
|
|
656
|
+
var ALLOWED_STATS = [
|
|
657
|
+
"total_errors",
|
|
658
|
+
"resolved_errors",
|
|
659
|
+
"uploaded_errors",
|
|
660
|
+
"queries_made"
|
|
661
|
+
];
|
|
662
|
+
function rowToRecord(row) {
|
|
663
|
+
return {
|
|
664
|
+
id: row.id,
|
|
665
|
+
errorHash: row.error_hash,
|
|
666
|
+
errorType: row.error_type,
|
|
667
|
+
errorMessage: row.error_message,
|
|
668
|
+
errorStack: row.error_stack || undefined,
|
|
669
|
+
language: row.language || undefined,
|
|
670
|
+
framework: row.framework || undefined,
|
|
671
|
+
toolName: row.tool_name,
|
|
672
|
+
toolInput: JSON.parse(row.tool_input || "{}"),
|
|
673
|
+
sessionId: row.session_id,
|
|
674
|
+
status: row.status,
|
|
675
|
+
resolution: row.resolution || undefined,
|
|
676
|
+
resolutionCode: row.resolution_code || undefined,
|
|
677
|
+
createdAt: row.created_at,
|
|
678
|
+
resolvedAt: row.resolved_at || undefined,
|
|
679
|
+
uploadedAt: row.uploaded_at || undefined,
|
|
680
|
+
cloudKnowledgeId: row.cloud_knowledge_id || undefined
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
function createLocalStore(projectDirectory) {
|
|
684
|
+
const dbPath = `${projectDirectory}/.fixhive/fixhive.db`;
|
|
685
|
+
const dir = dirname(dbPath);
|
|
686
|
+
if (!existsSync(dir)) {
|
|
687
|
+
mkdirSync(dir, { recursive: true });
|
|
716
688
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
query += " ORDER BY created_at DESC";
|
|
725
|
-
if (options?.limit) {
|
|
726
|
-
query += " LIMIT ?";
|
|
727
|
-
params.push(options.limit);
|
|
689
|
+
const db = new Database(dbPath);
|
|
690
|
+
db.pragma("journal_mode = WAL");
|
|
691
|
+
db.pragma("foreign_keys = ON");
|
|
692
|
+
runMigrations(db);
|
|
693
|
+
function incrementStat(stat) {
|
|
694
|
+
if (!ALLOWED_STATS.includes(stat)) {
|
|
695
|
+
throw new Error(`Invalid stat name: ${stat}. Allowed: ${ALLOWED_STATS.join(", ")}`);
|
|
728
696
|
}
|
|
729
|
-
const stmt =
|
|
730
|
-
|
|
731
|
-
}
|
|
732
|
-
getUnresolvedErrors(sessionId) {
|
|
733
|
-
return this.getSessionErrors(sessionId, { status: "unresolved" });
|
|
734
|
-
}
|
|
735
|
-
getRecentErrors(limit = 10) {
|
|
736
|
-
const stmt = this.db.prepare("SELECT * FROM error_records ORDER BY created_at DESC LIMIT ?");
|
|
737
|
-
return stmt.all(limit).map((row) => this.rowToRecord(row));
|
|
697
|
+
const stmt = db.prepare(`UPDATE usage_stats SET ${stat} = ${stat} + 1 WHERE id = 1`);
|
|
698
|
+
stmt.run();
|
|
738
699
|
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
700
|
+
return {
|
|
701
|
+
createErrorRecord(data) {
|
|
702
|
+
const id = uuidv4();
|
|
703
|
+
const errorHash = generateErrorFingerprint(data.errorMessage, data.errorStack);
|
|
704
|
+
const stmt = db.prepare(`
|
|
705
|
+
INSERT INTO error_records (
|
|
706
|
+
id, error_hash, error_type, error_message, error_stack,
|
|
707
|
+
language, framework, tool_name, tool_input, session_id, status
|
|
708
|
+
) VALUES (
|
|
709
|
+
@id, @errorHash, @errorType, @errorMessage, @errorStack,
|
|
710
|
+
@language, @framework, @toolName, @toolInput, @sessionId, 'unresolved'
|
|
711
|
+
)
|
|
712
|
+
`);
|
|
713
|
+
stmt.run({
|
|
714
|
+
id,
|
|
715
|
+
errorHash,
|
|
716
|
+
errorType: data.errorType,
|
|
717
|
+
errorMessage: data.errorMessage,
|
|
718
|
+
errorStack: data.errorStack || null,
|
|
719
|
+
language: data.language || null,
|
|
720
|
+
framework: data.framework || null,
|
|
721
|
+
toolName: data.toolName,
|
|
722
|
+
toolInput: JSON.stringify(data.toolInput),
|
|
723
|
+
sessionId: data.sessionId
|
|
724
|
+
});
|
|
725
|
+
incrementStat("total_errors");
|
|
751
726
|
return this.getErrorById(id);
|
|
727
|
+
},
|
|
728
|
+
getErrorById(id) {
|
|
729
|
+
const stmt = db.prepare("SELECT * FROM error_records WHERE id = ?");
|
|
730
|
+
const row = stmt.get(id);
|
|
731
|
+
return row ? rowToRecord(row) : null;
|
|
732
|
+
},
|
|
733
|
+
getSessionErrors(sessionId, options) {
|
|
734
|
+
let query = "SELECT * FROM error_records WHERE session_id = ?";
|
|
735
|
+
const params = [sessionId];
|
|
736
|
+
if (options?.status) {
|
|
737
|
+
query += " AND status = ?";
|
|
738
|
+
params.push(options.status);
|
|
739
|
+
}
|
|
740
|
+
query += " ORDER BY created_at DESC";
|
|
741
|
+
if (options?.limit) {
|
|
742
|
+
query += " LIMIT ?";
|
|
743
|
+
params.push(options.limit);
|
|
744
|
+
}
|
|
745
|
+
const stmt = db.prepare(query);
|
|
746
|
+
return stmt.all(...params).map((row) => rowToRecord(row));
|
|
747
|
+
},
|
|
748
|
+
getUnresolvedErrors(sessionId) {
|
|
749
|
+
return this.getSessionErrors(sessionId, { status: "unresolved" });
|
|
750
|
+
},
|
|
751
|
+
getRecentErrors(limit = 10) {
|
|
752
|
+
const stmt = db.prepare("SELECT * FROM error_records ORDER BY created_at DESC LIMIT ?");
|
|
753
|
+
return stmt.all(limit).map((row) => rowToRecord(row));
|
|
754
|
+
},
|
|
755
|
+
markResolved(id, data) {
|
|
756
|
+
const stmt = db.prepare(`
|
|
757
|
+
UPDATE error_records
|
|
758
|
+
SET status = 'resolved',
|
|
759
|
+
resolution = ?,
|
|
760
|
+
resolution_code = ?,
|
|
761
|
+
resolved_at = datetime('now')
|
|
762
|
+
WHERE id = ?
|
|
763
|
+
`);
|
|
764
|
+
const result = stmt.run(data.resolution, data.resolutionCode || null, id);
|
|
765
|
+
if (result.changes > 0) {
|
|
766
|
+
incrementStat("resolved_errors");
|
|
767
|
+
return this.getErrorById(id);
|
|
768
|
+
}
|
|
769
|
+
return null;
|
|
770
|
+
},
|
|
771
|
+
markUploaded(id, cloudKnowledgeId) {
|
|
772
|
+
const stmt = db.prepare(`
|
|
773
|
+
UPDATE error_records
|
|
774
|
+
SET status = 'uploaded',
|
|
775
|
+
cloud_knowledge_id = ?,
|
|
776
|
+
uploaded_at = datetime('now')
|
|
777
|
+
WHERE id = ?
|
|
778
|
+
`);
|
|
779
|
+
const result = stmt.run(cloudKnowledgeId, id);
|
|
780
|
+
if (result.changes > 0) {
|
|
781
|
+
incrementStat("uploaded_errors");
|
|
782
|
+
}
|
|
783
|
+
},
|
|
784
|
+
findSimilarErrors(errorHash) {
|
|
785
|
+
const stmt = db.prepare("SELECT * FROM error_records WHERE error_hash = ? ORDER BY created_at DESC");
|
|
786
|
+
return stmt.all(errorHash).map((row) => rowToRecord(row));
|
|
787
|
+
},
|
|
788
|
+
getCachedResults(errorHash) {
|
|
789
|
+
const stmt = db.prepare(`
|
|
790
|
+
SELECT results FROM query_cache
|
|
791
|
+
WHERE error_hash = ? AND expires_at > datetime('now')
|
|
792
|
+
ORDER BY created_at DESC LIMIT 1
|
|
793
|
+
`);
|
|
794
|
+
const row = stmt.get(errorHash);
|
|
795
|
+
if (row) {
|
|
796
|
+
return JSON.parse(row.results);
|
|
797
|
+
}
|
|
798
|
+
return null;
|
|
799
|
+
},
|
|
800
|
+
cacheResults(errorHash, results, expirationMs = 3600000) {
|
|
801
|
+
const id = uuidv4();
|
|
802
|
+
const expiresAt = new Date(Date.now() + expirationMs).toISOString();
|
|
803
|
+
const stmt = db.prepare(`
|
|
804
|
+
INSERT INTO query_cache (id, error_hash, results, expires_at)
|
|
805
|
+
VALUES (?, ?, ?, ?)
|
|
806
|
+
`);
|
|
807
|
+
stmt.run(id, errorHash, JSON.stringify(results), expiresAt);
|
|
808
|
+
incrementStat("queries_made");
|
|
809
|
+
},
|
|
810
|
+
clearExpiredCache() {
|
|
811
|
+
const stmt = db.prepare("DELETE FROM query_cache WHERE expires_at <= datetime('now')");
|
|
812
|
+
const result = stmt.run();
|
|
813
|
+
return result.changes;
|
|
814
|
+
},
|
|
815
|
+
getStats() {
|
|
816
|
+
const stmt = db.prepare("SELECT total_errors, resolved_errors, uploaded_errors FROM usage_stats WHERE id = 1");
|
|
817
|
+
const row = stmt.get();
|
|
818
|
+
return {
|
|
819
|
+
totalErrors: row.total_errors,
|
|
820
|
+
resolvedErrors: row.resolved_errors,
|
|
821
|
+
uploadedErrors: row.uploaded_errors
|
|
822
|
+
};
|
|
823
|
+
},
|
|
824
|
+
getPreference(key) {
|
|
825
|
+
const stmt = db.prepare("SELECT value FROM user_preferences WHERE key = ?");
|
|
826
|
+
const row = stmt.get(key);
|
|
827
|
+
return row?.value || null;
|
|
828
|
+
},
|
|
829
|
+
setPreference(key, value) {
|
|
830
|
+
const stmt = db.prepare(`
|
|
831
|
+
INSERT OR REPLACE INTO user_preferences (key, value) VALUES (?, ?)
|
|
832
|
+
`);
|
|
833
|
+
stmt.run(key, value);
|
|
834
|
+
},
|
|
835
|
+
close() {
|
|
836
|
+
db.close();
|
|
837
|
+
},
|
|
838
|
+
getDatabase() {
|
|
839
|
+
return db;
|
|
752
840
|
}
|
|
753
|
-
|
|
754
|
-
}
|
|
755
|
-
markUploaded(id, cloudKnowledgeId) {
|
|
756
|
-
const stmt = this.db.prepare(`
|
|
757
|
-
UPDATE error_records
|
|
758
|
-
SET status = 'uploaded',
|
|
759
|
-
cloud_knowledge_id = ?,
|
|
760
|
-
uploaded_at = datetime('now')
|
|
761
|
-
WHERE id = ?
|
|
762
|
-
`);
|
|
763
|
-
const result = stmt.run(cloudKnowledgeId, id);
|
|
764
|
-
if (result.changes > 0) {
|
|
765
|
-
this.incrementStat("uploaded_errors");
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
findSimilarErrors(errorHash) {
|
|
769
|
-
const stmt = this.db.prepare("SELECT * FROM error_records WHERE error_hash = ? ORDER BY created_at DESC");
|
|
770
|
-
return stmt.all(errorHash).map((row) => this.rowToRecord(row));
|
|
771
|
-
}
|
|
772
|
-
getCachedResults(errorHash) {
|
|
773
|
-
const stmt = this.db.prepare(`
|
|
774
|
-
SELECT results FROM query_cache
|
|
775
|
-
WHERE error_hash = ? AND expires_at > datetime('now')
|
|
776
|
-
ORDER BY created_at DESC LIMIT 1
|
|
777
|
-
`);
|
|
778
|
-
const row = stmt.get(errorHash);
|
|
779
|
-
if (row) {
|
|
780
|
-
return JSON.parse(row.results);
|
|
781
|
-
}
|
|
782
|
-
return null;
|
|
783
|
-
}
|
|
784
|
-
cacheResults(errorHash, results, expirationMs = 3600000) {
|
|
785
|
-
const id = uuidv4();
|
|
786
|
-
const expiresAt = new Date(Date.now() + expirationMs).toISOString();
|
|
787
|
-
const stmt = this.db.prepare(`
|
|
788
|
-
INSERT INTO query_cache (id, error_hash, results, expires_at)
|
|
789
|
-
VALUES (?, ?, ?, ?)
|
|
790
|
-
`);
|
|
791
|
-
stmt.run(id, errorHash, JSON.stringify(results), expiresAt);
|
|
792
|
-
this.incrementStat("queries_made");
|
|
793
|
-
}
|
|
794
|
-
clearExpiredCache() {
|
|
795
|
-
const stmt = this.db.prepare("DELETE FROM query_cache WHERE expires_at <= datetime('now')");
|
|
796
|
-
const result = stmt.run();
|
|
797
|
-
return result.changes;
|
|
798
|
-
}
|
|
799
|
-
getStats() {
|
|
800
|
-
const stmt = this.db.prepare("SELECT total_errors, resolved_errors, uploaded_errors FROM usage_stats WHERE id = 1");
|
|
801
|
-
const row = stmt.get();
|
|
802
|
-
return {
|
|
803
|
-
totalErrors: row.total_errors,
|
|
804
|
-
resolvedErrors: row.resolved_errors,
|
|
805
|
-
uploadedErrors: row.uploaded_errors
|
|
806
|
-
};
|
|
807
|
-
}
|
|
808
|
-
static ALLOWED_STATS = [
|
|
809
|
-
"total_errors",
|
|
810
|
-
"resolved_errors",
|
|
811
|
-
"uploaded_errors",
|
|
812
|
-
"queries_made"
|
|
813
|
-
];
|
|
814
|
-
incrementStat(stat) {
|
|
815
|
-
if (!LocalStore.ALLOWED_STATS.includes(stat)) {
|
|
816
|
-
throw new Error(`Invalid stat name: ${stat}. Allowed: ${LocalStore.ALLOWED_STATS.join(", ")}`);
|
|
817
|
-
}
|
|
818
|
-
const stmt = this.db.prepare(`UPDATE usage_stats SET ${stat} = ${stat} + 1 WHERE id = 1`);
|
|
819
|
-
stmt.run();
|
|
820
|
-
}
|
|
821
|
-
getPreference(key) {
|
|
822
|
-
const stmt = this.db.prepare("SELECT value FROM user_preferences WHERE key = ?");
|
|
823
|
-
const row = stmt.get(key);
|
|
824
|
-
return row?.value || null;
|
|
825
|
-
}
|
|
826
|
-
setPreference(key, value) {
|
|
827
|
-
const stmt = this.db.prepare(`
|
|
828
|
-
INSERT OR REPLACE INTO user_preferences (key, value) VALUES (?, ?)
|
|
829
|
-
`);
|
|
830
|
-
stmt.run(key, value);
|
|
831
|
-
}
|
|
832
|
-
rowToRecord(row) {
|
|
833
|
-
return {
|
|
834
|
-
id: row.id,
|
|
835
|
-
errorHash: row.error_hash,
|
|
836
|
-
errorType: row.error_type,
|
|
837
|
-
errorMessage: row.error_message,
|
|
838
|
-
errorStack: row.error_stack || undefined,
|
|
839
|
-
language: row.language || undefined,
|
|
840
|
-
framework: row.framework || undefined,
|
|
841
|
-
toolName: row.tool_name,
|
|
842
|
-
toolInput: JSON.parse(row.tool_input || "{}"),
|
|
843
|
-
sessionId: row.session_id,
|
|
844
|
-
status: row.status,
|
|
845
|
-
resolution: row.resolution || undefined,
|
|
846
|
-
resolutionCode: row.resolution_code || undefined,
|
|
847
|
-
createdAt: row.created_at,
|
|
848
|
-
resolvedAt: row.resolved_at || undefined,
|
|
849
|
-
uploadedAt: row.uploaded_at || undefined,
|
|
850
|
-
cloudKnowledgeId: row.cloud_knowledge_id || undefined
|
|
851
|
-
};
|
|
852
|
-
}
|
|
853
|
-
close() {
|
|
854
|
-
this.db.close();
|
|
855
|
-
}
|
|
856
|
-
getDatabase() {
|
|
857
|
-
return this.db;
|
|
858
|
-
}
|
|
841
|
+
};
|
|
859
842
|
}
|
|
843
|
+
var LocalStore = {
|
|
844
|
+
create: createLocalStore
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
// src/cloud/client.ts
|
|
848
|
+
import { createClient } from "@supabase/supabase-js";
|
|
860
849
|
|
|
861
850
|
// src/cloud/embedding.ts
|
|
862
851
|
import OpenAI from "openai";
|
|
863
852
|
var DEFAULT_MODEL = "text-embedding-3-small";
|
|
864
853
|
var DEFAULT_DIMENSIONS = 1536;
|
|
865
854
|
var MAX_INPUT_LENGTH = 30000;
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
model;
|
|
870
|
-
dimensions;
|
|
871
|
-
constructor(apiKey, model, dimensions) {
|
|
872
|
-
this.client = new OpenAI({ apiKey });
|
|
873
|
-
this.model = model || DEFAULT_MODEL;
|
|
874
|
-
this.dimensions = dimensions || DEFAULT_DIMENSIONS;
|
|
875
|
-
}
|
|
876
|
-
async generate(text) {
|
|
877
|
-
const truncated = this.truncateText(text);
|
|
878
|
-
const response = await this.client.embeddings.create({
|
|
879
|
-
model: this.model,
|
|
880
|
-
input: truncated,
|
|
881
|
-
dimensions: this.dimensions
|
|
882
|
-
});
|
|
883
|
-
return response.data[0].embedding;
|
|
884
|
-
}
|
|
885
|
-
async generateBatch(texts) {
|
|
886
|
-
const truncated = texts.map((t) => this.truncateText(t));
|
|
887
|
-
const response = await this.client.embeddings.create({
|
|
888
|
-
model: this.model,
|
|
889
|
-
input: truncated,
|
|
890
|
-
dimensions: this.dimensions
|
|
891
|
-
});
|
|
892
|
-
return response.data.map((d) => d.embedding);
|
|
855
|
+
function cosineSimilarity(a, b) {
|
|
856
|
+
if (a.length !== b.length) {
|
|
857
|
+
throw new Error("Embeddings must have same dimensions");
|
|
893
858
|
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
}
|
|
902
|
-
parts.push(`Error: ${errorMessage}`);
|
|
903
|
-
if (errorStack) {
|
|
904
|
-
parts.push(`Stack Trace:
|
|
905
|
-
${errorStack}`);
|
|
906
|
-
}
|
|
907
|
-
const text = parts.join(`
|
|
908
|
-
`);
|
|
909
|
-
return this.generate(text);
|
|
859
|
+
let dotProduct = 0;
|
|
860
|
+
let normA = 0;
|
|
861
|
+
let normB = 0;
|
|
862
|
+
for (let i = 0;i < a.length; i++) {
|
|
863
|
+
dotProduct += a[i] * b[i];
|
|
864
|
+
normA += a[i] * a[i];
|
|
865
|
+
normB += b[i] * b[i];
|
|
910
866
|
}
|
|
911
|
-
|
|
867
|
+
const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
|
|
868
|
+
if (magnitude === 0)
|
|
869
|
+
return 0;
|
|
870
|
+
return dotProduct / magnitude;
|
|
871
|
+
}
|
|
872
|
+
function createEmbeddingService(config) {
|
|
873
|
+
const client = new OpenAI({ apiKey: config.apiKey });
|
|
874
|
+
const model = config.model || DEFAULT_MODEL;
|
|
875
|
+
const dimensions = config.dimensions || DEFAULT_DIMENSIONS;
|
|
876
|
+
function truncateText(text) {
|
|
912
877
|
if (text.length <= MAX_INPUT_LENGTH) {
|
|
913
878
|
return text;
|
|
914
879
|
}
|
|
@@ -920,43 +885,56 @@ ${errorStack}`);
|
|
|
920
885
|
}
|
|
921
886
|
return truncated;
|
|
922
887
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
888
|
+
return {
|
|
889
|
+
async generate(text) {
|
|
890
|
+
const truncated = truncateText(text);
|
|
891
|
+
const response = await client.embeddings.create({
|
|
892
|
+
model,
|
|
893
|
+
input: truncated,
|
|
894
|
+
dimensions
|
|
895
|
+
});
|
|
896
|
+
return response.data[0].embedding;
|
|
897
|
+
},
|
|
898
|
+
async generateBatch(texts) {
|
|
899
|
+
const truncated = texts.map((t) => truncateText(t));
|
|
900
|
+
const response = await client.embeddings.create({
|
|
901
|
+
model,
|
|
902
|
+
input: truncated,
|
|
903
|
+
dimensions
|
|
904
|
+
});
|
|
905
|
+
return response.data.map((d) => d.embedding);
|
|
906
|
+
},
|
|
907
|
+
async generateErrorEmbedding(errorMessage, errorStack, context) {
|
|
908
|
+
const parts = [];
|
|
909
|
+
if (context?.language) {
|
|
910
|
+
parts.push(`Language: ${context.language}`);
|
|
911
|
+
}
|
|
912
|
+
if (context?.framework) {
|
|
913
|
+
parts.push(`Framework: ${context.framework}`);
|
|
914
|
+
}
|
|
915
|
+
parts.push(`Error: ${errorMessage}`);
|
|
916
|
+
if (errorStack) {
|
|
917
|
+
parts.push(`Stack Trace:
|
|
918
|
+
${errorStack}`);
|
|
919
|
+
}
|
|
920
|
+
const text = parts.join(`
|
|
921
|
+
`);
|
|
922
|
+
return this.generate(text);
|
|
923
|
+
},
|
|
924
|
+
getDimensions() {
|
|
925
|
+
return dimensions;
|
|
926
|
+
},
|
|
927
|
+
getModel() {
|
|
928
|
+
return model;
|
|
934
929
|
}
|
|
935
|
-
|
|
936
|
-
if (magnitude === 0)
|
|
937
|
-
return 0;
|
|
938
|
-
return dotProduct / magnitude;
|
|
939
|
-
}
|
|
940
|
-
getDimensions() {
|
|
941
|
-
return this.dimensions;
|
|
942
|
-
}
|
|
943
|
-
getModel() {
|
|
944
|
-
return this.model;
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
function createEmbeddingService(config) {
|
|
948
|
-
return new EmbeddingService(config.apiKey, config.model, config.dimensions);
|
|
930
|
+
};
|
|
949
931
|
}
|
|
932
|
+
var EmbeddingService = {
|
|
933
|
+
create: createEmbeddingService,
|
|
934
|
+
cosineSimilarity
|
|
935
|
+
};
|
|
950
936
|
|
|
951
937
|
// src/cloud/client.ts
|
|
952
|
-
var createClient;
|
|
953
|
-
async function getCreateClient() {
|
|
954
|
-
if (!createClient) {
|
|
955
|
-
const supabase = await import("@supabase/supabase-js");
|
|
956
|
-
createClient = supabase.createClient;
|
|
957
|
-
}
|
|
958
|
-
return createClient;
|
|
959
|
-
}
|
|
960
938
|
function mapToKnowledgeEntry(row) {
|
|
961
939
|
return {
|
|
962
940
|
id: row.id,
|
|
@@ -981,12 +959,11 @@ function mapToKnowledgeEntry(row) {
|
|
|
981
959
|
};
|
|
982
960
|
}
|
|
983
961
|
async function createCloudClient(config) {
|
|
984
|
-
const
|
|
985
|
-
const supabase = createClientFn(config.supabaseUrl, config.supabaseAnonKey);
|
|
962
|
+
const supabase = createClient(config.supabaseUrl, config.supabaseAnonKey);
|
|
986
963
|
let embedding = null;
|
|
987
964
|
if (config.openaiApiKey) {
|
|
988
965
|
try {
|
|
989
|
-
embedding =
|
|
966
|
+
embedding = createEmbeddingService({ apiKey: config.openaiApiKey });
|
|
990
967
|
} catch (err) {
|
|
991
968
|
console.warn("[FixHive] Failed to initialize embedding service:", err);
|
|
992
969
|
}
|
|
@@ -1400,10 +1377,10 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1400
1377
|
console.log("[FixHive] Plugin loaded");
|
|
1401
1378
|
console.log(`[FixHive] Project: ${ctx.directory}`);
|
|
1402
1379
|
console.log(`[FixHive] Cloud: ${config.supabaseUrl ? "enabled" : "disabled"}`);
|
|
1403
|
-
const privacyFilter =
|
|
1380
|
+
const privacyFilter = createPrivacyFilter();
|
|
1404
1381
|
const filterContext = createFilterContext(ctx.directory);
|
|
1405
|
-
const errorDetector =
|
|
1406
|
-
const localStore =
|
|
1382
|
+
const errorDetector = createErrorDetector(privacyFilter);
|
|
1383
|
+
const localStore = createLocalStore(ctx.directory);
|
|
1407
1384
|
let cloudClient = null;
|
|
1408
1385
|
if (config.supabaseUrl && config.supabaseAnonKey) {
|
|
1409
1386
|
try {
|
|
@@ -1623,9 +1600,13 @@ export {
|
|
|
1623
1600
|
defaultPrivacyFilter,
|
|
1624
1601
|
defaultErrorDetector,
|
|
1625
1602
|
plugin_default as default,
|
|
1603
|
+
createPrivacyFilter,
|
|
1604
|
+
createLocalStore,
|
|
1626
1605
|
createFilterContext,
|
|
1606
|
+
createErrorDetector,
|
|
1627
1607
|
createEmbeddingService,
|
|
1628
1608
|
createCloudClient,
|
|
1609
|
+
cosineSimilarity,
|
|
1629
1610
|
calculateStringSimilarity,
|
|
1630
1611
|
PrivacyFilter,
|
|
1631
1612
|
LocalStore,
|