@the-magic-tower/fixhive-opencode-plugin 0.1.16 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cloud/embedding.d.ts +22 -34
- package/dist/cloud/embedding.d.ts.map +1 -1
- package/dist/core/error-detector.d.ts +15 -41
- package/dist/core/error-detector.d.ts.map +1 -1
- package/dist/core/privacy-filter.d.ts +14 -25
- package/dist/core/privacy-filter.d.ts.map +1 -1
- package/dist/index.d.ts +15 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +396 -391
- package/dist/storage/local-store.d.ts +14 -66
- package/dist/storage/local-store.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -3,53 +3,41 @@
|
|
|
3
3
|
* Generates text embeddings for semantic search using OpenAI
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* Generates embeddings for error messages and solutions
|
|
6
|
+
* EmbeddingService interface - defines all public methods
|
|
8
7
|
*/
|
|
9
|
-
export
|
|
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
|
-
*
|
|
19
|
+
* EmbeddingService configuration
|
|
49
20
|
*/
|
|
50
|
-
export
|
|
21
|
+
export interface EmbeddingServiceConfig {
|
|
51
22
|
apiKey: string;
|
|
52
23
|
model?: string;
|
|
53
24
|
dimensions?: number;
|
|
54
|
-
}
|
|
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
|
|
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
|
-
*
|
|
9
|
-
* Analyzes tool outputs to detect errors
|
|
8
|
+
* ErrorDetector interface - defines all public methods
|
|
10
9
|
*/
|
|
11
|
-
export
|
|
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,
|
|
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
|
-
*
|
|
8
|
-
* Applies multiple filtering rules to sanitize sensitive content
|
|
7
|
+
* PrivacyFilter interface - defines all public methods
|
|
9
8
|
*/
|
|
10
|
-
export
|
|
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
|
|
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 {
|
|
28
|
-
export {
|
|
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 {
|
|
30
|
+
export { createLocalStore } from './storage/local-store.js';
|
|
31
31
|
export { runMigrations } from './storage/migrations.js';
|
|
32
|
-
export {
|
|
33
|
-
export {
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
162
|
-
|
|
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
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
332
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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
|
|
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,249 +653,227 @@ var MIGRATIONS = [
|
|
|
651
653
|
];
|
|
652
654
|
|
|
653
655
|
// src/storage/local-store.ts
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
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
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
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
|
-
|
|
707
|
-
|
|
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
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
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
|
-
|
|
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";
|
|
845
849
|
|
|
846
850
|
// src/cloud/embedding.ts
|
|
847
|
-
import OpenAI from "openai";
|
|
851
|
+
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
|
-
|
|
853
|
-
|
|
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
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
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
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
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
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
1380
|
+
const privacyFilter = createPrivacyFilter();
|
|
1380
1381
|
const filterContext = createFilterContext(ctx.directory);
|
|
1381
|
-
const errorDetector =
|
|
1382
|
-
const localStore =
|
|
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
|
-
*
|
|
9
|
-
* Manages SQLite database for error records and caching
|
|
8
|
+
* LocalStore interface - defines all public methods
|
|
10
9
|
*/
|
|
11
|
-
export
|
|
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;
|
|
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"}
|