@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/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
- var PrivacyFilter = class {
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: /* @__PURE__ */ new Map([
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
- var ErrorDetector = class {
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 !== void 0 && toolOutput.exitCode !== 0) {
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("\n"),
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) : void 0;
454
- const sanitizedOutput = this.privacyFilter.sanitize(combinedOutput.substring(0, 5e3));
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") continue;
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) return 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))) return "build";
538
- if (ERROR_PATTERNS.package.some((p) => p.test(content))) return "dependency";
539
- if (ERROR_PATTERNS.permission.some((p) => p.test(content))) return "permission";
540
- if (ERROR_PATTERNS.network.some((p) => p.test(content))) return "network";
541
- if (ERROR_PATTERNS.test.some((p) => p.test(content))) return "test";
542
- if (/TypeError:|type error|Type '[^']+' is not assignable/i.test(content)) return "type_error";
543
- if (/SyntaxError:|syntax error|unexpected token/i.test(content)) return "syntax";
544
- if (/ReferenceError:|RangeError:|runtime error/i.test(content)) return "runtime";
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) return "runtime";
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 !== void 0 && EXIT_CODE_SEVERITY[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) return "error";
558
- if (maxWeight >= 0.7) return "error";
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("\n");
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/) || // JS stack
574
- line.match(/^\s+File\s/) || // Python stack
575
- line.match(/^\s+\d+:\s/) || // Rust stack
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 || void 0
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 = /* @__PURE__ */ new Set([...words1, ...words2]);
646
- if (union.size === 0) return 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
- var LocalStore = class _LocalStore {
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 (!_LocalStore.ALLOWED_STATS.includes(stat)) {
939
- throw new Error(`Invalid stat name: ${stat}. Allowed: ${_LocalStore.ALLOWED_STATS.join(", ")}`);
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 || void 0,
973
- language: row.language || void 0,
974
- framework: row.framework || void 0,
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 || void 0,
980
- resolutionCode: row.resolution_code || void 0,
845
+ resolution: row.resolution || undefined,
846
+ resolutionCode: row.resolution_code || undefined,
981
847
  createdAt: row.created_at,
982
- resolvedAt: row.resolved_at || void 0,
983
- uploadedAt: row.uploaded_at || void 0,
984
- cloudKnowledgeId: row.cloud_knowledge_id || void 0
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 = 3e4;
1006
- var EmbeddingService = class {
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("\n");
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("\n");
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; i < a.length; i++) {
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) return 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
- var CloudClient = class _CloudClient {
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 _CloudClient(supabase, embedding, contributorId, similarityThreshold);
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 || void 0,
1170
+ errorStack: row.error_stack || undefined,
1361
1171
  language: row.language,
1362
- framework: row.framework || void 0,
1363
- dependencies: row.dependencies || void 0,
1172
+ framework: row.framework || undefined,
1173
+ dependencies: row.dependencies || undefined,
1364
1174
  resolutionDescription: row.resolution_description,
1365
- resolutionCode: row.resolution_code || void 0,
1366
- resolutionSteps: row.resolution_steps || void 0,
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 || void 0
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("\n")}
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("\n");
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
- (e) => `| ${e.id.slice(0, 8)} | ${e.errorType} | ${e.status} | ${e.errorMessage.slice(0, 50)}... |`
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: 36e5,
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)) return;
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 : void 0;
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("\n")}
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("\n")}
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 void 0;
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"]) return "nextjs";
1815
- if (deps["react"]) return "react";
1816
- if (deps["vue"]) return "vue";
1817
- if (deps["@angular/core"]) return "angular";
1818
- if (deps["express"]) return "express";
1819
- if (deps["fastify"]) return "fastify";
1820
- if (deps["hono"]) return "hono";
1821
- } catch {
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")) return "django";
1829
- if (content.includes("flask")) return "flask";
1830
- if (content.includes("fastapi")) return "fastapi";
1831
- } catch {
1832
- }
1833
- }
1834
- return void 0;
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
- CloudClient,
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
- shortHash
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
  };