@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.
@@ -14,75 +14,31 @@ export interface CloudClientConfig {
14
14
  similarityThreshold?: number;
15
15
  }
16
16
  /**
17
- * Cloud Client Class
18
- * Manages communication with Supabase cloud database
17
+ * CloudClient interface - defines all public methods
19
18
  */
20
- export declare class CloudClient {
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 cloud client with config (async for Bun compatibility)
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;AAe3B;;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;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,mBAAmB,CAAS;IAEpC,OAAO;IAYP;;OAEG;WACU,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;IAqBpE;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAiCpE;;OAEG;YACW,YAAY;IAgC1B;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAgEvE;;OAEG;IACG,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,oBAAoB,CAAC;IAoChC;;OAEG;IACG,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;IA2BhG;;OAEG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IActF;;OAEG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvD;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAiBtD;;OAEG;IACG,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAc/D;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAwB3B;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,mBAAmB,IAAI,OAAO;CAG/B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,WAAW,CAAC,CAEtB"}
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
- var createClient;
953
- async function getCreateClient() {
954
- if (!createClient) {
955
- const supabase = await import("@supabase/supabase-js");
956
- createClient = supabase.createClient;
957
- }
958
- return createClient;
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
- class CloudClient {
962
- supabase;
963
- embedding;
964
- contributorId;
965
- similarityThreshold;
966
- constructor(supabase, embedding, contributorId, similarityThreshold) {
967
- this.supabase = supabase;
968
- this.embedding = embedding;
969
- this.contributorId = contributorId;
970
- this.similarityThreshold = similarityThreshold;
971
- }
972
- static async create(config) {
973
- const createClientFn = await getCreateClient();
974
- const supabase = createClientFn(config.supabaseUrl, config.supabaseAnonKey);
975
- let embedding = null;
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
- async searchSimilar(request) {
988
- const startTime = Date.now();
989
- if (!this.embedding) {
990
- return this.searchByText(request);
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 queryText = `${request.errorMessage}
993
- ${request.errorStack || ""}`;
994
- const embedding = await this.embedding.generate(queryText);
995
- const { data, error } = await this.supabase.rpc("search_similar_errors", {
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
- console.error("Search error:", error);
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
- results: (data || []).map(this.mapToKnowledgeEntry),
1008
- queryTime: Date.now() - startTime,
1009
- cached: false
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 = this.supabase.from("knowledge_entries").select("*").ilike("error_message", `%${request.errorMessage.substring(0, 100)}%`).order("upvotes", { ascending: false }).limit(request.limit || 10);
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(this.mapToKnowledgeEntry),
1011
+ results: (data || []).map(mapToKnowledgeEntry),
1028
1012
  queryTime: Date.now() - startTime,
1029
1013
  cached: false
1030
1014
  };
1031
1015
  }
1032
- async uploadResolution(request) {
1033
- const { errorRecord, resolution, resolutionCode, resolutionSteps } = request;
1034
- let embedding = null;
1035
- if (this.embedding) {
1036
- const embeddingText = `${errorRecord.errorMessage}
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
- embedding = await this.embedding.generate(embeddingText);
1039
- }
1040
- if (embedding) {
1041
- const duplicateCheck = await this.checkDuplicate(errorRecord.errorHash, embedding);
1042
- if (duplicateCheck.isDuplicate && duplicateCheck.similarityScore > 0.95) {
1043
- await this.supabase.rpc("increment_usage_count", {
1044
- entry_id: duplicateCheck.existingId
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: true,
1048
- isDuplicate: true,
1049
- existingId: duplicateCheck.existingId,
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: false,
1085
+ success: true,
1086
+ knowledgeId: data.id,
1070
1087
  isDuplicate: false,
1071
- message: `Upload failed: ${error.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
- const { data, error } = await this.supabase.rpc("check_duplicate_entry", {
1091
- new_hash: errorHash,
1092
- new_embedding: embedding,
1093
- similarity_threshold: 0.95
1094
- });
1095
- if (error || !data || data.length === 0) {
1096
- return { isDuplicate: false, similarityScore: 0 };
1097
- }
1098
- const result = data[0];
1099
- return {
1100
- isDuplicate: result.is_duplicate,
1101
- existingId: result.existing_id,
1102
- similarityScore: result.similarity_score
1103
- };
1104
- }
1105
- async vote(knowledgeId, helpful) {
1106
- const voteType = helpful ? "up" : "down";
1107
- const { data, error } = await this.supabase.rpc("safe_vote", {
1108
- p_entry_id: knowledgeId,
1109
- p_user_hash: this.contributorId,
1110
- p_vote_type: voteType
1111
- });
1112
- if (error) {
1113
- return { success: false, error: error.message };
1114
- }
1115
- const result = data;
1116
- if (result.success) {
1117
- await this.supabase.from("usage_logs").insert({
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: helpful ? "upvote" : "downvote",
1120
- user_hash: this.contributorId
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
- return result;
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 CloudClient.create({
1386
+ cloudClient = await createCloudClient({
1420
1387
  supabaseUrl: config.supabaseUrl,
1421
1388
  supabaseAnonKey: config.supabaseAnonKey,
1422
1389
  openaiApiKey: config.openaiApiKey,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@the-magic-tower/fixhive-opencode-plugin",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Community-based error knowledge sharing for OpenCode",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",