@the-magic-tower/fixhive-opencode-plugin 0.1.12 → 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 -615
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +194 -394
- 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,92 +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
|
-
}
|
|
1000
|
-
|
|
1001
|
-
// src/cloud/client.ts
|
|
1002
|
-
import { createClient } from "@supabase/supabase-js";
|
|
859
|
+
}
|
|
1003
860
|
|
|
1004
861
|
// src/cloud/embedding.ts
|
|
1005
862
|
import OpenAI from "openai";
|
|
1006
863
|
var DEFAULT_MODEL = "text-embedding-3-small";
|
|
1007
864
|
var DEFAULT_DIMENSIONS = 1536;
|
|
1008
|
-
var MAX_INPUT_LENGTH =
|
|
1009
|
-
|
|
865
|
+
var MAX_INPUT_LENGTH = 30000;
|
|
866
|
+
|
|
867
|
+
class EmbeddingService {
|
|
1010
868
|
client;
|
|
1011
869
|
model;
|
|
1012
870
|
dimensions;
|
|
@@ -1015,9 +873,6 @@ var EmbeddingService = class {
|
|
|
1015
873
|
this.model = model || DEFAULT_MODEL;
|
|
1016
874
|
this.dimensions = dimensions || DEFAULT_DIMENSIONS;
|
|
1017
875
|
}
|
|
1018
|
-
/**
|
|
1019
|
-
* Generate embedding for a single text
|
|
1020
|
-
*/
|
|
1021
876
|
async generate(text) {
|
|
1022
877
|
const truncated = this.truncateText(text);
|
|
1023
878
|
const response = await this.client.embeddings.create({
|
|
@@ -1027,9 +882,6 @@ var EmbeddingService = class {
|
|
|
1027
882
|
});
|
|
1028
883
|
return response.data[0].embedding;
|
|
1029
884
|
}
|
|
1030
|
-
/**
|
|
1031
|
-
* Generate embeddings for multiple texts
|
|
1032
|
-
*/
|
|
1033
885
|
async generateBatch(texts) {
|
|
1034
886
|
const truncated = texts.map((t) => this.truncateText(t));
|
|
1035
887
|
const response = await this.client.embeddings.create({
|
|
@@ -1039,10 +891,6 @@ var EmbeddingService = class {
|
|
|
1039
891
|
});
|
|
1040
892
|
return response.data.map((d) => d.embedding);
|
|
1041
893
|
}
|
|
1042
|
-
/**
|
|
1043
|
-
* Generate embedding for error context
|
|
1044
|
-
* Combines error message, stack trace, and context
|
|
1045
|
-
*/
|
|
1046
894
|
async generateErrorEmbedding(errorMessage, errorStack, context) {
|
|
1047
895
|
const parts = [];
|
|
1048
896
|
if (context?.language) {
|
|
@@ -1056,26 +904,22 @@ var EmbeddingService = class {
|
|
|
1056
904
|
parts.push(`Stack Trace:
|
|
1057
905
|
${errorStack}`);
|
|
1058
906
|
}
|
|
1059
|
-
const text = parts.join(
|
|
907
|
+
const text = parts.join(`
|
|
908
|
+
`);
|
|
1060
909
|
return this.generate(text);
|
|
1061
910
|
}
|
|
1062
|
-
/**
|
|
1063
|
-
* Truncate text to fit within model limits
|
|
1064
|
-
*/
|
|
1065
911
|
truncateText(text) {
|
|
1066
912
|
if (text.length <= MAX_INPUT_LENGTH) {
|
|
1067
913
|
return text;
|
|
1068
914
|
}
|
|
1069
915
|
const truncated = text.substring(0, MAX_INPUT_LENGTH);
|
|
1070
|
-
const lastNewline = truncated.lastIndexOf(
|
|
916
|
+
const lastNewline = truncated.lastIndexOf(`
|
|
917
|
+
`);
|
|
1071
918
|
if (lastNewline > MAX_INPUT_LENGTH * 0.8) {
|
|
1072
919
|
return truncated.substring(0, lastNewline);
|
|
1073
920
|
}
|
|
1074
921
|
return truncated;
|
|
1075
922
|
}
|
|
1076
|
-
/**
|
|
1077
|
-
* Calculate cosine similarity between two embeddings
|
|
1078
|
-
*/
|
|
1079
923
|
static cosineSimilarity(a, b) {
|
|
1080
924
|
if (a.length !== b.length) {
|
|
1081
925
|
throw new Error("Embeddings must have same dimensions");
|
|
@@ -1083,56 +927,63 @@ ${errorStack}`);
|
|
|
1083
927
|
let dotProduct = 0;
|
|
1084
928
|
let normA = 0;
|
|
1085
929
|
let normB = 0;
|
|
1086
|
-
for (let i = 0;
|
|
930
|
+
for (let i = 0;i < a.length; i++) {
|
|
1087
931
|
dotProduct += a[i] * b[i];
|
|
1088
932
|
normA += a[i] * a[i];
|
|
1089
933
|
normB += b[i] * b[i];
|
|
1090
934
|
}
|
|
1091
935
|
const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
|
|
1092
|
-
if (magnitude === 0)
|
|
936
|
+
if (magnitude === 0)
|
|
937
|
+
return 0;
|
|
1093
938
|
return dotProduct / magnitude;
|
|
1094
939
|
}
|
|
1095
|
-
/**
|
|
1096
|
-
* Get embedding dimensions
|
|
1097
|
-
*/
|
|
1098
940
|
getDimensions() {
|
|
1099
941
|
return this.dimensions;
|
|
1100
942
|
}
|
|
1101
|
-
/**
|
|
1102
|
-
* Get model name
|
|
1103
|
-
*/
|
|
1104
943
|
getModel() {
|
|
1105
944
|
return this.model;
|
|
1106
945
|
}
|
|
1107
|
-
}
|
|
946
|
+
}
|
|
1108
947
|
function createEmbeddingService(config) {
|
|
1109
948
|
return new EmbeddingService(config.apiKey, config.model, config.dimensions);
|
|
1110
949
|
}
|
|
1111
950
|
|
|
1112
951
|
// src/cloud/client.ts
|
|
1113
|
-
var
|
|
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
|
+
|
|
961
|
+
class CloudClient {
|
|
1114
962
|
supabase;
|
|
1115
963
|
embedding;
|
|
1116
964
|
contributorId;
|
|
1117
965
|
similarityThreshold;
|
|
1118
|
-
constructor(
|
|
1119
|
-
this.supabase =
|
|
966
|
+
constructor(supabase, embedding, contributorId, similarityThreshold) {
|
|
967
|
+
this.supabase = supabase;
|
|
968
|
+
this.embedding = embedding;
|
|
969
|
+
this.contributorId = contributorId;
|
|
970
|
+
this.similarityThreshold = similarityThreshold;
|
|
971
|
+
}
|
|
972
|
+
static async create(config) {
|
|
973
|
+
const createClientFn = await getCreateClient();
|
|
974
|
+
const supabase = createClientFn(config.supabaseUrl, config.supabaseAnonKey);
|
|
975
|
+
let embedding = null;
|
|
1120
976
|
if (config.openaiApiKey) {
|
|
1121
977
|
try {
|
|
1122
|
-
|
|
978
|
+
embedding = new EmbeddingService(config.openaiApiKey);
|
|
1123
979
|
} catch (err) {
|
|
1124
980
|
console.warn("[FixHive] Failed to initialize embedding service:", err);
|
|
1125
|
-
this.embedding = null;
|
|
1126
981
|
}
|
|
1127
|
-
} else {
|
|
1128
|
-
this.embedding = null;
|
|
1129
982
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
983
|
+
const contributorId = config.contributorId || generateContributorId();
|
|
984
|
+
const similarityThreshold = config.similarityThreshold || 0.7;
|
|
985
|
+
return new CloudClient(supabase, embedding, contributorId, similarityThreshold);
|
|
1132
986
|
}
|
|
1133
|
-
/**
|
|
1134
|
-
* Search for similar errors in cloud knowledge base
|
|
1135
|
-
*/
|
|
1136
987
|
async searchSimilar(request) {
|
|
1137
988
|
const startTime = Date.now();
|
|
1138
989
|
if (!this.embedding) {
|
|
@@ -1158,9 +1009,6 @@ ${request.errorStack || ""}`;
|
|
|
1158
1009
|
cached: false
|
|
1159
1010
|
};
|
|
1160
1011
|
}
|
|
1161
|
-
/**
|
|
1162
|
-
* Fallback text-based search
|
|
1163
|
-
*/
|
|
1164
1012
|
async searchByText(request) {
|
|
1165
1013
|
const startTime = Date.now();
|
|
1166
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);
|
|
@@ -1181,9 +1029,6 @@ ${request.errorStack || ""}`;
|
|
|
1181
1029
|
cached: false
|
|
1182
1030
|
};
|
|
1183
1031
|
}
|
|
1184
|
-
/**
|
|
1185
|
-
* Upload a resolution to cloud knowledge base
|
|
1186
|
-
*/
|
|
1187
1032
|
async uploadResolution(request) {
|
|
1188
1033
|
const { errorRecord, resolution, resolutionCode, resolutionSteps } = request;
|
|
1189
1034
|
let embedding = null;
|
|
@@ -1233,9 +1078,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1233
1078
|
message: "Solution uploaded successfully!"
|
|
1234
1079
|
};
|
|
1235
1080
|
}
|
|
1236
|
-
/**
|
|
1237
|
-
* Check for duplicate entries
|
|
1238
|
-
*/
|
|
1239
1081
|
async checkDuplicate(errorHash, embedding) {
|
|
1240
1082
|
const { data: hashMatch } = await this.supabase.from("knowledge_entries").select("id").eq("error_hash", errorHash).limit(1).single();
|
|
1241
1083
|
if (hashMatch) {
|
|
@@ -1260,9 +1102,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1260
1102
|
similarityScore: result.similarity_score
|
|
1261
1103
|
};
|
|
1262
1104
|
}
|
|
1263
|
-
/**
|
|
1264
|
-
* Vote on a knowledge entry (with duplicate vote prevention)
|
|
1265
|
-
*/
|
|
1266
1105
|
async vote(knowledgeId, helpful) {
|
|
1267
1106
|
const voteType = helpful ? "up" : "down";
|
|
1268
1107
|
const { data, error } = await this.supabase.rpc("safe_vote", {
|
|
@@ -1283,9 +1122,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1283
1122
|
}
|
|
1284
1123
|
return result;
|
|
1285
1124
|
}
|
|
1286
|
-
/**
|
|
1287
|
-
* Report an entry for review
|
|
1288
|
-
*/
|
|
1289
1125
|
async reportEntry(knowledgeId, reason) {
|
|
1290
1126
|
const { data, error } = await this.supabase.rpc("report_entry", {
|
|
1291
1127
|
p_entry_id: knowledgeId,
|
|
@@ -1297,9 +1133,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1297
1133
|
}
|
|
1298
1134
|
return data;
|
|
1299
1135
|
}
|
|
1300
|
-
/**
|
|
1301
|
-
* Report helpful usage
|
|
1302
|
-
*/
|
|
1303
1136
|
async reportHelpful(knowledgeId) {
|
|
1304
1137
|
await this.supabase.rpc("increment_usage_count", {
|
|
1305
1138
|
entry_id: knowledgeId
|
|
@@ -1310,9 +1143,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1310
1143
|
user_hash: this.contributorId
|
|
1311
1144
|
});
|
|
1312
1145
|
}
|
|
1313
|
-
/**
|
|
1314
|
-
* Get contributor statistics
|
|
1315
|
-
*/
|
|
1316
1146
|
async getContributorStats() {
|
|
1317
1147
|
const { data } = await this.supabase.from("knowledge_entries").select("upvotes, usage_count").eq("contributor_id", this.contributorId);
|
|
1318
1148
|
if (!data || data.length === 0) {
|
|
@@ -1324,9 +1154,6 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1324
1154
|
totalUpvotes: data.reduce((sum, e) => sum + (e.upvotes || 0), 0)
|
|
1325
1155
|
};
|
|
1326
1156
|
}
|
|
1327
|
-
/**
|
|
1328
|
-
* Get entry by ID
|
|
1329
|
-
*/
|
|
1330
1157
|
async getEntry(id) {
|
|
1331
1158
|
const { data, error } = await this.supabase.from("knowledge_entries").select("*").eq("id", id).single();
|
|
1332
1159
|
if (error || !data) {
|
|
@@ -1334,22 +1161,19 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1334
1161
|
}
|
|
1335
1162
|
return this.mapToKnowledgeEntry(data);
|
|
1336
1163
|
}
|
|
1337
|
-
/**
|
|
1338
|
-
* Map database row to CloudKnowledgeEntry
|
|
1339
|
-
*/
|
|
1340
1164
|
mapToKnowledgeEntry(row) {
|
|
1341
1165
|
return {
|
|
1342
1166
|
id: row.id,
|
|
1343
1167
|
errorHash: row.error_hash,
|
|
1344
1168
|
errorType: row.error_type,
|
|
1345
1169
|
errorMessage: row.error_message,
|
|
1346
|
-
errorStack: row.error_stack ||
|
|
1170
|
+
errorStack: row.error_stack || undefined,
|
|
1347
1171
|
language: row.language,
|
|
1348
|
-
framework: row.framework ||
|
|
1349
|
-
dependencies: row.dependencies ||
|
|
1172
|
+
framework: row.framework || undefined,
|
|
1173
|
+
dependencies: row.dependencies || undefined,
|
|
1350
1174
|
resolutionDescription: row.resolution_description,
|
|
1351
|
-
resolutionCode: row.resolution_code ||
|
|
1352
|
-
resolutionSteps: row.resolution_steps ||
|
|
1175
|
+
resolutionCode: row.resolution_code || undefined,
|
|
1176
|
+
resolutionSteps: row.resolution_steps || undefined,
|
|
1353
1177
|
contributorId: row.contributor_id,
|
|
1354
1178
|
upvotes: row.upvotes || 0,
|
|
1355
1179
|
downvotes: row.downvotes || 0,
|
|
@@ -1357,33 +1181,24 @@ ${errorRecord.errorStack || ""}`;
|
|
|
1357
1181
|
createdAt: row.created_at,
|
|
1358
1182
|
updatedAt: row.updated_at,
|
|
1359
1183
|
isVerified: row.is_verified || false,
|
|
1360
|
-
similarity: row.similarity ||
|
|
1184
|
+
similarity: row.similarity || undefined
|
|
1361
1185
|
};
|
|
1362
1186
|
}
|
|
1363
|
-
/**
|
|
1364
|
-
* Get contributor ID
|
|
1365
|
-
*/
|
|
1366
1187
|
getContributorId() {
|
|
1367
1188
|
return this.contributorId;
|
|
1368
1189
|
}
|
|
1369
|
-
/**
|
|
1370
|
-
* Check if embedding service is available
|
|
1371
|
-
*/
|
|
1372
1190
|
hasEmbeddingService() {
|
|
1373
1191
|
return this.embedding !== null;
|
|
1374
1192
|
}
|
|
1375
|
-
}
|
|
1376
|
-
function createCloudClient(config) {
|
|
1377
|
-
return
|
|
1193
|
+
}
|
|
1194
|
+
async function createCloudClient(config) {
|
|
1195
|
+
return CloudClient.create(config);
|
|
1378
1196
|
}
|
|
1379
1197
|
|
|
1380
1198
|
// src/plugin/tools.ts
|
|
1381
1199
|
import { tool } from "@opencode-ai/plugin";
|
|
1382
1200
|
function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
1383
1201
|
return {
|
|
1384
|
-
/**
|
|
1385
|
-
* Search cloud knowledge base for error solutions
|
|
1386
|
-
*/
|
|
1387
1202
|
fixhive_search: tool({
|
|
1388
1203
|
description: "Search FixHive knowledge base for error solutions. Use when encountering errors to find community solutions.",
|
|
1389
1204
|
args: {
|
|
@@ -1412,9 +1227,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1412
1227
|
return formatSearchResults(results.results, false);
|
|
1413
1228
|
}
|
|
1414
1229
|
}),
|
|
1415
|
-
/**
|
|
1416
|
-
* Mark error as resolved and optionally upload solution
|
|
1417
|
-
*/
|
|
1418
1230
|
fixhive_resolve: tool({
|
|
1419
1231
|
description: "Mark an error as resolved and optionally share the solution with the community.",
|
|
1420
1232
|
args: {
|
|
@@ -1450,9 +1262,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1450
1262
|
return "Error marked as resolved locally.";
|
|
1451
1263
|
}
|
|
1452
1264
|
}),
|
|
1453
|
-
/**
|
|
1454
|
-
* List errors in current session
|
|
1455
|
-
*/
|
|
1456
1265
|
fixhive_list: tool({
|
|
1457
1266
|
description: "List errors detected in the current session.",
|
|
1458
1267
|
args: {
|
|
@@ -1471,9 +1280,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1471
1280
|
return formatErrorList(errors);
|
|
1472
1281
|
}
|
|
1473
1282
|
}),
|
|
1474
|
-
/**
|
|
1475
|
-
* Vote on a solution
|
|
1476
|
-
*/
|
|
1477
1283
|
fixhive_vote: tool({
|
|
1478
1284
|
description: "Upvote or downvote a FixHive solution based on whether it helped.",
|
|
1479
1285
|
args: {
|
|
@@ -1491,9 +1297,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1491
1297
|
return args.helpful ? "Thanks for the feedback! Solution upvoted." : "Thanks for the feedback! Solution downvoted.";
|
|
1492
1298
|
}
|
|
1493
1299
|
}),
|
|
1494
|
-
/**
|
|
1495
|
-
* Report inappropriate content
|
|
1496
|
-
*/
|
|
1497
1300
|
fixhive_report: tool({
|
|
1498
1301
|
description: "Report a FixHive solution for inappropriate content, spam, or incorrect information.",
|
|
1499
1302
|
args: {
|
|
@@ -1508,9 +1311,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1508
1311
|
return "Report submitted. Thank you for helping keep FixHive clean!";
|
|
1509
1312
|
}
|
|
1510
1313
|
}),
|
|
1511
|
-
/**
|
|
1512
|
-
* Get usage statistics
|
|
1513
|
-
*/
|
|
1514
1314
|
fixhive_stats: tool({
|
|
1515
1315
|
description: "Get FixHive usage statistics.",
|
|
1516
1316
|
args: {},
|
|
@@ -1532,9 +1332,6 @@ function createTools(localStore, cloudClient, privacyFilter, context) {
|
|
|
1532
1332
|
`;
|
|
1533
1333
|
}
|
|
1534
1334
|
}),
|
|
1535
|
-
/**
|
|
1536
|
-
* Report that a solution was helpful
|
|
1537
|
-
*/
|
|
1538
1335
|
fixhive_helpful: tool({
|
|
1539
1336
|
description: "Report that a FixHive solution was helpful and resolved your issue.",
|
|
1540
1337
|
args: {
|
|
@@ -1569,7 +1366,8 @@ ${r.resolutionCode}
|
|
|
1569
1366
|
if (r.resolutionSteps?.length) {
|
|
1570
1367
|
entry += `
|
|
1571
1368
|
**Steps:**
|
|
1572
|
-
${r.resolutionSteps.map((s, j) => `${j + 1}. ${s}`).join(
|
|
1369
|
+
${r.resolutionSteps.map((s, j) => `${j + 1}. ${s}`).join(`
|
|
1370
|
+
`)}
|
|
1573
1371
|
`;
|
|
1574
1372
|
}
|
|
1575
1373
|
entry += `
|
|
@@ -1577,7 +1375,8 @@ ${r.resolutionSteps.map((s, j) => `${j + 1}. ${s}`).join("\n")}
|
|
|
1577
1375
|
|
|
1578
1376
|
---`;
|
|
1579
1377
|
return entry;
|
|
1580
|
-
}).join(
|
|
1378
|
+
}).join(`
|
|
1379
|
+
`);
|
|
1581
1380
|
return `${header}
|
|
1582
1381
|
${entries}
|
|
1583
1382
|
|
|
@@ -1588,9 +1387,8 @@ function formatErrorList(errors) {
|
|
|
1588
1387
|
const table = `
|
|
1589
1388
|
| ID | Type | Status | Message |
|
|
1590
1389
|
|----|------|--------|---------|
|
|
1591
|
-
${errors.map(
|
|
1592
|
-
|
|
1593
|
-
).join("\n")}
|
|
1390
|
+
${errors.map((e) => `| ${e.id.slice(0, 8)} | ${e.errorType} | ${e.status} | ${e.errorMessage.slice(0, 50)}... |`).join(`
|
|
1391
|
+
`)}
|
|
1594
1392
|
`;
|
|
1595
1393
|
return `${header}
|
|
1596
1394
|
${table}
|
|
@@ -1600,8 +1398,7 @@ Use \`fixhive_resolve <id>\` to mark as resolved and share solutions.`;
|
|
|
1600
1398
|
|
|
1601
1399
|
// src/plugin/index.ts
|
|
1602
1400
|
var DEFAULT_CONFIG = {
|
|
1603
|
-
cacheExpirationMs:
|
|
1604
|
-
// 1 hour
|
|
1401
|
+
cacheExpirationMs: 3600000,
|
|
1605
1402
|
embeddingModel: "text-embedding-3-small",
|
|
1606
1403
|
embeddingDimensions: 1536,
|
|
1607
1404
|
similarityThreshold: 0.7,
|
|
@@ -1612,14 +1409,14 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1612
1409
|
console.log("[FixHive] Plugin loaded");
|
|
1613
1410
|
console.log(`[FixHive] Project: ${ctx.directory}`);
|
|
1614
1411
|
console.log(`[FixHive] Cloud: ${config.supabaseUrl ? "enabled" : "disabled"}`);
|
|
1615
|
-
const privacyFilter = new PrivacyFilter
|
|
1412
|
+
const privacyFilter = new PrivacyFilter;
|
|
1616
1413
|
const filterContext = createFilterContext(ctx.directory);
|
|
1617
1414
|
const errorDetector = new ErrorDetector(privacyFilter);
|
|
1618
1415
|
const localStore = new LocalStore(ctx.directory);
|
|
1619
1416
|
let cloudClient = null;
|
|
1620
1417
|
if (config.supabaseUrl && config.supabaseAnonKey) {
|
|
1621
1418
|
try {
|
|
1622
|
-
cloudClient =
|
|
1419
|
+
cloudClient = await CloudClient.create({
|
|
1623
1420
|
supabaseUrl: config.supabaseUrl,
|
|
1624
1421
|
supabaseAnonKey: config.supabaseAnonKey,
|
|
1625
1422
|
openaiApiKey: config.openaiApiKey,
|
|
@@ -1643,9 +1440,9 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1643
1440
|
console.log("[FixHive] Ready - use fixhive_stats to verify");
|
|
1644
1441
|
const errorProducingTools = ["bash", "edit", "write", "read", "terminal"];
|
|
1645
1442
|
return {
|
|
1646
|
-
// ============ Tool Execution Hook ============
|
|
1647
1443
|
"tool.execute.after": async (input, output) => {
|
|
1648
|
-
if (!errorProducingTools.includes(input.tool))
|
|
1444
|
+
if (!errorProducingTools.includes(input.tool))
|
|
1445
|
+
return;
|
|
1649
1446
|
const detection = errorDetector.detect({
|
|
1650
1447
|
tool: input.tool,
|
|
1651
1448
|
output: output.output,
|
|
@@ -1655,7 +1452,7 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1655
1452
|
});
|
|
1656
1453
|
if (detection.detected && detection.confidence >= 0.5) {
|
|
1657
1454
|
const sanitizedErrorMessage = privacyFilter.sanitize(detection.errorMessage, filterContext).sanitized;
|
|
1658
|
-
const sanitizedErrorStack = detection.errorStack ? privacyFilter.sanitize(detection.errorStack, filterContext).sanitized :
|
|
1455
|
+
const sanitizedErrorStack = detection.errorStack ? privacyFilter.sanitize(detection.errorStack, filterContext).sanitized : undefined;
|
|
1659
1456
|
localStore.createErrorRecord({
|
|
1660
1457
|
errorType: detection.errorType,
|
|
1661
1458
|
errorMessage: sanitizedErrorMessage,
|
|
@@ -1664,7 +1461,6 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1664
1461
|
framework: pluginContext.framework,
|
|
1665
1462
|
toolName: input.tool,
|
|
1666
1463
|
toolInput: {},
|
|
1667
|
-
// Tool input is intentionally omitted to avoid storing sensitive data
|
|
1668
1464
|
sessionId: pluginContext.sessionId || input.sessionID
|
|
1669
1465
|
});
|
|
1670
1466
|
if (cloudClient) {
|
|
@@ -1677,10 +1473,7 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1677
1473
|
limit: 3
|
|
1678
1474
|
});
|
|
1679
1475
|
if (solutions.results.length > 0) {
|
|
1680
|
-
localStore.cacheResults(
|
|
1681
|
-
generateErrorFingerprint(sanitizedErrorMessage, sanitizedErrorStack),
|
|
1682
|
-
solutions.results
|
|
1683
|
-
);
|
|
1476
|
+
localStore.cacheResults(generateErrorFingerprint(sanitizedErrorMessage, sanitizedErrorStack), solutions.results);
|
|
1684
1477
|
output.title = `${output.title} [FixHive: ${solutions.results.length} solution(s) found]`;
|
|
1685
1478
|
}
|
|
1686
1479
|
} catch (e) {
|
|
@@ -1690,24 +1483,22 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1690
1483
|
}
|
|
1691
1484
|
}
|
|
1692
1485
|
},
|
|
1693
|
-
// ============ Session Compaction Hook ============
|
|
1694
1486
|
"experimental.session.compacting": async (_input, output) => {
|
|
1695
1487
|
const unresolvedErrors = localStore.getUnresolvedErrors(pluginContext.sessionId);
|
|
1696
1488
|
if (unresolvedErrors.length > 0) {
|
|
1697
1489
|
output.context.push(`
|
|
1698
1490
|
## FixHive: Unresolved Errors in Session
|
|
1699
1491
|
|
|
1700
|
-
${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
|
+
`)}
|
|
1701
1494
|
|
|
1702
1495
|
Use \`fixhive_mark_resolved\` when errors are fixed to contribute solutions.
|
|
1703
1496
|
`);
|
|
1704
1497
|
}
|
|
1705
1498
|
},
|
|
1706
|
-
// ============ Chat Message Hook ============
|
|
1707
1499
|
"chat.message": async (input, _output) => {
|
|
1708
1500
|
pluginContext.sessionId = input.sessionID;
|
|
1709
1501
|
},
|
|
1710
|
-
// ============ Custom Tools ============
|
|
1711
1502
|
tool: cloudClient ? createTools(localStore, cloudClient, privacyFilter, pluginContext) : createOfflineTools(localStore, privacyFilter, pluginContext)
|
|
1712
1503
|
};
|
|
1713
1504
|
};
|
|
@@ -1730,7 +1521,8 @@ function createOfflineTools(localStore, _privacyFilter, context) {
|
|
|
1730
1521
|
}
|
|
1731
1522
|
return `## Session Errors (${errors.length})
|
|
1732
1523
|
|
|
1733
|
-
${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
|
+
`)}
|
|
1734
1526
|
|
|
1735
1527
|
*Cloud features disabled. Set FIXHIVE_SUPABASE_URL and FIXHIVE_SUPABASE_KEY to enable.*`;
|
|
1736
1528
|
}
|
|
@@ -1789,7 +1581,7 @@ function detectLanguage(directory) {
|
|
|
1789
1581
|
return lang;
|
|
1790
1582
|
}
|
|
1791
1583
|
}
|
|
1792
|
-
return
|
|
1584
|
+
return;
|
|
1793
1585
|
}
|
|
1794
1586
|
function detectFramework(directory) {
|
|
1795
1587
|
const pkgPath = join(directory, "package.json");
|
|
@@ -1797,49 +1589,57 @@ function detectFramework(directory) {
|
|
|
1797
1589
|
try {
|
|
1798
1590
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
1799
1591
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1800
|
-
if (deps["next"])
|
|
1801
|
-
|
|
1802
|
-
if (deps["
|
|
1803
|
-
|
|
1804
|
-
if (deps["
|
|
1805
|
-
|
|
1806
|
-
if (deps["
|
|
1807
|
-
|
|
1808
|
-
|
|
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 {}
|
|
1809
1607
|
}
|
|
1810
1608
|
const reqPath = join(directory, "requirements.txt");
|
|
1811
1609
|
if (existsSync2(reqPath)) {
|
|
1812
1610
|
try {
|
|
1813
1611
|
const content = readFileSync(reqPath, "utf-8");
|
|
1814
|
-
if (content.includes("django"))
|
|
1815
|
-
|
|
1816
|
-
if (content.includes("
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
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;
|
|
1821
1621
|
}
|
|
1822
1622
|
var plugin_default = FixHivePlugin;
|
|
1823
1623
|
export {
|
|
1824
|
-
|
|
1825
|
-
EmbeddingService,
|
|
1826
|
-
ErrorDetector,
|
|
1827
|
-
FixHivePlugin,
|
|
1828
|
-
LocalStore,
|
|
1829
|
-
PrivacyFilter,
|
|
1830
|
-
calculateStringSimilarity,
|
|
1831
|
-
createCloudClient,
|
|
1832
|
-
createEmbeddingService,
|
|
1833
|
-
createFilterContext,
|
|
1834
|
-
plugin_default as default,
|
|
1835
|
-
defaultErrorDetector,
|
|
1836
|
-
defaultPrivacyFilter,
|
|
1837
|
-
fingerprintsMatch,
|
|
1838
|
-
generateContributorId,
|
|
1839
|
-
generateErrorFingerprint,
|
|
1840
|
-
generateSessionHash,
|
|
1841
|
-
normalizeErrorContent,
|
|
1842
|
-
runMigrations,
|
|
1624
|
+
shortHash,
|
|
1843
1625
|
sha256,
|
|
1844
|
-
|
|
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
|
|
1845
1645
|
};
|