@the-magic-tower/fixhive-opencode-plugin 0.1.13 → 0.1.14
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 +88 -0
- package/dist/cloud/client.d.ts.map +1 -0
- package/dist/cloud/embedding.d.ts +55 -0
- package/dist/cloud/embedding.d.ts.map +1 -0
- package/dist/core/error-detector.d.ts +52 -0
- package/dist/core/error-detector.d.ts.map +1 -0
- package/dist/core/hash.d.ts +41 -0
- package/dist/core/hash.d.ts.map +1 -0
- package/dist/core/privacy-filter.d.ts +44 -0
- package/dist/core/privacy-filter.d.ts.map +1 -0
- package/dist/index.d.ts +34 -617
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +170 -384
- package/dist/plugin/index.d.ts +11 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/tools.d.ts +15 -0
- package/dist/plugin/tools.d.ts.map +1 -0
- package/dist/storage/local-store.d.ts +98 -0
- package/dist/storage/local-store.d.ts.map +1 -0
- package/dist/storage/migrations.d.ts +10 -0
- package/dist/storage/migrations.d.ts.map +1 -0
- package/dist/types/index.d.ts +218 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +7 -5
package/dist/index.js
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
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
|
+
|
|
1
20
|
// src/plugin/index.ts
|
|
2
21
|
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
3
22
|
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
@@ -5,10 +24,6 @@ import { join } from "path";
|
|
|
5
24
|
|
|
6
25
|
// src/core/privacy-filter.ts
|
|
7
26
|
var DEFAULT_FILTER_RULES = [
|
|
8
|
-
// =====================================
|
|
9
|
-
// SECRETS (Critical - Always Filter)
|
|
10
|
-
// =====================================
|
|
11
|
-
// AWS Keys
|
|
12
27
|
{
|
|
13
28
|
name: "aws_access_key",
|
|
14
29
|
category: "secret",
|
|
@@ -16,7 +31,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
16
31
|
replacement: "[AWS_KEY_REDACTED]",
|
|
17
32
|
priority: 100
|
|
18
33
|
},
|
|
19
|
-
// OpenAI API Keys
|
|
20
34
|
{
|
|
21
35
|
name: "openai_key",
|
|
22
36
|
category: "secret",
|
|
@@ -24,7 +38,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
24
38
|
replacement: "[OPENAI_KEY_REDACTED]",
|
|
25
39
|
priority: 100
|
|
26
40
|
},
|
|
27
|
-
// GitHub Tokens
|
|
28
41
|
{
|
|
29
42
|
name: "github_token",
|
|
30
43
|
category: "secret",
|
|
@@ -32,7 +45,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
32
45
|
replacement: "[GITHUB_TOKEN_REDACTED]",
|
|
33
46
|
priority: 100
|
|
34
47
|
},
|
|
35
|
-
// Google API Keys
|
|
36
48
|
{
|
|
37
49
|
name: "google_api_key",
|
|
38
50
|
category: "secret",
|
|
@@ -40,7 +52,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
40
52
|
replacement: "[GOOGLE_API_KEY_REDACTED]",
|
|
41
53
|
priority: 100
|
|
42
54
|
},
|
|
43
|
-
// Stripe Keys
|
|
44
55
|
{
|
|
45
56
|
name: "stripe_key",
|
|
46
57
|
category: "secret",
|
|
@@ -48,7 +59,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
48
59
|
replacement: "[STRIPE_KEY_REDACTED]",
|
|
49
60
|
priority: 100
|
|
50
61
|
},
|
|
51
|
-
// JWT Tokens (limited length to prevent ReDoS)
|
|
52
62
|
{
|
|
53
63
|
name: "jwt_token",
|
|
54
64
|
category: "secret",
|
|
@@ -56,7 +66,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
56
66
|
replacement: "[JWT_REDACTED]",
|
|
57
67
|
priority: 100
|
|
58
68
|
},
|
|
59
|
-
// Bearer Tokens
|
|
60
69
|
{
|
|
61
70
|
name: "bearer_token",
|
|
62
71
|
category: "secret",
|
|
@@ -64,7 +73,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
64
73
|
replacement: "$1 [TOKEN_REDACTED]",
|
|
65
74
|
priority: 100
|
|
66
75
|
},
|
|
67
|
-
// Private Keys
|
|
68
76
|
{
|
|
69
77
|
name: "private_key",
|
|
70
78
|
category: "secret",
|
|
@@ -72,7 +80,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
72
80
|
replacement: "[PRIVATE_KEY_REDACTED]",
|
|
73
81
|
priority: 100
|
|
74
82
|
},
|
|
75
|
-
// Generic API Keys (context-based, limited length to prevent ReDoS)
|
|
76
83
|
{
|
|
77
84
|
name: "generic_api_key",
|
|
78
85
|
category: "secret",
|
|
@@ -80,7 +87,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
80
87
|
replacement: "$1=[KEY_REDACTED]",
|
|
81
88
|
priority: 95
|
|
82
89
|
},
|
|
83
|
-
// Secret/Password assignments (limited length to prevent ReDoS)
|
|
84
90
|
{
|
|
85
91
|
name: "secret_assignment",
|
|
86
92
|
category: "secret",
|
|
@@ -88,10 +94,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
88
94
|
replacement: "$1=[REDACTED]",
|
|
89
95
|
priority: 90
|
|
90
96
|
},
|
|
91
|
-
// =====================================
|
|
92
|
-
// IDENTITY (High Risk)
|
|
93
|
-
// =====================================
|
|
94
|
-
// Email Addresses
|
|
95
97
|
{
|
|
96
98
|
name: "email",
|
|
97
99
|
category: "identity",
|
|
@@ -99,10 +101,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
99
101
|
replacement: "[EMAIL_REDACTED]",
|
|
100
102
|
priority: 80
|
|
101
103
|
},
|
|
102
|
-
// =====================================
|
|
103
|
-
// INFRASTRUCTURE (Medium Risk)
|
|
104
|
-
// =====================================
|
|
105
|
-
// Database Connection Strings
|
|
106
104
|
{
|
|
107
105
|
name: "db_connection",
|
|
108
106
|
category: "infrastructure",
|
|
@@ -110,7 +108,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
110
108
|
replacement: "$1://[CONNECTION_REDACTED]",
|
|
111
109
|
priority: 85
|
|
112
110
|
},
|
|
113
|
-
// Internal URLs
|
|
114
111
|
{
|
|
115
112
|
name: "internal_url",
|
|
116
113
|
category: "infrastructure",
|
|
@@ -118,7 +115,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
118
115
|
replacement: "[INTERNAL_URL_REDACTED]",
|
|
119
116
|
priority: 75
|
|
120
117
|
},
|
|
121
|
-
// IP Addresses (except localhost and common dev IPs)
|
|
122
118
|
{
|
|
123
119
|
name: "ipv4",
|
|
124
120
|
category: "infrastructure",
|
|
@@ -131,10 +127,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
131
127
|
},
|
|
132
128
|
priority: 70
|
|
133
129
|
},
|
|
134
|
-
// =====================================
|
|
135
|
-
// FILE PATHS (Context-dependent)
|
|
136
|
-
// =====================================
|
|
137
|
-
// Home Directory Paths (macOS)
|
|
138
130
|
{
|
|
139
131
|
name: "macos_home_path",
|
|
140
132
|
category: "path",
|
|
@@ -142,7 +134,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
142
134
|
replacement: "~",
|
|
143
135
|
priority: 60
|
|
144
136
|
},
|
|
145
|
-
// Home Directory Paths (Linux)
|
|
146
137
|
{
|
|
147
138
|
name: "linux_home_path",
|
|
148
139
|
category: "path",
|
|
@@ -150,7 +141,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
150
141
|
replacement: "~",
|
|
151
142
|
priority: 60
|
|
152
143
|
},
|
|
153
|
-
// Home Directory Paths (Windows)
|
|
154
144
|
{
|
|
155
145
|
name: "windows_home_path",
|
|
156
146
|
category: "path",
|
|
@@ -158,10 +148,6 @@ var DEFAULT_FILTER_RULES = [
|
|
|
158
148
|
replacement: "~",
|
|
159
149
|
priority: 60
|
|
160
150
|
},
|
|
161
|
-
// =====================================
|
|
162
|
-
// ENVIRONMENT (Medium Risk)
|
|
163
|
-
// =====================================
|
|
164
|
-
// Sensitive Environment Variables
|
|
165
151
|
{
|
|
166
152
|
name: "env_var_value",
|
|
167
153
|
category: "environment",
|
|
@@ -189,16 +175,12 @@ var DEFAULT_FILTER_RULES = [
|
|
|
189
175
|
priority: 65
|
|
190
176
|
}
|
|
191
177
|
];
|
|
192
|
-
|
|
178
|
+
|
|
179
|
+
class PrivacyFilter {
|
|
193
180
|
rules;
|
|
194
181
|
constructor(customRules) {
|
|
195
|
-
this.rules = [...DEFAULT_FILTER_RULES, ...customRules || []].sort(
|
|
196
|
-
(a, b) => b.priority - a.priority
|
|
197
|
-
);
|
|
182
|
+
this.rules = [...DEFAULT_FILTER_RULES, ...customRules || []].sort((a, b) => b.priority - a.priority);
|
|
198
183
|
}
|
|
199
|
-
/**
|
|
200
|
-
* Sanitize content by applying all filter rules
|
|
201
|
-
*/
|
|
202
184
|
sanitize(content, context) {
|
|
203
185
|
let result = content;
|
|
204
186
|
const appliedFilters = [];
|
|
@@ -228,9 +210,6 @@ var PrivacyFilter = class {
|
|
|
228
210
|
appliedFilters: [...new Set(appliedFilters)]
|
|
229
211
|
};
|
|
230
212
|
}
|
|
231
|
-
/**
|
|
232
|
-
* Generalize file paths while keeping meaningful structure
|
|
233
|
-
*/
|
|
234
213
|
generalizePaths(content, context) {
|
|
235
214
|
let result = content;
|
|
236
215
|
if (context.projectRoot) {
|
|
@@ -245,16 +224,10 @@ var PrivacyFilter = class {
|
|
|
245
224
|
result = result.replace(/site-packages\/[\w.-]+\//g, "site-packages/<PKG>/");
|
|
246
225
|
return result;
|
|
247
226
|
}
|
|
248
|
-
/**
|
|
249
|
-
* Add a custom filter rule
|
|
250
|
-
*/
|
|
251
227
|
addRule(rule) {
|
|
252
228
|
this.rules.push(rule);
|
|
253
229
|
this.rules.sort((a, b) => b.priority - a.priority);
|
|
254
230
|
}
|
|
255
|
-
/**
|
|
256
|
-
* Remove a filter rule by name
|
|
257
|
-
*/
|
|
258
231
|
removeRule(name) {
|
|
259
232
|
const index = this.rules.findIndex((r) => r.name === name);
|
|
260
233
|
if (index !== -1) {
|
|
@@ -263,16 +236,9 @@ var PrivacyFilter = class {
|
|
|
263
236
|
}
|
|
264
237
|
return false;
|
|
265
238
|
}
|
|
266
|
-
/**
|
|
267
|
-
* Get all current rules
|
|
268
|
-
*/
|
|
269
239
|
getRules() {
|
|
270
240
|
return this.rules;
|
|
271
241
|
}
|
|
272
|
-
/**
|
|
273
|
-
* Check if content contains sensitive data
|
|
274
|
-
* Note: Always reset regex lastIndex BEFORE testing to prevent state pollution
|
|
275
|
-
*/
|
|
276
242
|
containsSensitiveData(content) {
|
|
277
243
|
for (const rule of this.rules) {
|
|
278
244
|
if (rule.category === "secret") {
|
|
@@ -286,13 +252,13 @@ var PrivacyFilter = class {
|
|
|
286
252
|
}
|
|
287
253
|
return false;
|
|
288
254
|
}
|
|
289
|
-
}
|
|
255
|
+
}
|
|
290
256
|
function createFilterContext(projectDirectory) {
|
|
291
257
|
const homeDir = process.env.HOME || process.env.USERPROFILE || "~";
|
|
292
258
|
return {
|
|
293
259
|
projectRoot: projectDirectory,
|
|
294
260
|
homeDir,
|
|
295
|
-
commonPaths:
|
|
261
|
+
commonPaths: new Map([
|
|
296
262
|
["/usr/local/lib/", "<LIB>/"],
|
|
297
263
|
["/usr/lib/", "<LIB>/"],
|
|
298
264
|
["/var/log/", "<LOG>/"],
|
|
@@ -301,11 +267,10 @@ function createFilterContext(projectDirectory) {
|
|
|
301
267
|
])
|
|
302
268
|
};
|
|
303
269
|
}
|
|
304
|
-
var defaultPrivacyFilter = new PrivacyFilter
|
|
270
|
+
var defaultPrivacyFilter = new PrivacyFilter;
|
|
305
271
|
|
|
306
272
|
// src/core/error-detector.ts
|
|
307
273
|
var ERROR_PATTERNS = {
|
|
308
|
-
// Universal error indicators
|
|
309
274
|
universal: [
|
|
310
275
|
/\b(error|failed|failure|fatal|exception|panic)\b/i,
|
|
311
276
|
/\b(cannot|could not|unable to|couldn't)\b/i,
|
|
@@ -316,36 +281,26 @@ var ERROR_PATTERNS = {
|
|
|
316
281
|
/\b(segmentation fault|segfault|core dumped)\b/i,
|
|
317
282
|
/\b(out of memory|oom|memory allocation failed)\b/i
|
|
318
283
|
],
|
|
319
|
-
// Error prefixes
|
|
320
284
|
prefixed: [
|
|
321
285
|
/^Error:/m,
|
|
322
286
|
/^ERROR\s/m,
|
|
323
287
|
/^E\s+\d+:/m,
|
|
324
|
-
// Rust errors
|
|
325
288
|
/^\[ERROR\]/m,
|
|
326
289
|
/^fatal:/m,
|
|
327
290
|
/^FATAL:/m,
|
|
328
291
|
/^panic:/m,
|
|
329
292
|
/^Traceback \(most recent call last\):/m,
|
|
330
|
-
// Python
|
|
331
293
|
/^Exception in thread/m,
|
|
332
|
-
// Java
|
|
333
294
|
/^Uncaught \w+Error:/m
|
|
334
|
-
// JavaScript
|
|
335
295
|
],
|
|
336
|
-
// Build/compilation errors
|
|
337
296
|
build: [
|
|
338
297
|
/^.+:\d+:\d+:\s*error:/m,
|
|
339
|
-
// GCC/Clang format
|
|
340
298
|
/error\[E\d+\]:/m,
|
|
341
|
-
// Rust compiler
|
|
342
299
|
/error TS\d+:/m,
|
|
343
|
-
// TypeScript
|
|
344
300
|
/SyntaxError:/m,
|
|
345
301
|
/ParseError:/m,
|
|
346
302
|
/CompileError:/m
|
|
347
303
|
],
|
|
348
|
-
// Package manager errors
|
|
349
304
|
package: [
|
|
350
305
|
/npm ERR!/m,
|
|
351
306
|
/npm error/m,
|
|
@@ -358,9 +313,7 @@ var ERROR_PATTERNS = {
|
|
|
358
313
|
/Cannot find module/m,
|
|
359
314
|
/Module not found/m
|
|
360
315
|
],
|
|
361
|
-
// Permission errors
|
|
362
316
|
permission: [/EACCES:/m, /EPERM:/m, /Permission denied/m, /Access denied/m, /Insufficient permissions/m],
|
|
363
|
-
// Network errors
|
|
364
317
|
network: [
|
|
365
318
|
/ECONNREFUSED/m,
|
|
366
319
|
/ETIMEDOUT/m,
|
|
@@ -369,7 +322,6 @@ var ERROR_PATTERNS = {
|
|
|
369
322
|
/Connection refused/m,
|
|
370
323
|
/Network is unreachable/m
|
|
371
324
|
],
|
|
372
|
-
// Test failures
|
|
373
325
|
test: [/FAIL /m, /AssertionError/m, /Expected .+ but got/m, /Test failed/i, /\d+ failing/m]
|
|
374
326
|
};
|
|
375
327
|
var STACK_TRACE_PATTERNS = {
|
|
@@ -384,37 +336,26 @@ var STACK_TRACE_PATTERNS = {
|
|
|
384
336
|
};
|
|
385
337
|
var EXIT_CODE_SEVERITY = {
|
|
386
338
|
1: "error",
|
|
387
|
-
// General errors
|
|
388
339
|
2: "error",
|
|
389
|
-
// Misuse of shell builtins
|
|
390
340
|
126: "error",
|
|
391
|
-
// Command cannot execute
|
|
392
341
|
127: "error",
|
|
393
|
-
// Command not found
|
|
394
342
|
128: "critical",
|
|
395
|
-
// Invalid exit argument
|
|
396
343
|
130: "warning",
|
|
397
|
-
// Script terminated by Ctrl+C
|
|
398
344
|
137: "critical",
|
|
399
|
-
// SIGKILL (OOM, etc.)
|
|
400
345
|
139: "critical",
|
|
401
|
-
// Segmentation fault
|
|
402
346
|
143: "warning"
|
|
403
|
-
// SIGTERM
|
|
404
347
|
};
|
|
405
|
-
|
|
348
|
+
|
|
349
|
+
class ErrorDetector {
|
|
406
350
|
privacyFilter;
|
|
407
351
|
constructor(privacyFilter) {
|
|
408
|
-
this.privacyFilter = privacyFilter || new PrivacyFilter
|
|
352
|
+
this.privacyFilter = privacyFilter || new PrivacyFilter;
|
|
409
353
|
}
|
|
410
|
-
/**
|
|
411
|
-
* Detect if output contains an error
|
|
412
|
-
*/
|
|
413
354
|
detect(toolOutput) {
|
|
414
355
|
const signals = [];
|
|
415
356
|
const combinedOutput = `${toolOutput.output || ""}
|
|
416
357
|
${toolOutput.stderr || ""}`;
|
|
417
|
-
if (toolOutput.exitCode !==
|
|
358
|
+
if (toolOutput.exitCode !== undefined && toolOutput.exitCode !== 0) {
|
|
418
359
|
const severity2 = EXIT_CODE_SEVERITY[toolOutput.exitCode] || "error";
|
|
419
360
|
signals.push({
|
|
420
361
|
type: "exit_code",
|
|
@@ -440,7 +381,8 @@ ${toolOutput.stderr || ""}`;
|
|
|
440
381
|
signals.push({
|
|
441
382
|
type: "stack_trace",
|
|
442
383
|
weight: 0.95,
|
|
443
|
-
value: stackTrace.frames.slice(0, 5).join(
|
|
384
|
+
value: stackTrace.frames.slice(0, 5).join(`
|
|
385
|
+
`),
|
|
444
386
|
description: `${stackTrace.language} stack trace detected`
|
|
445
387
|
});
|
|
446
388
|
}
|
|
@@ -450,8 +392,8 @@ ${toolOutput.stderr || ""}`;
|
|
|
450
392
|
const severity = this.determineSeverity(signals, toolOutput.exitCode);
|
|
451
393
|
const { message, stack } = this.extractErrorDetails(combinedOutput);
|
|
452
394
|
const sanitizedMessage = this.privacyFilter.sanitize(message);
|
|
453
|
-
const sanitizedStack = stack ? this.privacyFilter.sanitize(stack) :
|
|
454
|
-
const sanitizedOutput = this.privacyFilter.sanitize(combinedOutput.substring(0,
|
|
395
|
+
const sanitizedStack = stack ? this.privacyFilter.sanitize(stack) : undefined;
|
|
396
|
+
const sanitizedOutput = this.privacyFilter.sanitize(combinedOutput.substring(0, 5000));
|
|
455
397
|
return {
|
|
456
398
|
detected,
|
|
457
399
|
confidence,
|
|
@@ -463,15 +405,9 @@ ${toolOutput.stderr || ""}`;
|
|
|
463
405
|
rawOutput: sanitizedOutput.sanitized
|
|
464
406
|
};
|
|
465
407
|
}
|
|
466
|
-
/**
|
|
467
|
-
* Check if content contains error keywords
|
|
468
|
-
*/
|
|
469
408
|
containsErrorKeywords(content) {
|
|
470
409
|
return ERROR_PATTERNS.universal.some((p) => p.test(content));
|
|
471
410
|
}
|
|
472
|
-
/**
|
|
473
|
-
* Detect error patterns in content
|
|
474
|
-
*/
|
|
475
411
|
detectErrorPatterns(content) {
|
|
476
412
|
const signals = [];
|
|
477
413
|
const weights = {
|
|
@@ -483,7 +419,8 @@ ${toolOutput.stderr || ""}`;
|
|
|
483
419
|
test: 0.7
|
|
484
420
|
};
|
|
485
421
|
for (const [category, patterns] of Object.entries(ERROR_PATTERNS)) {
|
|
486
|
-
if (category === "universal")
|
|
422
|
+
if (category === "universal")
|
|
423
|
+
continue;
|
|
487
424
|
for (const pattern of patterns) {
|
|
488
425
|
const match = content.match(pattern);
|
|
489
426
|
if (match) {
|
|
@@ -499,9 +436,6 @@ ${toolOutput.stderr || ""}`;
|
|
|
499
436
|
}
|
|
500
437
|
return signals;
|
|
501
438
|
}
|
|
502
|
-
/**
|
|
503
|
-
* Detect stack traces in content
|
|
504
|
-
*/
|
|
505
439
|
detectStackTrace(content) {
|
|
506
440
|
for (const [language, pattern] of Object.entries(STACK_TRACE_PATTERNS)) {
|
|
507
441
|
const globalPattern = new RegExp(pattern.source, "gm");
|
|
@@ -520,49 +454,50 @@ ${toolOutput.stderr || ""}`;
|
|
|
520
454
|
frames: []
|
|
521
455
|
};
|
|
522
456
|
}
|
|
523
|
-
/**
|
|
524
|
-
* Calculate confidence score from signals
|
|
525
|
-
*/
|
|
526
457
|
calculateConfidence(signals) {
|
|
527
|
-
if (signals.length === 0)
|
|
458
|
+
if (signals.length === 0)
|
|
459
|
+
return 0;
|
|
528
460
|
const totalWeight = signals.reduce((sum, s) => sum + s.weight, 0);
|
|
529
461
|
const avgWeight = totalWeight / signals.length;
|
|
530
462
|
const multiplier = Math.min(1.2, 1 + signals.length * 0.05);
|
|
531
463
|
return Math.min(1, avgWeight * multiplier);
|
|
532
464
|
}
|
|
533
|
-
/**
|
|
534
|
-
* Classify error type based on signals and content
|
|
535
|
-
*/
|
|
536
465
|
classifyErrorType(signals, content) {
|
|
537
|
-
if (ERROR_PATTERNS.build.some((p) => p.test(content)))
|
|
538
|
-
|
|
539
|
-
if (ERROR_PATTERNS.
|
|
540
|
-
|
|
541
|
-
if (ERROR_PATTERNS.
|
|
542
|
-
|
|
543
|
-
if (
|
|
544
|
-
|
|
466
|
+
if (ERROR_PATTERNS.build.some((p) => p.test(content)))
|
|
467
|
+
return "build";
|
|
468
|
+
if (ERROR_PATTERNS.package.some((p) => p.test(content)))
|
|
469
|
+
return "dependency";
|
|
470
|
+
if (ERROR_PATTERNS.permission.some((p) => p.test(content)))
|
|
471
|
+
return "permission";
|
|
472
|
+
if (ERROR_PATTERNS.network.some((p) => p.test(content)))
|
|
473
|
+
return "network";
|
|
474
|
+
if (ERROR_PATTERNS.test.some((p) => p.test(content)))
|
|
475
|
+
return "test";
|
|
476
|
+
if (/TypeError:|type error|Type '[^']+' is not assignable/i.test(content))
|
|
477
|
+
return "type_error";
|
|
478
|
+
if (/SyntaxError:|syntax error|unexpected token/i.test(content))
|
|
479
|
+
return "syntax";
|
|
480
|
+
if (/ReferenceError:|RangeError:|runtime error/i.test(content))
|
|
481
|
+
return "runtime";
|
|
545
482
|
const hasStackTrace = signals.some((s) => s.type === "stack_trace");
|
|
546
|
-
if (hasStackTrace)
|
|
483
|
+
if (hasStackTrace)
|
|
484
|
+
return "runtime";
|
|
547
485
|
return "unknown";
|
|
548
486
|
}
|
|
549
|
-
/**
|
|
550
|
-
* Determine severity from signals and exit code
|
|
551
|
-
*/
|
|
552
487
|
determineSeverity(signals, exitCode) {
|
|
553
|
-
if (exitCode !==
|
|
488
|
+
if (exitCode !== undefined && EXIT_CODE_SEVERITY[exitCode]) {
|
|
554
489
|
return EXIT_CODE_SEVERITY[exitCode];
|
|
555
490
|
}
|
|
556
491
|
const maxWeight = Math.max(...signals.map((s) => s.weight));
|
|
557
|
-
if (maxWeight >= 0.9)
|
|
558
|
-
|
|
492
|
+
if (maxWeight >= 0.9)
|
|
493
|
+
return "error";
|
|
494
|
+
if (maxWeight >= 0.7)
|
|
495
|
+
return "error";
|
|
559
496
|
return "warning";
|
|
560
497
|
}
|
|
561
|
-
/**
|
|
562
|
-
* Extract error message and stack from output
|
|
563
|
-
*/
|
|
564
498
|
extractErrorDetails(output) {
|
|
565
|
-
const lines = output.split(
|
|
499
|
+
const lines = output.split(`
|
|
500
|
+
`);
|
|
566
501
|
let message = "";
|
|
567
502
|
let stack = "";
|
|
568
503
|
let inStack = false;
|
|
@@ -570,11 +505,9 @@ ${toolOutput.stderr || ""}`;
|
|
|
570
505
|
if (this.isErrorLine(line) && !message) {
|
|
571
506
|
message = line.trim();
|
|
572
507
|
inStack = true;
|
|
573
|
-
} else if (inStack && (line.match(/^\s+at\s/) ||
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
line.match(/^\s+from\s/))) {
|
|
577
|
-
stack += line + "\n";
|
|
508
|
+
} else if (inStack && (line.match(/^\s+at\s/) || line.match(/^\s+File\s/) || line.match(/^\s+\d+:\s/) || line.match(/^\s+from\s/))) {
|
|
509
|
+
stack += line + `
|
|
510
|
+
`;
|
|
578
511
|
}
|
|
579
512
|
}
|
|
580
513
|
if (!message) {
|
|
@@ -587,18 +520,15 @@ ${toolOutput.stderr || ""}`;
|
|
|
587
520
|
}
|
|
588
521
|
return {
|
|
589
522
|
message: message || output.substring(0, 500),
|
|
590
|
-
stack: stack ||
|
|
523
|
+
stack: stack || undefined
|
|
591
524
|
};
|
|
592
525
|
}
|
|
593
|
-
/**
|
|
594
|
-
* Check if a line looks like an error message
|
|
595
|
-
*/
|
|
596
526
|
isErrorLine(line) {
|
|
597
527
|
const trimmed = line.trim();
|
|
598
528
|
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);
|
|
599
529
|
}
|
|
600
|
-
}
|
|
601
|
-
var defaultErrorDetector = new ErrorDetector
|
|
530
|
+
}
|
|
531
|
+
var defaultErrorDetector = new ErrorDetector;
|
|
602
532
|
|
|
603
533
|
// src/storage/local-store.ts
|
|
604
534
|
import Database from "better-sqlite3";
|
|
@@ -642,8 +572,9 @@ function calculateStringSimilarity(str1, str2) {
|
|
|
642
572
|
const words1 = new Set(str1.toLowerCase().split(/\s+/));
|
|
643
573
|
const words2 = new Set(str2.toLowerCase().split(/\s+/));
|
|
644
574
|
const intersection = new Set([...words1].filter((x) => words2.has(x)));
|
|
645
|
-
const union =
|
|
646
|
-
if (union.size === 0)
|
|
575
|
+
const union = new Set([...words1, ...words2]);
|
|
576
|
+
if (union.size === 0)
|
|
577
|
+
return 0;
|
|
647
578
|
return intersection.size / union.size;
|
|
648
579
|
}
|
|
649
580
|
|
|
@@ -656,9 +587,7 @@ function runMigrations(db) {
|
|
|
656
587
|
applied_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
657
588
|
)
|
|
658
589
|
`);
|
|
659
|
-
const appliedMigrations = new Set(
|
|
660
|
-
db.prepare("SELECT name FROM migrations").all().map((r) => r.name)
|
|
661
|
-
);
|
|
590
|
+
const appliedMigrations = new Set(db.prepare("SELECT name FROM migrations").all().map((r) => r.name));
|
|
662
591
|
for (const migration of MIGRATIONS) {
|
|
663
592
|
if (!appliedMigrations.has(migration.name)) {
|
|
664
593
|
db.exec(migration.sql);
|
|
@@ -740,7 +669,7 @@ var MIGRATIONS = [
|
|
|
740
669
|
];
|
|
741
670
|
|
|
742
671
|
// src/storage/local-store.ts
|
|
743
|
-
|
|
672
|
+
class LocalStore {
|
|
744
673
|
db;
|
|
745
674
|
constructor(projectDirectory) {
|
|
746
675
|
const dbPath = `${projectDirectory}/.fixhive/fixhive.db`;
|
|
@@ -753,10 +682,6 @@ var LocalStore = class _LocalStore {
|
|
|
753
682
|
this.db.pragma("foreign_keys = ON");
|
|
754
683
|
runMigrations(this.db);
|
|
755
684
|
}
|
|
756
|
-
// ============ Error Records ============
|
|
757
|
-
/**
|
|
758
|
-
* Create a new error record
|
|
759
|
-
*/
|
|
760
685
|
createErrorRecord(data) {
|
|
761
686
|
const id = uuidv4();
|
|
762
687
|
const errorHash = generateErrorFingerprint(data.errorMessage, data.errorStack);
|
|
@@ -784,17 +709,11 @@ var LocalStore = class _LocalStore {
|
|
|
784
709
|
this.incrementStat("total_errors");
|
|
785
710
|
return this.getErrorById(id);
|
|
786
711
|
}
|
|
787
|
-
/**
|
|
788
|
-
* Get error record by ID
|
|
789
|
-
*/
|
|
790
712
|
getErrorById(id) {
|
|
791
713
|
const stmt = this.db.prepare("SELECT * FROM error_records WHERE id = ?");
|
|
792
714
|
const row = stmt.get(id);
|
|
793
715
|
return row ? this.rowToRecord(row) : null;
|
|
794
716
|
}
|
|
795
|
-
/**
|
|
796
|
-
* Get errors by session
|
|
797
|
-
*/
|
|
798
717
|
getSessionErrors(sessionId, options) {
|
|
799
718
|
let query = "SELECT * FROM error_records WHERE session_id = ?";
|
|
800
719
|
const params = [sessionId];
|
|
@@ -810,24 +729,13 @@ var LocalStore = class _LocalStore {
|
|
|
810
729
|
const stmt = this.db.prepare(query);
|
|
811
730
|
return stmt.all(...params).map((row) => this.rowToRecord(row));
|
|
812
731
|
}
|
|
813
|
-
/**
|
|
814
|
-
* Get unresolved errors for a session
|
|
815
|
-
*/
|
|
816
732
|
getUnresolvedErrors(sessionId) {
|
|
817
733
|
return this.getSessionErrors(sessionId, { status: "unresolved" });
|
|
818
734
|
}
|
|
819
|
-
/**
|
|
820
|
-
* Get recent errors across all sessions
|
|
821
|
-
*/
|
|
822
735
|
getRecentErrors(limit = 10) {
|
|
823
|
-
const stmt = this.db.prepare(
|
|
824
|
-
"SELECT * FROM error_records ORDER BY created_at DESC LIMIT ?"
|
|
825
|
-
);
|
|
736
|
+
const stmt = this.db.prepare("SELECT * FROM error_records ORDER BY created_at DESC LIMIT ?");
|
|
826
737
|
return stmt.all(limit).map((row) => this.rowToRecord(row));
|
|
827
738
|
}
|
|
828
|
-
/**
|
|
829
|
-
* Mark error as resolved
|
|
830
|
-
*/
|
|
831
739
|
markResolved(id, data) {
|
|
832
740
|
const stmt = this.db.prepare(`
|
|
833
741
|
UPDATE error_records
|
|
@@ -844,9 +752,6 @@ var LocalStore = class _LocalStore {
|
|
|
844
752
|
}
|
|
845
753
|
return null;
|
|
846
754
|
}
|
|
847
|
-
/**
|
|
848
|
-
* Mark error as uploaded to cloud
|
|
849
|
-
*/
|
|
850
755
|
markUploaded(id, cloudKnowledgeId) {
|
|
851
756
|
const stmt = this.db.prepare(`
|
|
852
757
|
UPDATE error_records
|
|
@@ -860,19 +765,10 @@ var LocalStore = class _LocalStore {
|
|
|
860
765
|
this.incrementStat("uploaded_errors");
|
|
861
766
|
}
|
|
862
767
|
}
|
|
863
|
-
/**
|
|
864
|
-
* Find similar errors by hash
|
|
865
|
-
*/
|
|
866
768
|
findSimilarErrors(errorHash) {
|
|
867
|
-
const stmt = this.db.prepare(
|
|
868
|
-
"SELECT * FROM error_records WHERE error_hash = ? ORDER BY created_at DESC"
|
|
869
|
-
);
|
|
769
|
+
const stmt = this.db.prepare("SELECT * FROM error_records WHERE error_hash = ? ORDER BY created_at DESC");
|
|
870
770
|
return stmt.all(errorHash).map((row) => this.rowToRecord(row));
|
|
871
771
|
}
|
|
872
|
-
// ============ Query Cache ============
|
|
873
|
-
/**
|
|
874
|
-
* Get cached query results
|
|
875
|
-
*/
|
|
876
772
|
getCachedResults(errorHash) {
|
|
877
773
|
const stmt = this.db.prepare(`
|
|
878
774
|
SELECT results FROM query_cache
|
|
@@ -885,10 +781,7 @@ var LocalStore = class _LocalStore {
|
|
|
885
781
|
}
|
|
886
782
|
return null;
|
|
887
783
|
}
|
|
888
|
-
|
|
889
|
-
* Cache query results
|
|
890
|
-
*/
|
|
891
|
-
cacheResults(errorHash, results, expirationMs = 36e5) {
|
|
784
|
+
cacheResults(errorHash, results, expirationMs = 3600000) {
|
|
892
785
|
const id = uuidv4();
|
|
893
786
|
const expiresAt = new Date(Date.now() + expirationMs).toISOString();
|
|
894
787
|
const stmt = this.db.prepare(`
|
|
@@ -898,22 +791,13 @@ var LocalStore = class _LocalStore {
|
|
|
898
791
|
stmt.run(id, errorHash, JSON.stringify(results), expiresAt);
|
|
899
792
|
this.incrementStat("queries_made");
|
|
900
793
|
}
|
|
901
|
-
/**
|
|
902
|
-
* Clear expired cache entries
|
|
903
|
-
*/
|
|
904
794
|
clearExpiredCache() {
|
|
905
795
|
const stmt = this.db.prepare("DELETE FROM query_cache WHERE expires_at <= datetime('now')");
|
|
906
796
|
const result = stmt.run();
|
|
907
797
|
return result.changes;
|
|
908
798
|
}
|
|
909
|
-
// ============ Statistics ============
|
|
910
|
-
/**
|
|
911
|
-
* Get usage statistics
|
|
912
|
-
*/
|
|
913
799
|
getStats() {
|
|
914
|
-
const stmt = this.db.prepare(
|
|
915
|
-
"SELECT total_errors, resolved_errors, uploaded_errors FROM usage_stats WHERE id = 1"
|
|
916
|
-
);
|
|
800
|
+
const stmt = this.db.prepare("SELECT total_errors, resolved_errors, uploaded_errors FROM usage_stats WHERE id = 1");
|
|
917
801
|
const row = stmt.get();
|
|
918
802
|
return {
|
|
919
803
|
totalErrors: row.total_errors,
|
|
@@ -921,89 +805,66 @@ var LocalStore = class _LocalStore {
|
|
|
921
805
|
uploadedErrors: row.uploaded_errors
|
|
922
806
|
};
|
|
923
807
|
}
|
|
924
|
-
/**
|
|
925
|
-
* Allowed stat column names for incrementStat (whitelist to prevent SQL injection)
|
|
926
|
-
*/
|
|
927
808
|
static ALLOWED_STATS = [
|
|
928
809
|
"total_errors",
|
|
929
810
|
"resolved_errors",
|
|
930
811
|
"uploaded_errors",
|
|
931
812
|
"queries_made"
|
|
932
813
|
];
|
|
933
|
-
/**
|
|
934
|
-
* Increment a stat counter
|
|
935
|
-
* @throws Error if stat name is not in the allowed whitelist
|
|
936
|
-
*/
|
|
937
814
|
incrementStat(stat) {
|
|
938
|
-
if (!
|
|
939
|
-
throw new Error(`Invalid stat name: ${stat}. Allowed: ${
|
|
815
|
+
if (!LocalStore.ALLOWED_STATS.includes(stat)) {
|
|
816
|
+
throw new Error(`Invalid stat name: ${stat}. Allowed: ${LocalStore.ALLOWED_STATS.join(", ")}`);
|
|
940
817
|
}
|
|
941
818
|
const stmt = this.db.prepare(`UPDATE usage_stats SET ${stat} = ${stat} + 1 WHERE id = 1`);
|
|
942
819
|
stmt.run();
|
|
943
820
|
}
|
|
944
|
-
// ============ Preferences ============
|
|
945
|
-
/**
|
|
946
|
-
* Get preference value
|
|
947
|
-
*/
|
|
948
821
|
getPreference(key) {
|
|
949
822
|
const stmt = this.db.prepare("SELECT value FROM user_preferences WHERE key = ?");
|
|
950
823
|
const row = stmt.get(key);
|
|
951
824
|
return row?.value || null;
|
|
952
825
|
}
|
|
953
|
-
/**
|
|
954
|
-
* Set preference value
|
|
955
|
-
*/
|
|
956
826
|
setPreference(key, value) {
|
|
957
827
|
const stmt = this.db.prepare(`
|
|
958
828
|
INSERT OR REPLACE INTO user_preferences (key, value) VALUES (?, ?)
|
|
959
829
|
`);
|
|
960
830
|
stmt.run(key, value);
|
|
961
831
|
}
|
|
962
|
-
// ============ Utilities ============
|
|
963
|
-
/**
|
|
964
|
-
* Convert database row to LocalErrorRecord
|
|
965
|
-
*/
|
|
966
832
|
rowToRecord(row) {
|
|
967
833
|
return {
|
|
968
834
|
id: row.id,
|
|
969
835
|
errorHash: row.error_hash,
|
|
970
836
|
errorType: row.error_type,
|
|
971
837
|
errorMessage: row.error_message,
|
|
972
|
-
errorStack: row.error_stack ||
|
|
973
|
-
language: row.language ||
|
|
974
|
-
framework: row.framework ||
|
|
838
|
+
errorStack: row.error_stack || undefined,
|
|
839
|
+
language: row.language || undefined,
|
|
840
|
+
framework: row.framework || undefined,
|
|
975
841
|
toolName: row.tool_name,
|
|
976
842
|
toolInput: JSON.parse(row.tool_input || "{}"),
|
|
977
843
|
sessionId: row.session_id,
|
|
978
844
|
status: row.status,
|
|
979
|
-
resolution: row.resolution ||
|
|
980
|
-
resolutionCode: row.resolution_code ||
|
|
845
|
+
resolution: row.resolution || undefined,
|
|
846
|
+
resolutionCode: row.resolution_code || undefined,
|
|
981
847
|
createdAt: row.created_at,
|
|
982
|
-
resolvedAt: row.resolved_at ||
|
|
983
|
-
uploadedAt: row.uploaded_at ||
|
|
984
|
-
cloudKnowledgeId: row.cloud_knowledge_id ||
|
|
848
|
+
resolvedAt: row.resolved_at || undefined,
|
|
849
|
+
uploadedAt: row.uploaded_at || undefined,
|
|
850
|
+
cloudKnowledgeId: row.cloud_knowledge_id || undefined
|
|
985
851
|
};
|
|
986
852
|
}
|
|
987
|
-
/**
|
|
988
|
-
* Close database connection
|
|
989
|
-
*/
|
|
990
853
|
close() {
|
|
991
854
|
this.db.close();
|
|
992
855
|
}
|
|
993
|
-
/**
|
|
994
|
-
* Get database for advanced queries
|
|
995
|
-
*/
|
|
996
856
|
getDatabase() {
|
|
997
857
|
return this.db;
|
|
998
858
|
}
|
|
999
|
-
}
|
|
859
|
+
}
|
|
1000
860
|
|
|
1001
861
|
// src/cloud/embedding.ts
|
|
1002
862
|
import OpenAI from "openai";
|
|
1003
863
|
var DEFAULT_MODEL = "text-embedding-3-small";
|
|
1004
864
|
var DEFAULT_DIMENSIONS = 1536;
|
|
1005
|
-
var MAX_INPUT_LENGTH =
|
|
1006
|
-
|
|
865
|
+
var MAX_INPUT_LENGTH = 30000;
|
|
866
|
+
|
|
867
|
+
class EmbeddingService {
|
|
1007
868
|
client;
|
|
1008
869
|
model;
|
|
1009
870
|
dimensions;
|
|
@@ -1012,9 +873,6 @@ var EmbeddingService = class {
|
|
|
1012
873
|
this.model = model || DEFAULT_MODEL;
|
|
1013
874
|
this.dimensions = dimensions || DEFAULT_DIMENSIONS;
|
|
1014
875
|
}
|
|
1015
|
-
/**
|
|
1016
|
-
* Generate embedding for a single text
|
|
1017
|
-
*/
|
|
1018
876
|
async generate(text) {
|
|
1019
877
|
const truncated = this.truncateText(text);
|
|
1020
878
|
const response = await this.client.embeddings.create({
|
|
@@ -1024,9 +882,6 @@ var EmbeddingService = class {
|
|
|
1024
882
|
});
|
|
1025
883
|
return response.data[0].embedding;
|
|
1026
884
|
}
|
|
1027
|
-
/**
|
|
1028
|
-
* Generate embeddings for multiple texts
|
|
1029
|
-
*/
|
|
1030
885
|
async generateBatch(texts) {
|
|
1031
886
|
const truncated = texts.map((t) => this.truncateText(t));
|
|
1032
887
|
const response = await this.client.embeddings.create({
|
|
@@ -1036,10 +891,6 @@ var EmbeddingService = class {
|
|
|
1036
891
|
});
|
|
1037
892
|
return response.data.map((d) => d.embedding);
|
|
1038
893
|
}
|
|
1039
|
-
/**
|
|
1040
|
-
* Generate embedding for error context
|
|
1041
|
-
* Combines error message, stack trace, and context
|
|
1042
|
-
*/
|
|
1043
894
|
async generateErrorEmbedding(errorMessage, errorStack, context) {
|
|
1044
895
|
const parts = [];
|
|
1045
896
|
if (context?.language) {
|
|
@@ -1053,26 +904,22 @@ var EmbeddingService = class {
|
|
|
1053
904
|
parts.push(`Stack Trace:
|
|
1054
905
|
${errorStack}`);
|
|
1055
906
|
}
|
|
1056
|
-
const text = parts.join(
|
|
907
|
+
const text = parts.join(`
|
|
908
|
+
`);
|
|
1057
909
|
return this.generate(text);
|
|
1058
910
|
}
|
|
1059
|
-
/**
|
|
1060
|
-
* Truncate text to fit within model limits
|
|
1061
|
-
*/
|
|
1062
911
|
truncateText(text) {
|
|
1063
912
|
if (text.length <= MAX_INPUT_LENGTH) {
|
|
1064
913
|
return text;
|
|
1065
914
|
}
|
|
1066
915
|
const truncated = text.substring(0, MAX_INPUT_LENGTH);
|
|
1067
|
-
const lastNewline = truncated.lastIndexOf(
|
|
916
|
+
const lastNewline = truncated.lastIndexOf(`
|
|
917
|
+
`);
|
|
1068
918
|
if (lastNewline > MAX_INPUT_LENGTH * 0.8) {
|
|
1069
919
|
return truncated.substring(0, lastNewline);
|
|
1070
920
|
}
|
|
1071
921
|
return truncated;
|
|
1072
922
|
}
|
|
1073
|
-
/**
|
|
1074
|
-
* Calculate cosine similarity between two embeddings
|
|
1075
|
-
*/
|
|
1076
923
|
static cosineSimilarity(a, b) {
|
|
1077
924
|
if (a.length !== b.length) {
|
|
1078
925
|
throw new Error("Embeddings must have same dimensions");
|
|
@@ -1080,28 +927,23 @@ ${errorStack}`);
|
|
|
1080
927
|
let dotProduct = 0;
|
|
1081
928
|
let normA = 0;
|
|
1082
929
|
let normB = 0;
|
|
1083
|
-
for (let i = 0;
|
|
930
|
+
for (let i = 0;i < a.length; i++) {
|
|
1084
931
|
dotProduct += a[i] * b[i];
|
|
1085
932
|
normA += a[i] * a[i];
|
|
1086
933
|
normB += b[i] * b[i];
|
|
1087
934
|
}
|
|
1088
935
|
const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
|
|
1089
|
-
if (magnitude === 0)
|
|
936
|
+
if (magnitude === 0)
|
|
937
|
+
return 0;
|
|
1090
938
|
return dotProduct / magnitude;
|
|
1091
939
|
}
|
|
1092
|
-
/**
|
|
1093
|
-
* Get embedding dimensions
|
|
1094
|
-
*/
|
|
1095
940
|
getDimensions() {
|
|
1096
941
|
return this.dimensions;
|
|
1097
942
|
}
|
|
1098
|
-
/**
|
|
1099
|
-
* Get model name
|
|
1100
|
-
*/
|
|
1101
943
|
getModel() {
|
|
1102
944
|
return this.model;
|
|
1103
945
|
}
|
|
1104
|
-
}
|
|
946
|
+
}
|
|
1105
947
|
function createEmbeddingService(config) {
|
|
1106
948
|
return new EmbeddingService(config.apiKey, config.model, config.dimensions);
|
|
1107
949
|
}
|
|
@@ -1115,7 +957,8 @@ async function getCreateClient() {
|
|
|
1115
957
|
}
|
|
1116
958
|
return createClient;
|
|
1117
959
|
}
|
|
1118
|
-
|
|
960
|
+
|
|
961
|
+
class CloudClient {
|
|
1119
962
|
supabase;
|
|
1120
963
|
embedding;
|
|
1121
964
|
contributorId;
|
|
@@ -1126,9 +969,6 @@ var CloudClient = class _CloudClient {
|
|
|
1126
969
|
this.contributorId = contributorId;
|
|
1127
970
|
this.similarityThreshold = similarityThreshold;
|
|
1128
971
|
}
|
|
1129
|
-
/**
|
|
1130
|
-
* Create a CloudClient instance (async factory for Bun compatibility)
|
|
1131
|
-
*/
|
|
1132
972
|
static async create(config) {
|
|
1133
973
|
const createClientFn = await getCreateClient();
|
|
1134
974
|
const supabase = createClientFn(config.supabaseUrl, config.supabaseAnonKey);
|
|
@@ -1142,11 +982,8 @@ var CloudClient = class _CloudClient {
|
|
|
1142
982
|
}
|
|
1143
983
|
const contributorId = config.contributorId || generateContributorId();
|
|
1144
984
|
const similarityThreshold = config.similarityThreshold || 0.7;
|
|
1145
|
-
return new
|
|
985
|
+
return new CloudClient(supabase, embedding, contributorId, similarityThreshold);
|
|
1146
986
|
}
|
|
1147
|
-
/**
|
|
1148
|
-
* Search for similar errors in cloud knowledge base
|
|
1149
|
-
*/
|
|
1150
987
|
async searchSimilar(request) {
|
|
1151
988
|
const startTime = Date.now();
|
|
1152
989
|
if (!this.embedding) {
|
|
@@ -1172,9 +1009,6 @@ ${request.errorStack || ""}`;
|
|
|
1172
1009
|
cached: false
|
|
1173
1010
|
};
|
|
1174
1011
|
}
|
|
1175
|
-
/**
|
|
1176
|
-
* Fallback text-based search
|
|
1177
|
-
*/
|
|
1178
1012
|
async searchByText(request) {
|
|
1179
1013
|
const startTime = Date.now();
|
|
1180
1014
|
let query = this.supabase.from("knowledge_entries").select("*").ilike("error_message", `%${request.errorMessage.substring(0, 100)}%`).order("upvotes", { ascending: false }).limit(request.limit || 10);
|
|
@@ -1195,9 +1029,6 @@ ${request.errorStack || ""}`;
|
|
|
1195
1029
|
cached: false
|
|
1196
1030
|
};
|
|
1197
1031
|
}
|
|
1198
|
-
/**
|
|
1199
|
-
* Upload a resolution to cloud knowledge base
|
|
1200
|
-
*/
|
|
1201
1032
|
async uploadResolution(request) {
|
|
1202
1033
|
const { errorRecord, resolution, resolutionCode, resolutionSteps } = request;
|
|
1203
1034
|
let embedding = null;
|
|
@@ -1247,9 +1078,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1247
1078
|
message: "Solution uploaded successfully!"
|
|
1248
1079
|
};
|
|
1249
1080
|
}
|
|
1250
|
-
/**
|
|
1251
|
-
* Check for duplicate entries
|
|
1252
|
-
*/
|
|
1253
1081
|
async checkDuplicate(errorHash, embedding) {
|
|
1254
1082
|
const { data: hashMatch } = await this.supabase.from("knowledge_entries").select("id").eq("error_hash", errorHash).limit(1).single();
|
|
1255
1083
|
if (hashMatch) {
|
|
@@ -1274,9 +1102,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1274
1102
|
similarityScore: result.similarity_score
|
|
1275
1103
|
};
|
|
1276
1104
|
}
|
|
1277
|
-
/**
|
|
1278
|
-
* Vote on a knowledge entry (with duplicate vote prevention)
|
|
1279
|
-
*/
|
|
1280
1105
|
async vote(knowledgeId, helpful) {
|
|
1281
1106
|
const voteType = helpful ? "up" : "down";
|
|
1282
1107
|
const { data, error } = await this.supabase.rpc("safe_vote", {
|
|
@@ -1297,9 +1122,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1297
1122
|
}
|
|
1298
1123
|
return result;
|
|
1299
1124
|
}
|
|
1300
|
-
/**
|
|
1301
|
-
* Report an entry for review
|
|
1302
|
-
*/
|
|
1303
1125
|
async reportEntry(knowledgeId, reason) {
|
|
1304
1126
|
const { data, error } = await this.supabase.rpc("report_entry", {
|
|
1305
1127
|
p_entry_id: knowledgeId,
|
|
@@ -1311,9 +1133,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1311
1133
|
}
|
|
1312
1134
|
return data;
|
|
1313
1135
|
}
|
|
1314
|
-
/**
|
|
1315
|
-
* Report helpful usage
|
|
1316
|
-
*/
|
|
1317
1136
|
async reportHelpful(knowledgeId) {
|
|
1318
1137
|
await this.supabase.rpc("increment_usage_count", {
|
|
1319
1138
|
entry_id: knowledgeId
|
|
@@ -1324,9 +1143,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1324
1143
|
user_hash: this.contributorId
|
|
1325
1144
|
});
|
|
1326
1145
|
}
|
|
1327
|
-
/**
|
|
1328
|
-
* Get contributor statistics
|
|
1329
|
-
*/
|
|
1330
1146
|
async getContributorStats() {
|
|
1331
1147
|
const { data } = await this.supabase.from("knowledge_entries").select("upvotes, usage_count").eq("contributor_id", this.contributorId);
|
|
1332
1148
|
if (!data || data.length === 0) {
|
|
@@ -1338,9 +1154,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1338
1154
|
totalUpvotes: data.reduce((sum, e) => sum + (e.upvotes || 0), 0)
|
|
1339
1155
|
};
|
|
1340
1156
|
}
|
|
1341
|
-
/**
|
|
1342
|
-
* Get entry by ID
|
|
1343
|
-
*/
|
|
1344
1157
|
async getEntry(id) {
|
|
1345
1158
|
const { data, error } = await this.supabase.from("knowledge_entries").select("*").eq("id", id).single();
|
|
1346
1159
|
if (error || !data) {
|
|
@@ -1348,22 +1161,19 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1348
1161
|
}
|
|
1349
1162
|
return this.mapToKnowledgeEntry(data);
|
|
1350
1163
|
}
|
|
1351
|
-
/**
|
|
1352
|
-
* Map database row to CloudKnowledgeEntry
|
|
1353
|
-
*/
|
|
1354
1164
|
mapToKnowledgeEntry(row) {
|
|
1355
1165
|
return {
|
|
1356
1166
|
id: row.id,
|
|
1357
1167
|
errorHash: row.error_hash,
|
|
1358
1168
|
errorType: row.error_type,
|
|
1359
1169
|
errorMessage: row.error_message,
|
|
1360
|
-
errorStack: row.error_stack ||
|
|
1170
|
+
errorStack: row.error_stack || undefined,
|
|
1361
1171
|
language: row.language,
|
|
1362
|
-
framework: row.framework ||
|
|
1363
|
-
dependencies: row.dependencies ||
|
|
1172
|
+
framework: row.framework || undefined,
|
|
1173
|
+
dependencies: row.dependencies || undefined,
|
|
1364
1174
|
resolutionDescription: row.resolution_description,
|
|
1365
|
-
resolutionCode: row.resolution_code ||
|
|
1366
|
-
resolutionSteps: row.resolution_steps ||
|
|
1175
|
+
resolutionCode: row.resolution_code || undefined,
|
|
1176
|
+
resolutionSteps: row.resolution_steps || undefined,
|
|
1367
1177
|
contributorId: row.contributor_id,
|
|
1368
1178
|
upvotes: row.upvotes || 0,
|
|
1369
1179
|
downvotes: row.downvotes || 0,
|
|
@@ -1371,22 +1181,16 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1371
1181
|
createdAt: row.created_at,
|
|
1372
1182
|
updatedAt: row.updated_at,
|
|
1373
1183
|
isVerified: row.is_verified || false,
|
|
1374
|
-
similarity: row.similarity ||
|
|
1184
|
+
similarity: row.similarity || undefined
|
|
1375
1185
|
};
|
|
1376
1186
|
}
|
|
1377
|
-
/**
|
|
1378
|
-
* Get contributor ID
|
|
1379
|
-
*/
|
|
1380
1187
|
getContributorId() {
|
|
1381
1188
|
return this.contributorId;
|
|
1382
1189
|
}
|
|
1383
|
-
/**
|
|
1384
|
-
* Check if embedding service is available
|
|
1385
|
-
*/
|
|
1386
1190
|
hasEmbeddingService() {
|
|
1387
1191
|
return this.embedding !== null;
|
|
1388
1192
|
}
|
|
1389
|
-
}
|
|
1193
|
+
}
|
|
1390
1194
|
async function createCloudClient(config) {
|
|
1391
1195
|
return CloudClient.create(config);
|
|
1392
1196
|
}
|
|
@@ -1395,9 +1199,6 @@ async function createCloudClient(config) {
|
|
|
1395
1199
|
import { tool } from "@opencode-ai/plugin";
|
|
1396
1200
|
function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
1397
1201
|
return {
|
|
1398
|
-
/**
|
|
1399
|
-
* Search cloud knowledge base for error solutions
|
|
1400
|
-
*/
|
|
1401
1202
|
fixhive_search: tool({
|
|
1402
1203
|
description: "Search FixHive knowledge base for error solutions. Use when encountering errors to find community solutions.",
|
|
1403
1204
|
args: {
|
|
@@ -1426,9 +1227,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1426
1227
|
return formatSearchResults(results.results, false);
|
|
1427
1228
|
}
|
|
1428
1229
|
}),
|
|
1429
|
-
/**
|
|
1430
|
-
* Mark error as resolved and optionally upload solution
|
|
1431
|
-
*/
|
|
1432
1230
|
fixhive_resolve: tool({
|
|
1433
1231
|
description: "Mark an error as resolved and optionally share the solution with the community.",
|
|
1434
1232
|
args: {
|
|
@@ -1464,9 +1262,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1464
1262
|
return "Error marked as resolved locally.";
|
|
1465
1263
|
}
|
|
1466
1264
|
}),
|
|
1467
|
-
/**
|
|
1468
|
-
* List errors in current session
|
|
1469
|
-
*/
|
|
1470
1265
|
fixhive_list: tool({
|
|
1471
1266
|
description: "List errors detected in the current session.",
|
|
1472
1267
|
args: {
|
|
@@ -1485,9 +1280,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1485
1280
|
return formatErrorList(errors);
|
|
1486
1281
|
}
|
|
1487
1282
|
}),
|
|
1488
|
-
/**
|
|
1489
|
-
* Vote on a solution
|
|
1490
|
-
*/
|
|
1491
1283
|
fixhive_vote: tool({
|
|
1492
1284
|
description: "Upvote or downvote a FixHive solution based on whether it helped.",
|
|
1493
1285
|
args: {
|
|
@@ -1505,9 +1297,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1505
1297
|
return args.helpful ? "Thanks for the feedback! Solution upvoted." : "Thanks for the feedback! Solution downvoted.";
|
|
1506
1298
|
}
|
|
1507
1299
|
}),
|
|
1508
|
-
/**
|
|
1509
|
-
* Report inappropriate content
|
|
1510
|
-
*/
|
|
1511
1300
|
fixhive_report: tool({
|
|
1512
1301
|
description: "Report a FixHive solution for inappropriate content, spam, or incorrect information.",
|
|
1513
1302
|
args: {
|
|
@@ -1522,9 +1311,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1522
1311
|
return "Report submitted. Thank you for helping keep FixHive clean!";
|
|
1523
1312
|
}
|
|
1524
1313
|
}),
|
|
1525
|
-
/**
|
|
1526
|
-
* Get usage statistics
|
|
1527
|
-
*/
|
|
1528
1314
|
fixhive_stats: tool({
|
|
1529
1315
|
description: "Get FixHive usage statistics.",
|
|
1530
1316
|
args: {},
|
|
@@ -1546,9 +1332,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1546
1332
|
`;
|
|
1547
1333
|
}
|
|
1548
1334
|
}),
|
|
1549
|
-
/**
|
|
1550
|
-
* Report that a solution was helpful
|
|
1551
|
-
*/
|
|
1552
1335
|
fixhive_helpful: tool({
|
|
1553
1336
|
description: "Report that a FixHive solution was helpful and resolved your issue.",
|
|
1554
1337
|
args: {
|
|
@@ -1583,7 +1366,8 @@ ${r.resolutionCode}
|
|
|
1583
1366
|
if (r.resolutionSteps?.length) {
|
|
1584
1367
|
entry += `
|
|
1585
1368
|
**Steps:**
|
|
1586
|
-
${r.resolutionSteps.map((s, j) => `${j + 1}. ${s}`).join(
|
|
1369
|
+
${r.resolutionSteps.map((s, j) => `${j + 1}. ${s}`).join(`
|
|
1370
|
+
`)}
|
|
1587
1371
|
`;
|
|
1588
1372
|
}
|
|
1589
1373
|
entry += `
|
|
@@ -1591,7 +1375,8 @@ ${r.resolutionSteps.map((s, j) => `${j + 1}. ${s}`).join("\n")}
|
|
|
1591
1375
|
|
|
1592
1376
|
---`;
|
|
1593
1377
|
return entry;
|
|
1594
|
-
}).join(
|
|
1378
|
+
}).join(`
|
|
1379
|
+
`);
|
|
1595
1380
|
return `${header}
|
|
1596
1381
|
${entries}
|
|
1597
1382
|
|
|
@@ -1602,9 +1387,8 @@ function formatErrorList(errors) {
|
|
|
1602
1387
|
const table = `
|
|
1603
1388
|
| ID | Type | Status | Message |
|
|
1604
1389
|
|----|------|--------|---------|
|
|
1605
|
-
${errors.map(
|
|
1606
|
-
|
|
1607
|
-
).join("\n")}
|
|
1390
|
+
${errors.map((e) => `| ${e.id.slice(0, 8)} | ${e.errorType} | ${e.status} | ${e.errorMessage.slice(0, 50)}... |`).join(`
|
|
1391
|
+
`)}
|
|
1608
1392
|
`;
|
|
1609
1393
|
return `${header}
|
|
1610
1394
|
${table}
|
|
@@ -1614,8 +1398,7 @@ Use \`fixhive_resolve <id>\` to mark as resolved and share solutions.`;
|
|
|
1614
1398
|
|
|
1615
1399
|
// src/plugin/index.ts
|
|
1616
1400
|
var DEFAULT_CONFIG = {
|
|
1617
|
-
cacheExpirationMs:
|
|
1618
|
-
// 1 hour
|
|
1401
|
+
cacheExpirationMs: 3600000,
|
|
1619
1402
|
embeddingModel: "text-embedding-3-small",
|
|
1620
1403
|
embeddingDimensions: 1536,
|
|
1621
1404
|
similarityThreshold: 0.7,
|
|
@@ -1626,7 +1409,7 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1626
1409
|
console.log("[FixHive] Plugin loaded");
|
|
1627
1410
|
console.log(`[FixHive] Project: ${ctx.directory}`);
|
|
1628
1411
|
console.log(`[FixHive] Cloud: ${config.supabaseUrl ? "enabled" : "disabled"}`);
|
|
1629
|
-
const privacyFilter = new PrivacyFilter
|
|
1412
|
+
const privacyFilter = new PrivacyFilter;
|
|
1630
1413
|
const filterContext = createFilterContext(ctx.directory);
|
|
1631
1414
|
const errorDetector = new ErrorDetector(privacyFilter);
|
|
1632
1415
|
const localStore = new LocalStore(ctx.directory);
|
|
@@ -1657,9 +1440,9 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1657
1440
|
console.log("[FixHive] Ready - use fixhive_stats to verify");
|
|
1658
1441
|
const errorProducingTools = ["bash", "edit", "write", "read", "terminal"];
|
|
1659
1442
|
return {
|
|
1660
|
-
// ============ Tool Execution Hook ============
|
|
1661
1443
|
"tool.execute.after": async (input, output) => {
|
|
1662
|
-
if (!errorProducingTools.includes(input.tool))
|
|
1444
|
+
if (!errorProducingTools.includes(input.tool))
|
|
1445
|
+
return;
|
|
1663
1446
|
const detection = errorDetector.detect({
|
|
1664
1447
|
tool: input.tool,
|
|
1665
1448
|
output: output.output,
|
|
@@ -1669,7 +1452,7 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1669
1452
|
});
|
|
1670
1453
|
if (detection.detected && detection.confidence >= 0.5) {
|
|
1671
1454
|
const sanitizedErrorMessage = privacyFilter.sanitize(detection.errorMessage, filterContext).sanitized;
|
|
1672
|
-
const sanitizedErrorStack = detection.errorStack ? privacyFilter.sanitize(detection.errorStack, filterContext).sanitized :
|
|
1455
|
+
const sanitizedErrorStack = detection.errorStack ? privacyFilter.sanitize(detection.errorStack, filterContext).sanitized : undefined;
|
|
1673
1456
|
localStore.createErrorRecord({
|
|
1674
1457
|
errorType: detection.errorType,
|
|
1675
1458
|
errorMessage: sanitizedErrorMessage,
|
|
@@ -1678,7 +1461,6 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1678
1461
|
framework: pluginContext.framework,
|
|
1679
1462
|
toolName: input.tool,
|
|
1680
1463
|
toolInput: {},
|
|
1681
|
-
// Tool input is intentionally omitted to avoid storing sensitive data
|
|
1682
1464
|
sessionId: pluginContext.sessionId || input.sessionID
|
|
1683
1465
|
});
|
|
1684
1466
|
if (cloudClient) {
|
|
@@ -1691,10 +1473,7 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1691
1473
|
limit: 3
|
|
1692
1474
|
});
|
|
1693
1475
|
if (solutions.results.length > 0) {
|
|
1694
|
-
localStore.cacheResults(
|
|
1695
|
-
generateErrorFingerprint(sanitizedErrorMessage, sanitizedErrorStack),
|
|
1696
|
-
solutions.results
|
|
1697
|
-
);
|
|
1476
|
+
localStore.cacheResults(generateErrorFingerprint(sanitizedErrorMessage, sanitizedErrorStack), solutions.results);
|
|
1698
1477
|
output.title = `${output.title} [FixHive: ${solutions.results.length} solution(s) found]`;
|
|
1699
1478
|
}
|
|
1700
1479
|
} catch (e) {
|
|
@@ -1704,24 +1483,22 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1704
1483
|
}
|
|
1705
1484
|
}
|
|
1706
1485
|
},
|
|
1707
|
-
// ============ Session Compaction Hook ============
|
|
1708
1486
|
"experimental.session.compacting": async (_input, output) => {
|
|
1709
1487
|
const unresolvedErrors = localStore.getUnresolvedErrors(pluginContext.sessionId);
|
|
1710
1488
|
if (unresolvedErrors.length > 0) {
|
|
1711
1489
|
output.context.push(`
|
|
1712
1490
|
## FixHive: Unresolved Errors in Session
|
|
1713
1491
|
|
|
1714
|
-
${unresolvedErrors.map((e) => `- [${e.id.slice(0, 8)}] ${e.errorType}: ${e.errorMessage.slice(0, 100)}...`).join(
|
|
1492
|
+
${unresolvedErrors.map((e) => `- [${e.id.slice(0, 8)}] ${e.errorType}: ${e.errorMessage.slice(0, 100)}...`).join(`
|
|
1493
|
+
`)}
|
|
1715
1494
|
|
|
1716
1495
|
Use \`fixhive_mark_resolved\` when errors are fixed to contribute solutions.
|
|
1717
1496
|
`);
|
|
1718
1497
|
}
|
|
1719
1498
|
},
|
|
1720
|
-
// ============ Chat Message Hook ============
|
|
1721
1499
|
"chat.message": async (input, _output) => {
|
|
1722
1500
|
pluginContext.sessionId = input.sessionID;
|
|
1723
1501
|
},
|
|
1724
|
-
// ============ Custom Tools ============
|
|
1725
1502
|
tool: cloudClient ? createTools(localStore, cloudClient, privacyFilter, pluginContext) : createOfflineTools(localStore, privacyFilter, pluginContext)
|
|
1726
1503
|
};
|
|
1727
1504
|
};
|
|
@@ -1744,7 +1521,8 @@ function createOfflineTools(localStore, _privacyFilter, context) {
|
|
|
1744
1521
|
}
|
|
1745
1522
|
return `## Session Errors (${errors.length})
|
|
1746
1523
|
|
|
1747
|
-
${errors.map((e) => `- [${e.id.slice(0, 8)}] ${e.errorType}: ${e.errorMessage.slice(0, 80)}...`).join(
|
|
1524
|
+
${errors.map((e) => `- [${e.id.slice(0, 8)}] ${e.errorType}: ${e.errorMessage.slice(0, 80)}...`).join(`
|
|
1525
|
+
`)}
|
|
1748
1526
|
|
|
1749
1527
|
*Cloud features disabled. Set FIXHIVE_SUPABASE_URL and FIXHIVE_SUPABASE_KEY to enable.*`;
|
|
1750
1528
|
}
|
|
@@ -1803,7 +1581,7 @@ function detectLanguage(directory) {
|
|
|
1803
1581
|
return lang;
|
|
1804
1582
|
}
|
|
1805
1583
|
}
|
|
1806
|
-
return
|
|
1584
|
+
return;
|
|
1807
1585
|
}
|
|
1808
1586
|
function detectFramework(directory) {
|
|
1809
1587
|
const pkgPath = join(directory, "package.json");
|
|
@@ -1811,49 +1589,57 @@ function detectFramework(directory) {
|
|
|
1811
1589
|
try {
|
|
1812
1590
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
1813
1591
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1814
|
-
if (deps["next"])
|
|
1815
|
-
|
|
1816
|
-
if (deps["
|
|
1817
|
-
|
|
1818
|
-
if (deps["
|
|
1819
|
-
|
|
1820
|
-
if (deps["
|
|
1821
|
-
|
|
1822
|
-
|
|
1592
|
+
if (deps["next"])
|
|
1593
|
+
return "nextjs";
|
|
1594
|
+
if (deps["react"])
|
|
1595
|
+
return "react";
|
|
1596
|
+
if (deps["vue"])
|
|
1597
|
+
return "vue";
|
|
1598
|
+
if (deps["@angular/core"])
|
|
1599
|
+
return "angular";
|
|
1600
|
+
if (deps["express"])
|
|
1601
|
+
return "express";
|
|
1602
|
+
if (deps["fastify"])
|
|
1603
|
+
return "fastify";
|
|
1604
|
+
if (deps["hono"])
|
|
1605
|
+
return "hono";
|
|
1606
|
+
} catch {}
|
|
1823
1607
|
}
|
|
1824
1608
|
const reqPath = join(directory, "requirements.txt");
|
|
1825
1609
|
if (existsSync2(reqPath)) {
|
|
1826
1610
|
try {
|
|
1827
1611
|
const content = readFileSync(reqPath, "utf-8");
|
|
1828
|
-
if (content.includes("django"))
|
|
1829
|
-
|
|
1830
|
-
if (content.includes("
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1612
|
+
if (content.includes("django"))
|
|
1613
|
+
return "django";
|
|
1614
|
+
if (content.includes("flask"))
|
|
1615
|
+
return "flask";
|
|
1616
|
+
if (content.includes("fastapi"))
|
|
1617
|
+
return "fastapi";
|
|
1618
|
+
} catch {}
|
|
1619
|
+
}
|
|
1620
|
+
return;
|
|
1835
1621
|
}
|
|
1836
1622
|
var plugin_default = FixHivePlugin;
|
|
1837
1623
|
export {
|
|
1838
|
-
|
|
1839
|
-
EmbeddingService,
|
|
1840
|
-
ErrorDetector,
|
|
1841
|
-
FixHivePlugin,
|
|
1842
|
-
LocalStore,
|
|
1843
|
-
PrivacyFilter,
|
|
1844
|
-
calculateStringSimilarity,
|
|
1845
|
-
createCloudClient,
|
|
1846
|
-
createEmbeddingService,
|
|
1847
|
-
createFilterContext,
|
|
1848
|
-
plugin_default as default,
|
|
1849
|
-
defaultErrorDetector,
|
|
1850
|
-
defaultPrivacyFilter,
|
|
1851
|
-
fingerprintsMatch,
|
|
1852
|
-
generateContributorId,
|
|
1853
|
-
generateErrorFingerprint,
|
|
1854
|
-
generateSessionHash,
|
|
1855
|
-
normalizeErrorContent,
|
|
1856
|
-
runMigrations,
|
|
1624
|
+
shortHash,
|
|
1857
1625
|
sha256,
|
|
1858
|
-
|
|
1626
|
+
runMigrations,
|
|
1627
|
+
normalizeErrorContent,
|
|
1628
|
+
generateSessionHash,
|
|
1629
|
+
generateErrorFingerprint,
|
|
1630
|
+
generateContributorId,
|
|
1631
|
+
fingerprintsMatch,
|
|
1632
|
+
defaultPrivacyFilter,
|
|
1633
|
+
defaultErrorDetector,
|
|
1634
|
+
plugin_default as default,
|
|
1635
|
+
createFilterContext,
|
|
1636
|
+
createEmbeddingService,
|
|
1637
|
+
createCloudClient,
|
|
1638
|
+
calculateStringSimilarity,
|
|
1639
|
+
PrivacyFilter,
|
|
1640
|
+
LocalStore,
|
|
1641
|
+
FixHivePlugin,
|
|
1642
|
+
ErrorDetector,
|
|
1643
|
+
EmbeddingService,
|
|
1644
|
+
CloudClient
|
|
1859
1645
|
};
|