@the-magic-tower/fixhive-opencode-plugin 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cloud/client.d.ts +7 -51
- package/dist/cloud/client.d.ts.map +1 -1
- package/dist/index.js +194 -227
- package/package.json +1 -1
package/dist/cloud/client.d.ts
CHANGED
|
@@ -14,75 +14,31 @@ export interface CloudClientConfig {
|
|
|
14
14
|
similarityThreshold?: number;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
* Manages communication with Supabase cloud database
|
|
17
|
+
* CloudClient interface - defines all public methods
|
|
19
18
|
*/
|
|
20
|
-
export
|
|
21
|
-
private supabase;
|
|
22
|
-
private embedding;
|
|
23
|
-
private contributorId;
|
|
24
|
-
private similarityThreshold;
|
|
25
|
-
private constructor();
|
|
26
|
-
/**
|
|
27
|
-
* Create a CloudClient instance (async factory for Bun compatibility)
|
|
28
|
-
*/
|
|
29
|
-
static create(config: CloudClientConfig): Promise<CloudClient>;
|
|
30
|
-
/**
|
|
31
|
-
* Search for similar errors in cloud knowledge base
|
|
32
|
-
*/
|
|
19
|
+
export interface CloudClient {
|
|
33
20
|
searchSimilar(request: SearchRequest): Promise<SearchResponse>;
|
|
34
|
-
/**
|
|
35
|
-
* Fallback text-based search
|
|
36
|
-
*/
|
|
37
|
-
private searchByText;
|
|
38
|
-
/**
|
|
39
|
-
* Upload a resolution to cloud knowledge base
|
|
40
|
-
*/
|
|
41
21
|
uploadResolution(request: UploadRequest): Promise<UploadResponse>;
|
|
42
|
-
/**
|
|
43
|
-
* Check for duplicate entries
|
|
44
|
-
*/
|
|
45
22
|
checkDuplicate(errorHash: string, embedding: number[]): Promise<DuplicateCheckResult>;
|
|
46
|
-
/**
|
|
47
|
-
* Vote on a knowledge entry (with duplicate vote prevention)
|
|
48
|
-
*/
|
|
49
23
|
vote(knowledgeId: string, helpful: boolean): Promise<{
|
|
50
24
|
success: boolean;
|
|
51
25
|
error?: string;
|
|
52
26
|
}>;
|
|
53
|
-
/**
|
|
54
|
-
* Report an entry for review
|
|
55
|
-
*/
|
|
56
27
|
reportEntry(knowledgeId: string, reason?: string): Promise<{
|
|
57
28
|
success: boolean;
|
|
58
29
|
}>;
|
|
59
|
-
/**
|
|
60
|
-
* Report helpful usage
|
|
61
|
-
*/
|
|
62
30
|
reportHelpful(knowledgeId: string): Promise<void>;
|
|
63
|
-
/**
|
|
64
|
-
* Get contributor statistics
|
|
65
|
-
*/
|
|
66
31
|
getContributorStats(): Promise<ContributorStats>;
|
|
67
|
-
/**
|
|
68
|
-
* Get entry by ID
|
|
69
|
-
*/
|
|
70
32
|
getEntry(id: string): Promise<CloudKnowledgeEntry | null>;
|
|
71
|
-
/**
|
|
72
|
-
* Map database row to CloudKnowledgeEntry
|
|
73
|
-
*/
|
|
74
|
-
private mapToKnowledgeEntry;
|
|
75
|
-
/**
|
|
76
|
-
* Get contributor ID
|
|
77
|
-
*/
|
|
78
33
|
getContributorId(): string;
|
|
79
|
-
/**
|
|
80
|
-
* Check if embedding service is available
|
|
81
|
-
*/
|
|
82
34
|
hasEmbeddingService(): boolean;
|
|
83
35
|
}
|
|
84
36
|
/**
|
|
85
|
-
* Create
|
|
37
|
+
* Create a CloudClient instance
|
|
38
|
+
* Factory function pattern to avoid ES6 class issues with Bun
|
|
86
39
|
*/
|
|
87
40
|
export declare function createCloudClient(config: CloudClientConfig): Promise<CloudClient>;
|
|
41
|
+
export declare const CloudClient: {
|
|
42
|
+
create: typeof createCloudClient;
|
|
43
|
+
};
|
|
88
44
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/cloud/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/cloud/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAI3B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC/D,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACtF,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3F,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACjF,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IAC1D,gBAAgB,IAAI,MAAM,CAAC;IAC3B,mBAAmB,IAAI,OAAO,CAAC;CAChC;AA6BD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CA0RvF;AAID,eAAO,MAAM,WAAW;;CAEvB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __require = import.meta.require;
|
|
19
|
-
|
|
20
2
|
// src/plugin/index.ts
|
|
21
3
|
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
22
4
|
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
@@ -858,6 +840,9 @@ class LocalStore {
|
|
|
858
840
|
}
|
|
859
841
|
}
|
|
860
842
|
|
|
843
|
+
// src/cloud/client.ts
|
|
844
|
+
import { createClient } from "@supabase/supabase-js";
|
|
845
|
+
|
|
861
846
|
// src/cloud/embedding.ts
|
|
862
847
|
import OpenAI from "openai";
|
|
863
848
|
var DEFAULT_MODEL = "text-embedding-3-small";
|
|
@@ -949,69 +934,68 @@ function createEmbeddingService(config) {
|
|
|
949
934
|
}
|
|
950
935
|
|
|
951
936
|
// src/cloud/client.ts
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
937
|
+
function mapToKnowledgeEntry(row) {
|
|
938
|
+
return {
|
|
939
|
+
id: row.id,
|
|
940
|
+
errorHash: row.error_hash,
|
|
941
|
+
errorType: row.error_type,
|
|
942
|
+
errorMessage: row.error_message,
|
|
943
|
+
errorStack: row.error_stack || undefined,
|
|
944
|
+
language: row.language,
|
|
945
|
+
framework: row.framework || undefined,
|
|
946
|
+
dependencies: row.dependencies || undefined,
|
|
947
|
+
resolutionDescription: row.resolution_description,
|
|
948
|
+
resolutionCode: row.resolution_code || undefined,
|
|
949
|
+
resolutionSteps: row.resolution_steps || undefined,
|
|
950
|
+
contributorId: row.contributor_id,
|
|
951
|
+
upvotes: row.upvotes || 0,
|
|
952
|
+
downvotes: row.downvotes || 0,
|
|
953
|
+
usageCount: row.usage_count || 0,
|
|
954
|
+
createdAt: row.created_at,
|
|
955
|
+
updatedAt: row.updated_at,
|
|
956
|
+
isVerified: row.is_verified || false,
|
|
957
|
+
similarity: row.similarity || undefined
|
|
958
|
+
};
|
|
959
959
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
this.embedding = embedding;
|
|
969
|
-
this.contributorId = contributorId;
|
|
970
|
-
this.similarityThreshold = similarityThreshold;
|
|
971
|
-
}
|
|
972
|
-
static async create(config) {
|
|
973
|
-
const createClientFn = await getCreateClient();
|
|
974
|
-
const supabase = createClientFn(config.supabaseUrl, config.supabaseAnonKey);
|
|
975
|
-
let embedding = null;
|
|
976
|
-
if (config.openaiApiKey) {
|
|
977
|
-
try {
|
|
978
|
-
embedding = new EmbeddingService(config.openaiApiKey);
|
|
979
|
-
} catch (err) {
|
|
980
|
-
console.warn("[FixHive] Failed to initialize embedding service:", err);
|
|
981
|
-
}
|
|
960
|
+
async function createCloudClient(config) {
|
|
961
|
+
const supabase = createClient(config.supabaseUrl, config.supabaseAnonKey);
|
|
962
|
+
let embedding = null;
|
|
963
|
+
if (config.openaiApiKey) {
|
|
964
|
+
try {
|
|
965
|
+
embedding = new EmbeddingService(config.openaiApiKey);
|
|
966
|
+
} catch (err) {
|
|
967
|
+
console.warn("[FixHive] Failed to initialize embedding service:", err);
|
|
982
968
|
}
|
|
983
|
-
const contributorId = config.contributorId || generateContributorId();
|
|
984
|
-
const similarityThreshold = config.similarityThreshold || 0.7;
|
|
985
|
-
return new CloudClient(supabase, embedding, contributorId, similarityThreshold);
|
|
986
969
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
970
|
+
const contributorId = config.contributorId || generateContributorId();
|
|
971
|
+
const similarityThreshold = config.similarityThreshold || 0.7;
|
|
972
|
+
async function checkDuplicateInternal(errorHash, embeddingData) {
|
|
973
|
+
const { data: hashMatch } = await supabase.from("knowledge_entries").select("id").eq("error_hash", errorHash).limit(1).single();
|
|
974
|
+
if (hashMatch) {
|
|
975
|
+
return {
|
|
976
|
+
isDuplicate: true,
|
|
977
|
+
existingId: hashMatch.id,
|
|
978
|
+
similarityScore: 1
|
|
979
|
+
};
|
|
991
980
|
}
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
query_embedding: embedding,
|
|
997
|
-
match_threshold: request.threshold || this.similarityThreshold,
|
|
998
|
-
match_count: request.limit || 10,
|
|
999
|
-
filter_language: request.language || null,
|
|
1000
|
-
filter_framework: request.framework || null
|
|
981
|
+
const { data, error } = await supabase.rpc("check_duplicate_entry", {
|
|
982
|
+
new_hash: errorHash,
|
|
983
|
+
new_embedding: embeddingData,
|
|
984
|
+
similarity_threshold: 0.95
|
|
1001
985
|
});
|
|
1002
|
-
if (error) {
|
|
1003
|
-
|
|
1004
|
-
return { results: [], queryTime: Date.now() - startTime, cached: false };
|
|
986
|
+
if (error || !data || data.length === 0) {
|
|
987
|
+
return { isDuplicate: false, similarityScore: 0 };
|
|
1005
988
|
}
|
|
989
|
+
const result = data[0];
|
|
1006
990
|
return {
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
991
|
+
isDuplicate: result.is_duplicate,
|
|
992
|
+
existingId: result.existing_id,
|
|
993
|
+
similarityScore: result.similarity_score
|
|
1010
994
|
};
|
|
1011
995
|
}
|
|
1012
|
-
async searchByText(request) {
|
|
996
|
+
async function searchByText(request) {
|
|
1013
997
|
const startTime = Date.now();
|
|
1014
|
-
let query =
|
|
998
|
+
let query = supabase.from("knowledge_entries").select("*").ilike("error_message", `%${request.errorMessage.substring(0, 100)}%`).order("upvotes", { ascending: false }).limit(request.limit || 10);
|
|
1015
999
|
if (request.language) {
|
|
1016
1000
|
query = query.eq("language", request.language);
|
|
1017
1001
|
}
|
|
@@ -1024,176 +1008,159 @@ ${request.errorStack || ""}`;
|
|
|
1024
1008
|
return { results: [], queryTime: Date.now() - startTime, cached: false };
|
|
1025
1009
|
}
|
|
1026
1010
|
return {
|
|
1027
|
-
results: (data || []).map(
|
|
1011
|
+
results: (data || []).map(mapToKnowledgeEntry),
|
|
1028
1012
|
queryTime: Date.now() - startTime,
|
|
1029
1013
|
cached: false
|
|
1030
1014
|
};
|
|
1031
1015
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1016
|
+
return {
|
|
1017
|
+
async searchSimilar(request) {
|
|
1018
|
+
const startTime = Date.now();
|
|
1019
|
+
if (!embedding) {
|
|
1020
|
+
return searchByText(request);
|
|
1021
|
+
}
|
|
1022
|
+
const queryText = `${request.errorMessage}
|
|
1023
|
+
${request.errorStack || ""}`;
|
|
1024
|
+
const queryEmbedding = await embedding.generate(queryText);
|
|
1025
|
+
const { data, error } = await supabase.rpc("search_similar_errors", {
|
|
1026
|
+
query_embedding: queryEmbedding,
|
|
1027
|
+
match_threshold: request.threshold || similarityThreshold,
|
|
1028
|
+
match_count: request.limit || 10,
|
|
1029
|
+
filter_language: request.language || null,
|
|
1030
|
+
filter_framework: request.framework || null
|
|
1031
|
+
});
|
|
1032
|
+
if (error) {
|
|
1033
|
+
console.error("Search error:", error);
|
|
1034
|
+
return { results: [], queryTime: Date.now() - startTime, cached: false };
|
|
1035
|
+
}
|
|
1036
|
+
return {
|
|
1037
|
+
results: (data || []).map(mapToKnowledgeEntry),
|
|
1038
|
+
queryTime: Date.now() - startTime,
|
|
1039
|
+
cached: false
|
|
1040
|
+
};
|
|
1041
|
+
},
|
|
1042
|
+
async uploadResolution(request) {
|
|
1043
|
+
const { errorRecord, resolution, resolutionCode, resolutionSteps } = request;
|
|
1044
|
+
let embeddingData = null;
|
|
1045
|
+
if (embedding) {
|
|
1046
|
+
const embeddingText = `${errorRecord.errorMessage}
|
|
1037
1047
|
${errorRecord.errorStack || ""}`;
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1048
|
+
embeddingData = await embedding.generate(embeddingText);
|
|
1049
|
+
}
|
|
1050
|
+
if (embeddingData) {
|
|
1051
|
+
const duplicateCheck = await checkDuplicateInternal(errorRecord.errorHash, embeddingData);
|
|
1052
|
+
if (duplicateCheck.isDuplicate && duplicateCheck.similarityScore > 0.95) {
|
|
1053
|
+
await supabase.rpc("increment_usage_count", {
|
|
1054
|
+
entry_id: duplicateCheck.existingId
|
|
1055
|
+
});
|
|
1056
|
+
return {
|
|
1057
|
+
success: true,
|
|
1058
|
+
isDuplicate: true,
|
|
1059
|
+
existingId: duplicateCheck.existingId,
|
|
1060
|
+
message: "Similar solution already exists. Usage count incremented."
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
const { data, error } = await supabase.from("knowledge_entries").insert({
|
|
1065
|
+
error_hash: errorRecord.errorHash,
|
|
1066
|
+
error_type: errorRecord.errorType,
|
|
1067
|
+
error_message: errorRecord.errorMessage,
|
|
1068
|
+
error_stack: errorRecord.errorStack,
|
|
1069
|
+
language: errorRecord.language || "other",
|
|
1070
|
+
framework: errorRecord.framework,
|
|
1071
|
+
embedding: embeddingData,
|
|
1072
|
+
resolution_description: resolution,
|
|
1073
|
+
resolution_code: resolutionCode,
|
|
1074
|
+
resolution_steps: resolutionSteps,
|
|
1075
|
+
contributor_id: contributorId
|
|
1076
|
+
}).select("id").single();
|
|
1077
|
+
if (error) {
|
|
1046
1078
|
return {
|
|
1047
|
-
success:
|
|
1048
|
-
isDuplicate:
|
|
1049
|
-
|
|
1050
|
-
message: "Similar solution already exists. Usage count incremented."
|
|
1079
|
+
success: false,
|
|
1080
|
+
isDuplicate: false,
|
|
1081
|
+
message: `Upload failed: ${error.message}`
|
|
1051
1082
|
};
|
|
1052
1083
|
}
|
|
1053
|
-
}
|
|
1054
|
-
const { data, error } = await this.supabase.from("knowledge_entries").insert({
|
|
1055
|
-
error_hash: errorRecord.errorHash,
|
|
1056
|
-
error_type: errorRecord.errorType,
|
|
1057
|
-
error_message: errorRecord.errorMessage,
|
|
1058
|
-
error_stack: errorRecord.errorStack,
|
|
1059
|
-
language: errorRecord.language || "other",
|
|
1060
|
-
framework: errorRecord.framework,
|
|
1061
|
-
embedding,
|
|
1062
|
-
resolution_description: resolution,
|
|
1063
|
-
resolution_code: resolutionCode,
|
|
1064
|
-
resolution_steps: resolutionSteps,
|
|
1065
|
-
contributor_id: this.contributorId
|
|
1066
|
-
}).select("id").single();
|
|
1067
|
-
if (error) {
|
|
1068
1084
|
return {
|
|
1069
|
-
success:
|
|
1085
|
+
success: true,
|
|
1086
|
+
knowledgeId: data.id,
|
|
1070
1087
|
isDuplicate: false,
|
|
1071
|
-
message:
|
|
1072
|
-
};
|
|
1073
|
-
}
|
|
1074
|
-
return {
|
|
1075
|
-
success: true,
|
|
1076
|
-
knowledgeId: data.id,
|
|
1077
|
-
isDuplicate: false,
|
|
1078
|
-
message: "Solution uploaded successfully!"
|
|
1079
|
-
};
|
|
1080
|
-
}
|
|
1081
|
-
async checkDuplicate(errorHash, embedding) {
|
|
1082
|
-
const { data: hashMatch } = await this.supabase.from("knowledge_entries").select("id").eq("error_hash", errorHash).limit(1).single();
|
|
1083
|
-
if (hashMatch) {
|
|
1084
|
-
return {
|
|
1085
|
-
isDuplicate: true,
|
|
1086
|
-
existingId: hashMatch.id,
|
|
1087
|
-
similarityScore: 1
|
|
1088
|
+
message: "Solution uploaded successfully!"
|
|
1088
1089
|
};
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1090
|
+
},
|
|
1091
|
+
async checkDuplicate(errorHash, embeddingData) {
|
|
1092
|
+
return checkDuplicateInternal(errorHash, embeddingData);
|
|
1093
|
+
},
|
|
1094
|
+
async vote(knowledgeId, helpful) {
|
|
1095
|
+
const voteType = helpful ? "up" : "down";
|
|
1096
|
+
const { data, error } = await supabase.rpc("safe_vote", {
|
|
1097
|
+
p_entry_id: knowledgeId,
|
|
1098
|
+
p_user_hash: contributorId,
|
|
1099
|
+
p_vote_type: voteType
|
|
1100
|
+
});
|
|
1101
|
+
if (error) {
|
|
1102
|
+
return { success: false, error: error.message };
|
|
1103
|
+
}
|
|
1104
|
+
const result = data;
|
|
1105
|
+
if (result.success) {
|
|
1106
|
+
await supabase.from("usage_logs").insert({
|
|
1107
|
+
knowledge_id: knowledgeId,
|
|
1108
|
+
action: helpful ? "upvote" : "downvote",
|
|
1109
|
+
user_hash: contributorId
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
return result;
|
|
1113
|
+
},
|
|
1114
|
+
async reportEntry(knowledgeId, reason) {
|
|
1115
|
+
const { data, error } = await supabase.rpc("report_entry", {
|
|
1116
|
+
p_entry_id: knowledgeId,
|
|
1117
|
+
p_user_hash: contributorId,
|
|
1118
|
+
p_reason: reason || null
|
|
1119
|
+
});
|
|
1120
|
+
if (error) {
|
|
1121
|
+
return { success: false };
|
|
1122
|
+
}
|
|
1123
|
+
return data;
|
|
1124
|
+
},
|
|
1125
|
+
async reportHelpful(knowledgeId) {
|
|
1126
|
+
await supabase.rpc("increment_usage_count", {
|
|
1127
|
+
entry_id: knowledgeId
|
|
1128
|
+
});
|
|
1129
|
+
await supabase.from("usage_logs").insert({
|
|
1118
1130
|
knowledge_id: knowledgeId,
|
|
1119
|
-
action:
|
|
1120
|
-
user_hash:
|
|
1131
|
+
action: "apply",
|
|
1132
|
+
user_hash: contributorId
|
|
1121
1133
|
});
|
|
1134
|
+
},
|
|
1135
|
+
async getContributorStats() {
|
|
1136
|
+
const { data } = await supabase.from("knowledge_entries").select("upvotes, usage_count").eq("contributor_id", contributorId);
|
|
1137
|
+
if (!data || data.length === 0) {
|
|
1138
|
+
return { contributionCount: 0, helpedCount: 0, totalUpvotes: 0 };
|
|
1139
|
+
}
|
|
1140
|
+
return {
|
|
1141
|
+
contributionCount: data.length,
|
|
1142
|
+
helpedCount: data.reduce((sum, e) => sum + (e.usage_count || 0), 0),
|
|
1143
|
+
totalUpvotes: data.reduce((sum, e) => sum + (e.upvotes || 0), 0)
|
|
1144
|
+
};
|
|
1145
|
+
},
|
|
1146
|
+
async getEntry(id) {
|
|
1147
|
+
const { data, error } = await supabase.from("knowledge_entries").select("*").eq("id", id).single();
|
|
1148
|
+
if (error || !data) {
|
|
1149
|
+
return null;
|
|
1150
|
+
}
|
|
1151
|
+
return mapToKnowledgeEntry(data);
|
|
1152
|
+
},
|
|
1153
|
+
getContributorId() {
|
|
1154
|
+
return contributorId;
|
|
1155
|
+
},
|
|
1156
|
+
hasEmbeddingService() {
|
|
1157
|
+
return embedding !== null;
|
|
1122
1158
|
}
|
|
1123
|
-
|
|
1124
|
-
}
|
|
1125
|
-
async reportEntry(knowledgeId, reason) {
|
|
1126
|
-
const { data, error } = await this.supabase.rpc("report_entry", {
|
|
1127
|
-
p_entry_id: knowledgeId,
|
|
1128
|
-
p_user_hash: this.contributorId,
|
|
1129
|
-
p_reason: reason || null
|
|
1130
|
-
});
|
|
1131
|
-
if (error) {
|
|
1132
|
-
return { success: false };
|
|
1133
|
-
}
|
|
1134
|
-
return data;
|
|
1135
|
-
}
|
|
1136
|
-
async reportHelpful(knowledgeId) {
|
|
1137
|
-
await this.supabase.rpc("increment_usage_count", {
|
|
1138
|
-
entry_id: knowledgeId
|
|
1139
|
-
});
|
|
1140
|
-
await this.supabase.from("usage_logs").insert({
|
|
1141
|
-
knowledge_id: knowledgeId,
|
|
1142
|
-
action: "apply",
|
|
1143
|
-
user_hash: this.contributorId
|
|
1144
|
-
});
|
|
1145
|
-
}
|
|
1146
|
-
async getContributorStats() {
|
|
1147
|
-
const { data } = await this.supabase.from("knowledge_entries").select("upvotes, usage_count").eq("contributor_id", this.contributorId);
|
|
1148
|
-
if (!data || data.length === 0) {
|
|
1149
|
-
return { contributionCount: 0, helpedCount: 0, totalUpvotes: 0 };
|
|
1150
|
-
}
|
|
1151
|
-
return {
|
|
1152
|
-
contributionCount: data.length,
|
|
1153
|
-
helpedCount: data.reduce((sum, e) => sum + (e.usage_count || 0), 0),
|
|
1154
|
-
totalUpvotes: data.reduce((sum, e) => sum + (e.upvotes || 0), 0)
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
async getEntry(id) {
|
|
1158
|
-
const { data, error } = await this.supabase.from("knowledge_entries").select("*").eq("id", id).single();
|
|
1159
|
-
if (error || !data) {
|
|
1160
|
-
return null;
|
|
1161
|
-
}
|
|
1162
|
-
return this.mapToKnowledgeEntry(data);
|
|
1163
|
-
}
|
|
1164
|
-
mapToKnowledgeEntry(row) {
|
|
1165
|
-
return {
|
|
1166
|
-
id: row.id,
|
|
1167
|
-
errorHash: row.error_hash,
|
|
1168
|
-
errorType: row.error_type,
|
|
1169
|
-
errorMessage: row.error_message,
|
|
1170
|
-
errorStack: row.error_stack || undefined,
|
|
1171
|
-
language: row.language,
|
|
1172
|
-
framework: row.framework || undefined,
|
|
1173
|
-
dependencies: row.dependencies || undefined,
|
|
1174
|
-
resolutionDescription: row.resolution_description,
|
|
1175
|
-
resolutionCode: row.resolution_code || undefined,
|
|
1176
|
-
resolutionSteps: row.resolution_steps || undefined,
|
|
1177
|
-
contributorId: row.contributor_id,
|
|
1178
|
-
upvotes: row.upvotes || 0,
|
|
1179
|
-
downvotes: row.downvotes || 0,
|
|
1180
|
-
usageCount: row.usage_count || 0,
|
|
1181
|
-
createdAt: row.created_at,
|
|
1182
|
-
updatedAt: row.updated_at,
|
|
1183
|
-
isVerified: row.is_verified || false,
|
|
1184
|
-
similarity: row.similarity || undefined
|
|
1185
|
-
};
|
|
1186
|
-
}
|
|
1187
|
-
getContributorId() {
|
|
1188
|
-
return this.contributorId;
|
|
1189
|
-
}
|
|
1190
|
-
hasEmbeddingService() {
|
|
1191
|
-
return this.embedding !== null;
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
async function createCloudClient(config) {
|
|
1195
|
-
return CloudClient.create(config);
|
|
1159
|
+
};
|
|
1196
1160
|
}
|
|
1161
|
+
var CloudClient = {
|
|
1162
|
+
create: createCloudClient
|
|
1163
|
+
};
|
|
1197
1164
|
|
|
1198
1165
|
// src/plugin/tools.ts
|
|
1199
1166
|
import { tool } from "@opencode-ai/plugin";
|
|
@@ -1416,7 +1383,7 @@ var FixHivePlugin = async (ctx) => {
|
|
|
1416
1383
|
let cloudClient = null;
|
|
1417
1384
|
if (config.supabaseUrl && config.supabaseAnonKey) {
|
|
1418
1385
|
try {
|
|
1419
|
-
cloudClient = await
|
|
1386
|
+
cloudClient = await createCloudClient({
|
|
1420
1387
|
supabaseUrl: config.supabaseUrl,
|
|
1421
1388
|
supabaseAnonKey: config.supabaseAnonKey,
|
|
1422
1389
|
openaiApiKey: config.openaiApiKey,
|