@the-magic-tower/fixhive-opencode-plugin 0.1.16 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,53 +3,41 @@
3
3
  * Generates text embeddings for semantic search using OpenAI
4
4
  */
5
5
  /**
6
- * Embedding Service Class
7
- * Generates embeddings for error messages and solutions
6
+ * EmbeddingService interface - defines all public methods
8
7
  */
9
- export declare class EmbeddingService {
10
- private client;
11
- private model;
12
- private dimensions;
13
- constructor(apiKey: string, model?: string, dimensions?: number);
14
- /**
15
- * Generate embedding for a single text
16
- */
8
+ export interface EmbeddingService {
17
9
  generate(text: string): Promise<number[]>;
18
- /**
19
- * Generate embeddings for multiple texts
20
- */
21
10
  generateBatch(texts: string[]): Promise<number[][]>;
22
- /**
23
- * Generate embedding for error context
24
- * Combines error message, stack trace, and context
25
- */
26
11
  generateErrorEmbedding(errorMessage: string, errorStack?: string, context?: {
27
12
  language?: string;
28
13
  framework?: string;
29
14
  }): Promise<number[]>;
30
- /**
31
- * Truncate text to fit within model limits
32
- */
33
- private truncateText;
34
- /**
35
- * Calculate cosine similarity between two embeddings
36
- */
37
- static cosineSimilarity(a: number[], b: number[]): number;
38
- /**
39
- * Get embedding dimensions
40
- */
41
15
  getDimensions(): number;
42
- /**
43
- * Get model name
44
- */
45
16
  getModel(): string;
46
17
  }
47
18
  /**
48
- * Create embedding service with config
19
+ * EmbeddingService configuration
49
20
  */
50
- export declare function createEmbeddingService(config: {
21
+ export interface EmbeddingServiceConfig {
51
22
  apiKey: string;
52
23
  model?: string;
53
24
  dimensions?: number;
54
- }): EmbeddingService;
25
+ }
26
+ /**
27
+ * Calculate cosine similarity between two embeddings
28
+ */
29
+ export declare function cosineSimilarity(a: number[], b: number[]): number;
30
+ /**
31
+ * Create an EmbeddingService instance
32
+ * Factory function pattern to avoid ES6 class issues with Bun
33
+ */
34
+ export declare function createEmbeddingService(config: EmbeddingServiceConfig): EmbeddingService;
35
+ /**
36
+ * Legacy class wrapper for backwards compatibility
37
+ * @deprecated Use createEmbeddingService() instead
38
+ */
39
+ export declare const EmbeddingService: {
40
+ create: typeof createEmbeddingService;
41
+ cosineSimilarity: typeof cosineSimilarity;
42
+ };
55
43
  //# sourceMappingURL=embedding.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../src/cloud/embedding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;IAM/D;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAY/C;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IAYzD;;;OAGG;IACG,sBAAsB,CAC1B,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAClD,OAAO,CAAC,MAAM,EAAE,CAAC;IAqBpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAgBpB;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM;IAqBzD;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,QAAQ,IAAI,MAAM;CAGnB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,gBAAgB,CAEnB"}
1
+ {"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../src/cloud/embedding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1C,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACpD,sBAAsB,CACpB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAClD,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrB,aAAa,IAAI,MAAM,CAAC;IACxB,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAmBjE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,sBAAsB,GAAG,gBAAgB,CAkGvF;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;CAG5B,CAAC"}
@@ -3,50 +3,24 @@
3
3
  * Detects errors from tool outputs using multi-signal analysis
4
4
  */
5
5
  import type { ErrorDetectionResult, ToolOutput } from '../types/index.js';
6
- import { PrivacyFilter } from './privacy-filter.js';
6
+ import { type PrivacyFilter } from './privacy-filter.js';
7
7
  /**
8
- * Error Detector Class
9
- * Analyzes tool outputs to detect errors
8
+ * ErrorDetector interface - defines all public methods
10
9
  */
11
- export declare class ErrorDetector {
12
- private privacyFilter;
13
- constructor(privacyFilter?: PrivacyFilter);
14
- /**
15
- * Detect if output contains an error
16
- */
10
+ export interface ErrorDetector {
17
11
  detect(toolOutput: ToolOutput): ErrorDetectionResult;
18
- /**
19
- * Check if content contains error keywords
20
- */
21
- private containsErrorKeywords;
22
- /**
23
- * Detect error patterns in content
24
- */
25
- private detectErrorPatterns;
26
- /**
27
- * Detect stack traces in content
28
- */
29
- private detectStackTrace;
30
- /**
31
- * Calculate confidence score from signals
32
- */
33
- private calculateConfidence;
34
- /**
35
- * Classify error type based on signals and content
36
- */
37
- private classifyErrorType;
38
- /**
39
- * Determine severity from signals and exit code
40
- */
41
- private determineSeverity;
42
- /**
43
- * Extract error message and stack from output
44
- */
45
- private extractErrorDetails;
46
- /**
47
- * Check if a line looks like an error message
48
- */
49
- private isErrorLine;
50
12
  }
13
+ /**
14
+ * Create an ErrorDetector instance
15
+ * Factory function pattern to avoid ES6 class issues with Bun
16
+ */
17
+ export declare function createErrorDetector(privacyFilter?: PrivacyFilter): ErrorDetector;
18
+ /**
19
+ * Legacy class wrapper for backwards compatibility
20
+ * @deprecated Use createErrorDetector() instead
21
+ */
22
+ export declare const ErrorDetector: {
23
+ create: typeof createErrorDetector;
24
+ };
51
25
  export declare const defaultErrorDetector: ErrorDetector;
52
26
  //# sourceMappingURL=error-detector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-detector.d.ts","sourceRoot":"","sources":["../../src/core/error-detector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAIV,oBAAoB,EAEpB,UAAU,EACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAsGpD;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,aAAa,CAAgB;gBAEzB,aAAa,CAAC,EAAE,aAAa;IAIzC;;OAEG;IACH,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,oBAAoB;IAsEpD;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAI7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA+B3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAwBzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAczB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAqC3B;;OAEG;IACH,OAAO,CAAC,WAAW;CASpB;AAGD,eAAO,MAAM,oBAAoB,eAAsB,CAAC"}
1
+ {"version":3,"file":"error-detector.d.ts","sourceRoot":"","sources":["../../src/core/error-detector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAIV,oBAAoB,EAEpB,UAAU,EACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAsG9E;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,oBAAoB,CAAC;CACtD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,CAAC,EAAE,aAAa,GAAG,aAAa,CA8PhF;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAGF,eAAO,MAAM,oBAAoB,eAAwB,CAAC"}
@@ -4,38 +4,27 @@
4
4
  */
5
5
  import type { PrivacyFilterRule, SanitizedContent, FilterContext } from '../types/index.js';
6
6
  /**
7
- * Privacy Filter Pipeline
8
- * Applies multiple filtering rules to sanitize sensitive content
7
+ * PrivacyFilter interface - defines all public methods
9
8
  */
10
- export declare class PrivacyFilter {
11
- private rules;
12
- constructor(customRules?: PrivacyFilterRule[]);
13
- /**
14
- * Sanitize content by applying all filter rules
15
- */
9
+ export interface PrivacyFilter {
16
10
  sanitize(content: string, context?: FilterContext): SanitizedContent;
17
- /**
18
- * Generalize file paths while keeping meaningful structure
19
- */
20
- private generalizePaths;
21
- /**
22
- * Add a custom filter rule
23
- */
24
11
  addRule(rule: PrivacyFilterRule): void;
25
- /**
26
- * Remove a filter rule by name
27
- */
28
12
  removeRule(name: string): boolean;
29
- /**
30
- * Get all current rules
31
- */
32
13
  getRules(): ReadonlyArray<PrivacyFilterRule>;
33
- /**
34
- * Check if content contains sensitive data
35
- * Note: Always reset regex lastIndex BEFORE testing to prevent state pollution
36
- */
37
14
  containsSensitiveData(content: string): boolean;
38
15
  }
16
+ /**
17
+ * Create a PrivacyFilter instance
18
+ * Factory function pattern to avoid ES6 class issues with Bun
19
+ */
20
+ export declare function createPrivacyFilter(customRules?: PrivacyFilterRule[]): PrivacyFilter;
21
+ /**
22
+ * Legacy class wrapper for backwards compatibility
23
+ * @deprecated Use createPrivacyFilter() instead
24
+ */
25
+ export declare const PrivacyFilter: {
26
+ create: typeof createPrivacyFilter;
27
+ };
39
28
  /**
40
29
  * Create default filter context from project directory
41
30
  */
@@ -1 +1 @@
1
- {"version":3,"file":"privacy-filter.d.ts","sourceRoot":"","sources":["../../src/core/privacy-filter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAwN5F;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,KAAK,CAAsB;gBAEvB,WAAW,CAAC,EAAE,iBAAiB,EAAE;IAO7C;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,gBAAgB;IAqCpE;;OAEG;IACH,OAAO,CAAC,eAAe;IAwBvB;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAKtC;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IASjC;;OAEG;IACH,QAAQ,IAAI,aAAa,CAAC,iBAAiB,CAAC;IAI5C;;;OAGG;IACH,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;CAehD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,aAAa,CAc3E;AAGD,eAAO,MAAM,oBAAoB,eAAsB,CAAC"}
1
+ {"version":3,"file":"privacy-filter.d.ts","sourceRoot":"","sources":["../../src/core/privacy-filter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAwN5F;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,gBAAgB,CAAC;IACrE,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACvC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,QAAQ,IAAI,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAC7C,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,CAAC,EAAE,iBAAiB,EAAE,GAAG,aAAa,CAyHpF;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,aAAa,CAc3E;AAGD,eAAO,MAAM,oBAAoB,eAAwB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -24,12 +24,22 @@
24
24
  * ```
25
25
  */
26
26
  export { FixHivePlugin, default } from './plugin/index.js';
27
- export { ErrorDetector, defaultErrorDetector } from './core/error-detector.js';
28
- export { PrivacyFilter, defaultPrivacyFilter, createFilterContext } from './core/privacy-filter.js';
27
+ export { createErrorDetector, defaultErrorDetector } from './core/error-detector.js';
28
+ export { createPrivacyFilter, defaultPrivacyFilter, createFilterContext } from './core/privacy-filter.js';
29
29
  export { sha256, shortHash, generateErrorFingerprint, normalizeErrorContent, generateContributorId, generateSessionHash, fingerprintsMatch, calculateStringSimilarity, } from './core/hash.js';
30
- export { LocalStore } from './storage/local-store.js';
30
+ export { createLocalStore } from './storage/local-store.js';
31
31
  export { runMigrations } from './storage/migrations.js';
32
- export { CloudClient, createCloudClient } from './cloud/client.js';
33
- export { EmbeddingService, createEmbeddingService } from './cloud/embedding.js';
32
+ export { createCloudClient } from './cloud/client.js';
33
+ export { createEmbeddingService, cosineSimilarity } from './cloud/embedding.js';
34
+ export { ErrorDetector } from './core/error-detector.js';
35
+ export { PrivacyFilter } from './core/privacy-filter.js';
36
+ export { LocalStore } from './storage/local-store.js';
37
+ export { CloudClient } from './cloud/client.js';
38
+ export { EmbeddingService } from './cloud/embedding.js';
34
39
  export type { ErrorType, ErrorStatus, Language, Severity, LocalErrorRecord, QueryCacheEntry, LocalStats, CloudKnowledgeEntry, DuplicateCheckResult, ContributorStats, DetectedSignal, ErrorDetectionResult, StackFrame, StackTraceInfo, FixHiveContext, ToolOutput, PrivacyFilterRule, SanitizedContent, FilterContext, SearchRequest, SearchResponse, UploadRequest, UploadResponse, QueryKnowledgeArgs, SubmitResolutionArgs, ListErrorsArgs, MarkResolvedArgs, VoteArgs, FixHiveConfig, PartialConfig, FixHiveEvent, } from './types/index.js';
40
+ export type { ErrorDetector as ErrorDetectorInterface } from './core/error-detector.js';
41
+ export type { PrivacyFilter as PrivacyFilterInterface } from './core/privacy-filter.js';
42
+ export type { LocalStore as LocalStoreInterface } from './storage/local-store.js';
43
+ export type { CloudClient as CloudClientInterface } from './cloud/client.js';
44
+ export type { EmbeddingService as EmbeddingServiceInterface, EmbeddingServiceConfig } from './cloud/embedding.js';
35
45
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpG,OAAO,EACL,MAAM,EACN,SAAS,EACT,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAGhF,YAAY,EAEV,SAAS,EACT,WAAW,EACX,QAAQ,EACR,QAAQ,EAGR,gBAAgB,EAChB,eAAe,EACf,UAAU,EAGV,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAGhB,cAAc,EACd,oBAAoB,EACpB,UAAU,EACV,cAAc,EAGd,cAAc,EACd,UAAU,EAGV,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EAGb,aAAa,EACb,cAAc,EACd,aAAa,EACb,cAAc,EAGd,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,QAAQ,EAGR,aAAa,EACb,aAAa,EAGb,YAAY,GACb,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC1G,OAAO,EACL,MAAM,EACN,SAAS,EACT,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,YAAY,EAEV,SAAS,EACT,WAAW,EACX,QAAQ,EACR,QAAQ,EAGR,gBAAgB,EAChB,eAAe,EACf,UAAU,EAGV,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAGhB,cAAc,EACd,oBAAoB,EACpB,UAAU,EACV,cAAc,EAGd,cAAc,EACd,UAAU,EAGV,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EAGb,aAAa,EACb,cAAc,EACd,aAAa,EACb,cAAc,EAGd,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,QAAQ,EAGR,aAAa,EACb,aAAa,EAGb,YAAY,GACb,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EAAE,aAAa,IAAI,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACxF,YAAY,EAAE,aAAa,IAAI,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACxF,YAAY,EAAE,UAAU,IAAI,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAClF,YAAY,EAAE,WAAW,IAAI,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,YAAY,EAAE,gBAAgB,IAAI,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -157,42 +157,9 @@ var DEFAULT_FILTER_RULES = [
157
157
  priority: 65
158
158
  }
159
159
  ];
160
-
161
- class PrivacyFilter {
162
- rules;
163
- constructor(customRules) {
164
- this.rules = [...DEFAULT_FILTER_RULES, ...customRules || []].sort((a, b) => b.priority - a.priority);
165
- }
166
- sanitize(content, context) {
167
- let result = content;
168
- const appliedFilters = [];
169
- let totalRedacted = 0;
170
- for (const rule of this.rules) {
171
- const before = result;
172
- if (typeof rule.replacement === "function") {
173
- result = result.replace(rule.pattern, rule.replacement);
174
- } else {
175
- result = result.replace(rule.pattern, rule.replacement);
176
- }
177
- if (result !== before) {
178
- const matches = before.match(rule.pattern);
179
- if (matches) {
180
- totalRedacted += matches.length;
181
- appliedFilters.push(rule.name);
182
- }
183
- }
184
- }
185
- if (context) {
186
- result = this.generalizePaths(result, context);
187
- }
188
- return {
189
- original: content,
190
- sanitized: result,
191
- redactedCount: totalRedacted,
192
- appliedFilters: [...new Set(appliedFilters)]
193
- };
194
- }
195
- generalizePaths(content, context) {
160
+ function createPrivacyFilter(customRules) {
161
+ const rules = [...DEFAULT_FILTER_RULES, ...customRules || []].sort((a, b) => b.priority - a.priority);
162
+ function generalizePaths(content, context) {
196
163
  let result = content;
197
164
  if (context.projectRoot) {
198
165
  const escapedRoot = context.projectRoot.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -206,35 +173,69 @@ class PrivacyFilter {
206
173
  result = result.replace(/site-packages\/[\w.-]+\//g, "site-packages/<PKG>/");
207
174
  return result;
208
175
  }
209
- addRule(rule) {
210
- this.rules.push(rule);
211
- this.rules.sort((a, b) => b.priority - a.priority);
212
- }
213
- removeRule(name) {
214
- const index = this.rules.findIndex((r) => r.name === name);
215
- if (index !== -1) {
216
- this.rules.splice(index, 1);
217
- return true;
218
- }
219
- return false;
220
- }
221
- getRules() {
222
- return this.rules;
223
- }
224
- containsSensitiveData(content) {
225
- for (const rule of this.rules) {
226
- if (rule.category === "secret") {
227
- rule.pattern.lastIndex = 0;
228
- const hasSensitiveData = rule.pattern.test(content);
229
- rule.pattern.lastIndex = 0;
230
- if (hasSensitiveData) {
231
- return true;
176
+ return {
177
+ sanitize(content, context) {
178
+ let result = content;
179
+ const appliedFilters = [];
180
+ let totalRedacted = 0;
181
+ for (const rule of rules) {
182
+ const before = result;
183
+ if (typeof rule.replacement === "function") {
184
+ result = result.replace(rule.pattern, rule.replacement);
185
+ } else {
186
+ result = result.replace(rule.pattern, rule.replacement);
187
+ }
188
+ if (result !== before) {
189
+ const matches = before.match(rule.pattern);
190
+ if (matches) {
191
+ totalRedacted += matches.length;
192
+ appliedFilters.push(rule.name);
193
+ }
194
+ }
195
+ }
196
+ if (context) {
197
+ result = generalizePaths(result, context);
198
+ }
199
+ return {
200
+ original: content,
201
+ sanitized: result,
202
+ redactedCount: totalRedacted,
203
+ appliedFilters: [...new Set(appliedFilters)]
204
+ };
205
+ },
206
+ addRule(rule) {
207
+ rules.push(rule);
208
+ rules.sort((a, b) => b.priority - a.priority);
209
+ },
210
+ removeRule(name) {
211
+ const index = rules.findIndex((r) => r.name === name);
212
+ if (index !== -1) {
213
+ rules.splice(index, 1);
214
+ return true;
215
+ }
216
+ return false;
217
+ },
218
+ getRules() {
219
+ return rules;
220
+ },
221
+ containsSensitiveData(content) {
222
+ for (const rule of rules) {
223
+ if (rule.category === "secret") {
224
+ rule.pattern.lastIndex = 0;
225
+ const hasSensitiveData = rule.pattern.test(content);
226
+ rule.pattern.lastIndex = 0;
227
+ if (hasSensitiveData) {
228
+ return true;
229
+ }
232
230
  }
233
231
  }
232
+ return false;
234
233
  }
235
- return false;
236
- }
234
+ };
237
235
  }
236
+ var PrivacyFilter = {
237
+ create: createPrivacyFilter
238
+ };
238
239
  function createFilterContext(projectDirectory) {
239
240
  const homeDir = process.env.HOME || process.env.USERPROFILE || "~";
240
241
  return {
@@ -249,7 +250,7 @@ function createFilterContext(projectDirectory) {
249
250
  ])
250
251
  };
251
252
  }
252
- var defaultPrivacyFilter = new PrivacyFilter;
253
+ var defaultPrivacyFilter = createPrivacyFilter();
253
254
 
254
255
  // src/core/error-detector.ts
255
256
  var ERROR_PATTERNS = {
@@ -327,70 +328,12 @@ var EXIT_CODE_SEVERITY = {
327
328
  139: "critical",
328
329
  143: "warning"
329
330
  };
330
-
331
- class ErrorDetector {
332
- privacyFilter;
333
- constructor(privacyFilter) {
334
- this.privacyFilter = privacyFilter || new PrivacyFilter;
335
- }
336
- detect(toolOutput) {
337
- const signals = [];
338
- const combinedOutput = `${toolOutput.output || ""}
339
- ${toolOutput.stderr || ""}`;
340
- if (toolOutput.exitCode !== undefined && toolOutput.exitCode !== 0) {
341
- const severity2 = EXIT_CODE_SEVERITY[toolOutput.exitCode] || "error";
342
- signals.push({
343
- type: "exit_code",
344
- weight: 0.9,
345
- value: toolOutput.exitCode,
346
- description: `Non-zero exit code: ${toolOutput.exitCode} (${severity2})`
347
- });
348
- }
349
- if (toolOutput.stderr && toolOutput.stderr.trim().length > 0) {
350
- const hasErrorKeywords = this.containsErrorKeywords(toolOutput.stderr);
351
- const stderrWeight = hasErrorKeywords ? 0.85 : 0.4;
352
- signals.push({
353
- type: "stderr",
354
- weight: stderrWeight,
355
- value: toolOutput.stderr.substring(0, 500),
356
- description: hasErrorKeywords ? "Stderr with error keywords" : "Stderr output present"
357
- });
358
- }
359
- const patternMatches = this.detectErrorPatterns(combinedOutput);
360
- signals.push(...patternMatches);
361
- const stackTrace = this.detectStackTrace(combinedOutput);
362
- if (stackTrace.hasStackTrace) {
363
- signals.push({
364
- type: "stack_trace",
365
- weight: 0.95,
366
- value: stackTrace.frames.slice(0, 5).join(`
367
- `),
368
- description: `${stackTrace.language} stack trace detected`
369
- });
370
- }
371
- const confidence = this.calculateConfidence(signals);
372
- const detected = confidence >= 0.5;
373
- const errorType = this.classifyErrorType(signals, combinedOutput);
374
- const severity = this.determineSeverity(signals, toolOutput.exitCode);
375
- const { message, stack } = this.extractErrorDetails(combinedOutput);
376
- const sanitizedMessage = this.privacyFilter.sanitize(message);
377
- const sanitizedStack = stack ? this.privacyFilter.sanitize(stack) : undefined;
378
- const sanitizedOutput = this.privacyFilter.sanitize(combinedOutput.substring(0, 5000));
379
- return {
380
- detected,
381
- confidence,
382
- errorType,
383
- severity,
384
- signals,
385
- errorMessage: sanitizedMessage.sanitized,
386
- errorStack: sanitizedStack?.sanitized,
387
- rawOutput: sanitizedOutput.sanitized
388
- };
389
- }
390
- containsErrorKeywords(content) {
331
+ function createErrorDetector(privacyFilter) {
332
+ const filter = privacyFilter || createPrivacyFilter();
333
+ function containsErrorKeywords(content) {
391
334
  return ERROR_PATTERNS.universal.some((p) => p.test(content));
392
335
  }
393
- detectErrorPatterns(content) {
336
+ function detectErrorPatterns(content) {
394
337
  const signals = [];
395
338
  const weights = {
396
339
  prefixed: 0.85,
@@ -418,7 +361,7 @@ ${toolOutput.stderr || ""}`;
418
361
  }
419
362
  return signals;
420
363
  }
421
- detectStackTrace(content) {
364
+ function detectStackTrace(content) {
422
365
  for (const [language, pattern] of Object.entries(STACK_TRACE_PATTERNS)) {
423
366
  const globalPattern = new RegExp(pattern.source, "gm");
424
367
  const matches = content.match(globalPattern);
@@ -436,7 +379,7 @@ ${toolOutput.stderr || ""}`;
436
379
  frames: []
437
380
  };
438
381
  }
439
- calculateConfidence(signals) {
382
+ function calculateConfidence(signals) {
440
383
  if (signals.length === 0)
441
384
  return 0;
442
385
  const totalWeight = signals.reduce((sum, s) => sum + s.weight, 0);
@@ -444,7 +387,7 @@ ${toolOutput.stderr || ""}`;
444
387
  const multiplier = Math.min(1.2, 1 + signals.length * 0.05);
445
388
  return Math.min(1, avgWeight * multiplier);
446
389
  }
447
- classifyErrorType(signals, content) {
390
+ function classifyErrorType(signals, content) {
448
391
  if (ERROR_PATTERNS.build.some((p) => p.test(content)))
449
392
  return "build";
450
393
  if (ERROR_PATTERNS.package.some((p) => p.test(content)))
@@ -466,7 +409,7 @@ ${toolOutput.stderr || ""}`;
466
409
  return "runtime";
467
410
  return "unknown";
468
411
  }
469
- determineSeverity(signals, exitCode) {
412
+ function determineSeverity(signals, exitCode) {
470
413
  if (exitCode !== undefined && EXIT_CODE_SEVERITY[exitCode]) {
471
414
  return EXIT_CODE_SEVERITY[exitCode];
472
415
  }
@@ -477,14 +420,18 @@ ${toolOutput.stderr || ""}`;
477
420
  return "error";
478
421
  return "warning";
479
422
  }
480
- extractErrorDetails(output) {
423
+ function isErrorLine(line) {
424
+ const trimmed = line.trim();
425
+ return /^(Error|TypeError|ReferenceError|SyntaxError|RangeError):/i.test(trimmed) || /^(error|FAIL|fatal|panic)\b/i.test(trimmed) || /^error\[E\d+\]:/.test(trimmed) || /^error TS\d+:/.test(trimmed);
426
+ }
427
+ function extractErrorDetails(output) {
481
428
  const lines = output.split(`
482
429
  `);
483
430
  let message = "";
484
431
  let stack = "";
485
432
  let inStack = false;
486
433
  for (const line of lines) {
487
- if (this.isErrorLine(line) && !message) {
434
+ if (isErrorLine(line) && !message) {
488
435
  message = line.trim();
489
436
  inStack = true;
490
437
  } else if (inStack && (line.match(/^\s+at\s/) || line.match(/^\s+File\s/) || line.match(/^\s+\d+:\s/) || line.match(/^\s+from\s/))) {
@@ -505,12 +452,67 @@ ${toolOutput.stderr || ""}`;
505
452
  stack: stack || undefined
506
453
  };
507
454
  }
508
- isErrorLine(line) {
509
- const trimmed = line.trim();
510
- 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);
511
- }
455
+ return {
456
+ detect(toolOutput) {
457
+ const signals = [];
458
+ const combinedOutput = `${toolOutput.output || ""}
459
+ ${toolOutput.stderr || ""}`;
460
+ if (toolOutput.exitCode !== undefined && toolOutput.exitCode !== 0) {
461
+ const severity2 = EXIT_CODE_SEVERITY[toolOutput.exitCode] || "error";
462
+ signals.push({
463
+ type: "exit_code",
464
+ weight: 0.9,
465
+ value: toolOutput.exitCode,
466
+ description: `Non-zero exit code: ${toolOutput.exitCode} (${severity2})`
467
+ });
468
+ }
469
+ if (toolOutput.stderr && toolOutput.stderr.trim().length > 0) {
470
+ const hasErrorKeywords = containsErrorKeywords(toolOutput.stderr);
471
+ const stderrWeight = hasErrorKeywords ? 0.85 : 0.4;
472
+ signals.push({
473
+ type: "stderr",
474
+ weight: stderrWeight,
475
+ value: toolOutput.stderr.substring(0, 500),
476
+ description: hasErrorKeywords ? "Stderr with error keywords" : "Stderr output present"
477
+ });
478
+ }
479
+ const patternMatches = detectErrorPatterns(combinedOutput);
480
+ signals.push(...patternMatches);
481
+ const stackTrace = detectStackTrace(combinedOutput);
482
+ if (stackTrace.hasStackTrace) {
483
+ signals.push({
484
+ type: "stack_trace",
485
+ weight: 0.95,
486
+ value: stackTrace.frames.slice(0, 5).join(`
487
+ `),
488
+ description: `${stackTrace.language} stack trace detected`
489
+ });
490
+ }
491
+ const confidence = calculateConfidence(signals);
492
+ const detected = confidence >= 0.5;
493
+ const errorType = classifyErrorType(signals, combinedOutput);
494
+ const severity = determineSeverity(signals, toolOutput.exitCode);
495
+ const { message, stack } = extractErrorDetails(combinedOutput);
496
+ const sanitizedMessage = filter.sanitize(message);
497
+ const sanitizedStack = stack ? filter.sanitize(stack) : undefined;
498
+ const sanitizedOutput = filter.sanitize(combinedOutput.substring(0, 5000));
499
+ return {
500
+ detected,
501
+ confidence,
502
+ errorType,
503
+ severity,
504
+ signals,
505
+ errorMessage: sanitizedMessage.sanitized,
506
+ errorStack: sanitizedStack?.sanitized,
507
+ rawOutput: sanitizedOutput.sanitized
508
+ };
509
+ }
510
+ };
512
511
  }
513
- var defaultErrorDetector = new ErrorDetector;
512
+ var ErrorDetector = {
513
+ create: createErrorDetector
514
+ };
515
+ var defaultErrorDetector = createErrorDetector();
514
516
 
515
517
  // src/storage/local-store.ts
516
518
  import Database from "better-sqlite3";
@@ -651,194 +653,196 @@ var MIGRATIONS = [
651
653
  ];
652
654
 
653
655
  // src/storage/local-store.ts
654
- class LocalStore {
655
- db;
656
- constructor(projectDirectory) {
657
- const dbPath = `${projectDirectory}/.fixhive/fixhive.db`;
658
- const dir = dirname(dbPath);
659
- if (!existsSync(dir)) {
660
- mkdirSync(dir, { recursive: true });
661
- }
662
- this.db = new Database(dbPath);
663
- this.db.pragma("journal_mode = WAL");
664
- this.db.pragma("foreign_keys = ON");
665
- runMigrations(this.db);
666
- }
667
- createErrorRecord(data) {
668
- const id = uuidv4();
669
- const errorHash = generateErrorFingerprint(data.errorMessage, data.errorStack);
670
- const stmt = this.db.prepare(`
671
- INSERT INTO error_records (
672
- id, error_hash, error_type, error_message, error_stack,
673
- language, framework, tool_name, tool_input, session_id, status
674
- ) VALUES (
675
- @id, @errorHash, @errorType, @errorMessage, @errorStack,
676
- @language, @framework, @toolName, @toolInput, @sessionId, 'unresolved'
677
- )
678
- `);
679
- stmt.run({
680
- id,
681
- errorHash,
682
- errorType: data.errorType,
683
- errorMessage: data.errorMessage,
684
- errorStack: data.errorStack || null,
685
- language: data.language || null,
686
- framework: data.framework || null,
687
- toolName: data.toolName,
688
- toolInput: JSON.stringify(data.toolInput),
689
- sessionId: data.sessionId
690
- });
691
- this.incrementStat("total_errors");
692
- return this.getErrorById(id);
693
- }
694
- getErrorById(id) {
695
- const stmt = this.db.prepare("SELECT * FROM error_records WHERE id = ?");
696
- const row = stmt.get(id);
697
- return row ? this.rowToRecord(row) : null;
656
+ var ALLOWED_STATS = [
657
+ "total_errors",
658
+ "resolved_errors",
659
+ "uploaded_errors",
660
+ "queries_made"
661
+ ];
662
+ function rowToRecord(row) {
663
+ return {
664
+ id: row.id,
665
+ errorHash: row.error_hash,
666
+ errorType: row.error_type,
667
+ errorMessage: row.error_message,
668
+ errorStack: row.error_stack || undefined,
669
+ language: row.language || undefined,
670
+ framework: row.framework || undefined,
671
+ toolName: row.tool_name,
672
+ toolInput: JSON.parse(row.tool_input || "{}"),
673
+ sessionId: row.session_id,
674
+ status: row.status,
675
+ resolution: row.resolution || undefined,
676
+ resolutionCode: row.resolution_code || undefined,
677
+ createdAt: row.created_at,
678
+ resolvedAt: row.resolved_at || undefined,
679
+ uploadedAt: row.uploaded_at || undefined,
680
+ cloudKnowledgeId: row.cloud_knowledge_id || undefined
681
+ };
682
+ }
683
+ function createLocalStore(projectDirectory) {
684
+ const dbPath = `${projectDirectory}/.fixhive/fixhive.db`;
685
+ const dir = dirname(dbPath);
686
+ if (!existsSync(dir)) {
687
+ mkdirSync(dir, { recursive: true });
698
688
  }
699
- getSessionErrors(sessionId, options) {
700
- let query = "SELECT * FROM error_records WHERE session_id = ?";
701
- const params = [sessionId];
702
- if (options?.status) {
703
- query += " AND status = ?";
704
- params.push(options.status);
689
+ const db = new Database(dbPath);
690
+ db.pragma("journal_mode = WAL");
691
+ db.pragma("foreign_keys = ON");
692
+ runMigrations(db);
693
+ function incrementStat(stat) {
694
+ if (!ALLOWED_STATS.includes(stat)) {
695
+ throw new Error(`Invalid stat name: ${stat}. Allowed: ${ALLOWED_STATS.join(", ")}`);
705
696
  }
706
- query += " ORDER BY created_at DESC";
707
- if (options?.limit) {
708
- query += " LIMIT ?";
709
- params.push(options.limit);
710
- }
711
- const stmt = this.db.prepare(query);
712
- return stmt.all(...params).map((row) => this.rowToRecord(row));
713
- }
714
- getUnresolvedErrors(sessionId) {
715
- return this.getSessionErrors(sessionId, { status: "unresolved" });
716
- }
717
- getRecentErrors(limit = 10) {
718
- const stmt = this.db.prepare("SELECT * FROM error_records ORDER BY created_at DESC LIMIT ?");
719
- return stmt.all(limit).map((row) => this.rowToRecord(row));
697
+ const stmt = db.prepare(`UPDATE usage_stats SET ${stat} = ${stat} + 1 WHERE id = 1`);
698
+ stmt.run();
720
699
  }
721
- markResolved(id, data) {
722
- const stmt = this.db.prepare(`
723
- UPDATE error_records
724
- SET status = 'resolved',
725
- resolution = ?,
726
- resolution_code = ?,
727
- resolved_at = datetime('now')
728
- WHERE id = ?
729
- `);
730
- const result = stmt.run(data.resolution, data.resolutionCode || null, id);
731
- if (result.changes > 0) {
732
- this.incrementStat("resolved_errors");
700
+ return {
701
+ createErrorRecord(data) {
702
+ const id = uuidv4();
703
+ const errorHash = generateErrorFingerprint(data.errorMessage, data.errorStack);
704
+ const stmt = db.prepare(`
705
+ INSERT INTO error_records (
706
+ id, error_hash, error_type, error_message, error_stack,
707
+ language, framework, tool_name, tool_input, session_id, status
708
+ ) VALUES (
709
+ @id, @errorHash, @errorType, @errorMessage, @errorStack,
710
+ @language, @framework, @toolName, @toolInput, @sessionId, 'unresolved'
711
+ )
712
+ `);
713
+ stmt.run({
714
+ id,
715
+ errorHash,
716
+ errorType: data.errorType,
717
+ errorMessage: data.errorMessage,
718
+ errorStack: data.errorStack || null,
719
+ language: data.language || null,
720
+ framework: data.framework || null,
721
+ toolName: data.toolName,
722
+ toolInput: JSON.stringify(data.toolInput),
723
+ sessionId: data.sessionId
724
+ });
725
+ incrementStat("total_errors");
733
726
  return this.getErrorById(id);
727
+ },
728
+ getErrorById(id) {
729
+ const stmt = db.prepare("SELECT * FROM error_records WHERE id = ?");
730
+ const row = stmt.get(id);
731
+ return row ? rowToRecord(row) : null;
732
+ },
733
+ getSessionErrors(sessionId, options) {
734
+ let query = "SELECT * FROM error_records WHERE session_id = ?";
735
+ const params = [sessionId];
736
+ if (options?.status) {
737
+ query += " AND status = ?";
738
+ params.push(options.status);
739
+ }
740
+ query += " ORDER BY created_at DESC";
741
+ if (options?.limit) {
742
+ query += " LIMIT ?";
743
+ params.push(options.limit);
744
+ }
745
+ const stmt = db.prepare(query);
746
+ return stmt.all(...params).map((row) => rowToRecord(row));
747
+ },
748
+ getUnresolvedErrors(sessionId) {
749
+ return this.getSessionErrors(sessionId, { status: "unresolved" });
750
+ },
751
+ getRecentErrors(limit = 10) {
752
+ const stmt = db.prepare("SELECT * FROM error_records ORDER BY created_at DESC LIMIT ?");
753
+ return stmt.all(limit).map((row) => rowToRecord(row));
754
+ },
755
+ markResolved(id, data) {
756
+ const stmt = db.prepare(`
757
+ UPDATE error_records
758
+ SET status = 'resolved',
759
+ resolution = ?,
760
+ resolution_code = ?,
761
+ resolved_at = datetime('now')
762
+ WHERE id = ?
763
+ `);
764
+ const result = stmt.run(data.resolution, data.resolutionCode || null, id);
765
+ if (result.changes > 0) {
766
+ incrementStat("resolved_errors");
767
+ return this.getErrorById(id);
768
+ }
769
+ return null;
770
+ },
771
+ markUploaded(id, cloudKnowledgeId) {
772
+ const stmt = db.prepare(`
773
+ UPDATE error_records
774
+ SET status = 'uploaded',
775
+ cloud_knowledge_id = ?,
776
+ uploaded_at = datetime('now')
777
+ WHERE id = ?
778
+ `);
779
+ const result = stmt.run(cloudKnowledgeId, id);
780
+ if (result.changes > 0) {
781
+ incrementStat("uploaded_errors");
782
+ }
783
+ },
784
+ findSimilarErrors(errorHash) {
785
+ const stmt = db.prepare("SELECT * FROM error_records WHERE error_hash = ? ORDER BY created_at DESC");
786
+ return stmt.all(errorHash).map((row) => rowToRecord(row));
787
+ },
788
+ getCachedResults(errorHash) {
789
+ const stmt = db.prepare(`
790
+ SELECT results FROM query_cache
791
+ WHERE error_hash = ? AND expires_at > datetime('now')
792
+ ORDER BY created_at DESC LIMIT 1
793
+ `);
794
+ const row = stmt.get(errorHash);
795
+ if (row) {
796
+ return JSON.parse(row.results);
797
+ }
798
+ return null;
799
+ },
800
+ cacheResults(errorHash, results, expirationMs = 3600000) {
801
+ const id = uuidv4();
802
+ const expiresAt = new Date(Date.now() + expirationMs).toISOString();
803
+ const stmt = db.prepare(`
804
+ INSERT INTO query_cache (id, error_hash, results, expires_at)
805
+ VALUES (?, ?, ?, ?)
806
+ `);
807
+ stmt.run(id, errorHash, JSON.stringify(results), expiresAt);
808
+ incrementStat("queries_made");
809
+ },
810
+ clearExpiredCache() {
811
+ const stmt = db.prepare("DELETE FROM query_cache WHERE expires_at <= datetime('now')");
812
+ const result = stmt.run();
813
+ return result.changes;
814
+ },
815
+ getStats() {
816
+ const stmt = db.prepare("SELECT total_errors, resolved_errors, uploaded_errors FROM usage_stats WHERE id = 1");
817
+ const row = stmt.get();
818
+ return {
819
+ totalErrors: row.total_errors,
820
+ resolvedErrors: row.resolved_errors,
821
+ uploadedErrors: row.uploaded_errors
822
+ };
823
+ },
824
+ getPreference(key) {
825
+ const stmt = db.prepare("SELECT value FROM user_preferences WHERE key = ?");
826
+ const row = stmt.get(key);
827
+ return row?.value || null;
828
+ },
829
+ setPreference(key, value) {
830
+ const stmt = db.prepare(`
831
+ INSERT OR REPLACE INTO user_preferences (key, value) VALUES (?, ?)
832
+ `);
833
+ stmt.run(key, value);
834
+ },
835
+ close() {
836
+ db.close();
837
+ },
838
+ getDatabase() {
839
+ return db;
734
840
  }
735
- return null;
736
- }
737
- markUploaded(id, cloudKnowledgeId) {
738
- const stmt = this.db.prepare(`
739
- UPDATE error_records
740
- SET status = 'uploaded',
741
- cloud_knowledge_id = ?,
742
- uploaded_at = datetime('now')
743
- WHERE id = ?
744
- `);
745
- const result = stmt.run(cloudKnowledgeId, id);
746
- if (result.changes > 0) {
747
- this.incrementStat("uploaded_errors");
748
- }
749
- }
750
- findSimilarErrors(errorHash) {
751
- const stmt = this.db.prepare("SELECT * FROM error_records WHERE error_hash = ? ORDER BY created_at DESC");
752
- return stmt.all(errorHash).map((row) => this.rowToRecord(row));
753
- }
754
- getCachedResults(errorHash) {
755
- const stmt = this.db.prepare(`
756
- SELECT results FROM query_cache
757
- WHERE error_hash = ? AND expires_at > datetime('now')
758
- ORDER BY created_at DESC LIMIT 1
759
- `);
760
- const row = stmt.get(errorHash);
761
- if (row) {
762
- return JSON.parse(row.results);
763
- }
764
- return null;
765
- }
766
- cacheResults(errorHash, results, expirationMs = 3600000) {
767
- const id = uuidv4();
768
- const expiresAt = new Date(Date.now() + expirationMs).toISOString();
769
- const stmt = this.db.prepare(`
770
- INSERT INTO query_cache (id, error_hash, results, expires_at)
771
- VALUES (?, ?, ?, ?)
772
- `);
773
- stmt.run(id, errorHash, JSON.stringify(results), expiresAt);
774
- this.incrementStat("queries_made");
775
- }
776
- clearExpiredCache() {
777
- const stmt = this.db.prepare("DELETE FROM query_cache WHERE expires_at <= datetime('now')");
778
- const result = stmt.run();
779
- return result.changes;
780
- }
781
- getStats() {
782
- const stmt = this.db.prepare("SELECT total_errors, resolved_errors, uploaded_errors FROM usage_stats WHERE id = 1");
783
- const row = stmt.get();
784
- return {
785
- totalErrors: row.total_errors,
786
- resolvedErrors: row.resolved_errors,
787
- uploadedErrors: row.uploaded_errors
788
- };
789
- }
790
- static ALLOWED_STATS = [
791
- "total_errors",
792
- "resolved_errors",
793
- "uploaded_errors",
794
- "queries_made"
795
- ];
796
- incrementStat(stat) {
797
- if (!LocalStore.ALLOWED_STATS.includes(stat)) {
798
- throw new Error(`Invalid stat name: ${stat}. Allowed: ${LocalStore.ALLOWED_STATS.join(", ")}`);
799
- }
800
- const stmt = this.db.prepare(`UPDATE usage_stats SET ${stat} = ${stat} + 1 WHERE id = 1`);
801
- stmt.run();
802
- }
803
- getPreference(key) {
804
- const stmt = this.db.prepare("SELECT value FROM user_preferences WHERE key = ?");
805
- const row = stmt.get(key);
806
- return row?.value || null;
807
- }
808
- setPreference(key, value) {
809
- const stmt = this.db.prepare(`
810
- INSERT OR REPLACE INTO user_preferences (key, value) VALUES (?, ?)
811
- `);
812
- stmt.run(key, value);
813
- }
814
- rowToRecord(row) {
815
- return {
816
- id: row.id,
817
- errorHash: row.error_hash,
818
- errorType: row.error_type,
819
- errorMessage: row.error_message,
820
- errorStack: row.error_stack || undefined,
821
- language: row.language || undefined,
822
- framework: row.framework || undefined,
823
- toolName: row.tool_name,
824
- toolInput: JSON.parse(row.tool_input || "{}"),
825
- sessionId: row.session_id,
826
- status: row.status,
827
- resolution: row.resolution || undefined,
828
- resolutionCode: row.resolution_code || undefined,
829
- createdAt: row.created_at,
830
- resolvedAt: row.resolved_at || undefined,
831
- uploadedAt: row.uploaded_at || undefined,
832
- cloudKnowledgeId: row.cloud_knowledge_id || undefined
833
- };
834
- }
835
- close() {
836
- this.db.close();
837
- }
838
- getDatabase() {
839
- return this.db;
840
- }
841
+ };
841
842
  }
843
+ var LocalStore = {
844
+ create: createLocalStore
845
+ };
842
846
 
843
847
  // src/cloud/client.ts
844
848
  import { createClient } from "@supabase/supabase-js";
@@ -848,52 +852,28 @@ import OpenAI from "openai";
848
852
  var DEFAULT_MODEL = "text-embedding-3-small";
849
853
  var DEFAULT_DIMENSIONS = 1536;
850
854
  var MAX_INPUT_LENGTH = 30000;
851
-
852
- class EmbeddingService {
853
- client;
854
- model;
855
- dimensions;
856
- constructor(apiKey, model, dimensions) {
857
- this.client = new OpenAI({ apiKey });
858
- this.model = model || DEFAULT_MODEL;
859
- this.dimensions = dimensions || DEFAULT_DIMENSIONS;
855
+ function cosineSimilarity(a, b) {
856
+ if (a.length !== b.length) {
857
+ throw new Error("Embeddings must have same dimensions");
860
858
  }
861
- async generate(text) {
862
- const truncated = this.truncateText(text);
863
- const response = await this.client.embeddings.create({
864
- model: this.model,
865
- input: truncated,
866
- dimensions: this.dimensions
867
- });
868
- return response.data[0].embedding;
859
+ let dotProduct = 0;
860
+ let normA = 0;
861
+ let normB = 0;
862
+ for (let i = 0;i < a.length; i++) {
863
+ dotProduct += a[i] * b[i];
864
+ normA += a[i] * a[i];
865
+ normB += b[i] * b[i];
869
866
  }
870
- async generateBatch(texts) {
871
- const truncated = texts.map((t) => this.truncateText(t));
872
- const response = await this.client.embeddings.create({
873
- model: this.model,
874
- input: truncated,
875
- dimensions: this.dimensions
876
- });
877
- return response.data.map((d) => d.embedding);
878
- }
879
- async generateErrorEmbedding(errorMessage, errorStack, context) {
880
- const parts = [];
881
- if (context?.language) {
882
- parts.push(`Language: ${context.language}`);
883
- }
884
- if (context?.framework) {
885
- parts.push(`Framework: ${context.framework}`);
886
- }
887
- parts.push(`Error: ${errorMessage}`);
888
- if (errorStack) {
889
- parts.push(`Stack Trace:
890
- ${errorStack}`);
891
- }
892
- const text = parts.join(`
893
- `);
894
- return this.generate(text);
895
- }
896
- truncateText(text) {
867
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
868
+ if (magnitude === 0)
869
+ return 0;
870
+ return dotProduct / magnitude;
871
+ }
872
+ function createEmbeddingService(config) {
873
+ const client = new OpenAI({ apiKey: config.apiKey });
874
+ const model = config.model || DEFAULT_MODEL;
875
+ const dimensions = config.dimensions || DEFAULT_DIMENSIONS;
876
+ function truncateText(text) {
897
877
  if (text.length <= MAX_INPUT_LENGTH) {
898
878
  return text;
899
879
  }
@@ -905,33 +885,54 @@ ${errorStack}`);
905
885
  }
906
886
  return truncated;
907
887
  }
908
- static cosineSimilarity(a, b) {
909
- if (a.length !== b.length) {
910
- throw new Error("Embeddings must have same dimensions");
911
- }
912
- let dotProduct = 0;
913
- let normA = 0;
914
- let normB = 0;
915
- for (let i = 0;i < a.length; i++) {
916
- dotProduct += a[i] * b[i];
917
- normA += a[i] * a[i];
918
- normB += b[i] * b[i];
888
+ return {
889
+ async generate(text) {
890
+ const truncated = truncateText(text);
891
+ const response = await client.embeddings.create({
892
+ model,
893
+ input: truncated,
894
+ dimensions
895
+ });
896
+ return response.data[0].embedding;
897
+ },
898
+ async generateBatch(texts) {
899
+ const truncated = texts.map((t) => truncateText(t));
900
+ const response = await client.embeddings.create({
901
+ model,
902
+ input: truncated,
903
+ dimensions
904
+ });
905
+ return response.data.map((d) => d.embedding);
906
+ },
907
+ async generateErrorEmbedding(errorMessage, errorStack, context) {
908
+ const parts = [];
909
+ if (context?.language) {
910
+ parts.push(`Language: ${context.language}`);
911
+ }
912
+ if (context?.framework) {
913
+ parts.push(`Framework: ${context.framework}`);
914
+ }
915
+ parts.push(`Error: ${errorMessage}`);
916
+ if (errorStack) {
917
+ parts.push(`Stack Trace:
918
+ ${errorStack}`);
919
+ }
920
+ const text = parts.join(`
921
+ `);
922
+ return this.generate(text);
923
+ },
924
+ getDimensions() {
925
+ return dimensions;
926
+ },
927
+ getModel() {
928
+ return model;
919
929
  }
920
- const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
921
- if (magnitude === 0)
922
- return 0;
923
- return dotProduct / magnitude;
924
- }
925
- getDimensions() {
926
- return this.dimensions;
927
- }
928
- getModel() {
929
- return this.model;
930
- }
931
- }
932
- function createEmbeddingService(config) {
933
- return new EmbeddingService(config.apiKey, config.model, config.dimensions);
930
+ };
934
931
  }
932
+ var EmbeddingService = {
933
+ create: createEmbeddingService,
934
+ cosineSimilarity
935
+ };
935
936
 
936
937
  // src/cloud/client.ts
937
938
  function mapToKnowledgeEntry(row) {
@@ -962,7 +963,7 @@ async function createCloudClient(config) {
962
963
  let embedding = null;
963
964
  if (config.openaiApiKey) {
964
965
  try {
965
- embedding = new EmbeddingService(config.openaiApiKey);
966
+ embedding = createEmbeddingService({ apiKey: config.openaiApiKey });
966
967
  } catch (err) {
967
968
  console.warn("[FixHive] Failed to initialize embedding service:", err);
968
969
  }
@@ -1376,10 +1377,10 @@ var FixHivePlugin = async (ctx) => {
1376
1377
  console.log("[FixHive] Plugin loaded");
1377
1378
  console.log(`[FixHive] Project: ${ctx.directory}`);
1378
1379
  console.log(`[FixHive] Cloud: ${config.supabaseUrl ? "enabled" : "disabled"}`);
1379
- const privacyFilter = new PrivacyFilter;
1380
+ const privacyFilter = createPrivacyFilter();
1380
1381
  const filterContext = createFilterContext(ctx.directory);
1381
- const errorDetector = new ErrorDetector(privacyFilter);
1382
- const localStore = new LocalStore(ctx.directory);
1382
+ const errorDetector = createErrorDetector(privacyFilter);
1383
+ const localStore = createLocalStore(ctx.directory);
1383
1384
  let cloudClient = null;
1384
1385
  if (config.supabaseUrl && config.supabaseAnonKey) {
1385
1386
  try {
@@ -1599,9 +1600,13 @@ export {
1599
1600
  defaultPrivacyFilter,
1600
1601
  defaultErrorDetector,
1601
1602
  plugin_default as default,
1603
+ createPrivacyFilter,
1604
+ createLocalStore,
1602
1605
  createFilterContext,
1606
+ createErrorDetector,
1603
1607
  createEmbeddingService,
1604
1608
  createCloudClient,
1609
+ cosineSimilarity,
1605
1610
  calculateStringSimilarity,
1606
1611
  PrivacyFilter,
1607
1612
  LocalStore,
@@ -5,94 +5,42 @@
5
5
  import Database from 'better-sqlite3';
6
6
  import type { LocalErrorRecord, ErrorStatus, LocalStats, CloudKnowledgeEntry } from '../types/index.js';
7
7
  /**
8
- * Local Store Class
9
- * Manages SQLite database for error records and caching
8
+ * LocalStore interface - defines all public methods
10
9
  */
11
- export declare class LocalStore {
12
- private db;
13
- constructor(projectDirectory: string);
14
- /**
15
- * Create a new error record
16
- */
10
+ export interface LocalStore {
17
11
  createErrorRecord(data: Omit<LocalErrorRecord, 'id' | 'errorHash' | 'status' | 'createdAt'>): LocalErrorRecord;
18
- /**
19
- * Get error record by ID
20
- */
21
12
  getErrorById(id: string): LocalErrorRecord | null;
22
- /**
23
- * Get errors by session
24
- */
25
13
  getSessionErrors(sessionId: string, options?: {
26
14
  status?: ErrorStatus;
27
15
  limit?: number;
28
16
  }): LocalErrorRecord[];
29
- /**
30
- * Get unresolved errors for a session
31
- */
32
17
  getUnresolvedErrors(sessionId: string): LocalErrorRecord[];
33
- /**
34
- * Get recent errors across all sessions
35
- */
36
18
  getRecentErrors(limit?: number): LocalErrorRecord[];
37
- /**
38
- * Mark error as resolved
39
- */
40
19
  markResolved(id: string, data: {
41
20
  resolution: string;
42
21
  resolutionCode?: string;
43
22
  }): LocalErrorRecord | null;
44
- /**
45
- * Mark error as uploaded to cloud
46
- */
47
23
  markUploaded(id: string, cloudKnowledgeId: string): void;
48
- /**
49
- * Find similar errors by hash
50
- */
51
24
  findSimilarErrors(errorHash: string): LocalErrorRecord[];
52
- /**
53
- * Get cached query results
54
- */
55
25
  getCachedResults(errorHash: string): CloudKnowledgeEntry[] | null;
56
- /**
57
- * Cache query results
58
- */
59
26
  cacheResults(errorHash: string, results: CloudKnowledgeEntry[], expirationMs?: number): void;
60
- /**
61
- * Clear expired cache entries
62
- */
63
27
  clearExpiredCache(): number;
64
- /**
65
- * Get usage statistics
66
- */
67
28
  getStats(): LocalStats;
68
- /**
69
- * Allowed stat column names for incrementStat (whitelist to prevent SQL injection)
70
- */
71
- private static readonly ALLOWED_STATS;
72
- /**
73
- * Increment a stat counter
74
- * @throws Error if stat name is not in the allowed whitelist
75
- */
76
- private incrementStat;
77
- /**
78
- * Get preference value
79
- */
80
29
  getPreference(key: string): string | null;
81
- /**
82
- * Set preference value
83
- */
84
30
  setPreference(key: string, value: string): void;
85
- /**
86
- * Convert database row to LocalErrorRecord
87
- */
88
- private rowToRecord;
89
- /**
90
- * Close database connection
91
- */
92
31
  close(): void;
93
- /**
94
- * Get database for advanced queries
95
- */
96
32
  getDatabase(): Database.Database;
97
33
  }
34
+ /**
35
+ * Create a LocalStore instance
36
+ * Factory function pattern to avoid ES6 class issues with Bun
37
+ */
38
+ export declare function createLocalStore(projectDirectory: string): LocalStore;
39
+ /**
40
+ * Legacy class wrapper for backwards compatibility
41
+ * @deprecated Use createLocalStore() instead
42
+ */
43
+ export declare const LocalStore: {
44
+ create: typeof createLocalStore;
45
+ };
98
46
  //# sourceMappingURL=local-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-store.d.ts","sourceRoot":"","sources":["../../src/storage/local-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAI3B;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,EAAE,CAAoB;gBAElB,gBAAgB,EAAE,MAAM;IAoBpC;;OAEG;IACH,iBAAiB,CACf,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC,GACxE,gBAAgB;IAiCnB;;OAEG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAMjD;;OAEG;IACH,gBAAgB,CACd,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACjD,gBAAgB,EAAE;IAoBrB;;OAEG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAI1D;;OAEG;IACH,eAAe,CAAC,KAAK,GAAE,MAAW,GAAG,gBAAgB,EAAE;IAOvD;;OAEG;IACH,YAAY,CACV,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GACpD,gBAAgB,GAAG,IAAI;IAoB1B;;OAEG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAgBxD;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,EAAE;IASxD;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE,GAAG,IAAI;IAcjE;;OAEG;IACH,YAAY,CACV,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,mBAAmB,EAAE,EAC9B,YAAY,GAAE,MAAgB,GAC7B,IAAI;IAeP;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAQ3B;;OAEG;IACH,QAAQ,IAAI,UAAU;IAiBtB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAK1B;IAEX;;;OAGG;IACH,OAAO,CAAC,aAAa;IAWrB;;OAEG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAMzC;;OAEG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAS/C;;OAEG;IACH,OAAO,CAAC,WAAW;IAsBnB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,WAAW,IAAI,QAAQ,CAAC,QAAQ;CAGjC"}
1
+ {"version":3,"file":"local-store.d.ts","sourceRoot":"","sources":["../../src/storage/local-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAc3B;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC,GAAG,gBAAgB,CAAC;IAC/G,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAClD,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,gBAAgB,EAAE,CAAC;IAC5G,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAC3D,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAAC;IACpD,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,gBAAgB,GAAG,IAAI,CAAC;IACzG,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzD,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAAC;IACzD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE,GAAG,IAAI,CAAC;IAClE,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7F,iBAAiB,IAAI,MAAM,CAAC;IAC5B,QAAQ,IAAI,UAAU,CAAC;IACvB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC1C,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAChD,KAAK,IAAI,IAAI,CAAC;IACd,WAAW,IAAI,QAAQ,CAAC,QAAQ,CAAC;CAClC;AA2BD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,UAAU,CA+RrE;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU;;CAEtB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@the-magic-tower/fixhive-opencode-plugin",
3
- "version": "0.1.16",
3
+ "version": "0.1.19",
4
4
  "description": "Community-based error knowledge sharing for OpenCode",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",