opencode-mem 2.6.1 → 2.7.0

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.
Files changed (41) hide show
  1. package/dist/index.d.ts.map +1 -1
  2. package/dist/index.js +25 -9
  3. package/dist/services/ai/providers/openai-chat-completion.d.ts.map +1 -1
  4. package/dist/services/ai/providers/openai-chat-completion.js +0 -4
  5. package/dist/services/ai/providers/openai-responses.d.ts.map +1 -1
  6. package/dist/services/ai/providers/openai-responses.js +0 -10
  7. package/dist/services/api-handlers.d.ts.map +1 -1
  8. package/dist/services/api-handlers.js +2 -2
  9. package/dist/services/auto-capture.d.ts.map +1 -1
  10. package/dist/services/auto-capture.js +10 -20
  11. package/dist/services/cleanup-service.d.ts.map +1 -1
  12. package/dist/services/cleanup-service.js +0 -13
  13. package/dist/services/client.d.ts.map +1 -1
  14. package/dist/services/client.js +1 -4
  15. package/dist/services/deduplication-service.d.ts.map +1 -1
  16. package/dist/services/deduplication-service.js +4 -9
  17. package/dist/services/embedding.d.ts +3 -0
  18. package/dist/services/embedding.d.ts.map +1 -1
  19. package/dist/services/embedding.js +26 -6
  20. package/dist/services/logger.d.ts.map +1 -1
  21. package/dist/services/logger.js +17 -1
  22. package/dist/services/migration-service.d.ts.map +1 -1
  23. package/dist/services/migration-service.js +1 -9
  24. package/dist/services/sqlite/connection-manager.d.ts +1 -0
  25. package/dist/services/sqlite/connection-manager.d.ts.map +1 -1
  26. package/dist/services/sqlite/connection-manager.js +12 -6
  27. package/dist/services/sqlite/shard-manager.d.ts.map +1 -1
  28. package/dist/services/sqlite/shard-manager.js +2 -5
  29. package/dist/services/sqlite/vector-search.d.ts +2 -2
  30. package/dist/services/sqlite/vector-search.d.ts.map +1 -1
  31. package/dist/services/sqlite/vector-search.js +27 -14
  32. package/dist/services/user-memory-learning.d.ts.map +1 -1
  33. package/dist/services/user-memory-learning.js +6 -20
  34. package/dist/services/user-prompt/user-prompt-manager.d.ts +1 -0
  35. package/dist/services/user-prompt/user-prompt-manager.d.ts.map +1 -1
  36. package/dist/services/user-prompt/user-prompt-manager.js +6 -0
  37. package/dist/services/web-server.d.ts.map +1 -1
  38. package/dist/services/web-server.js +0 -1
  39. package/dist/web/app.js +1 -1
  40. package/dist/web/index.html +12 -1
  41. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAkB/D,eAAO,MAAM,iBAAiB,EAAE,MAiU/B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAkB/D,eAAO,MAAM,iBAAiB,EAAE,MAiV/B,CAAC"}
package/dist/index.js CHANGED
@@ -14,15 +14,14 @@ export const OpenCodeMemPlugin = async (ctx) => {
14
14
  const { directory } = ctx;
15
15
  const tags = getTags(directory);
16
16
  let webServer = null;
17
+ let idleTimeout = null;
17
18
  if (!isConfigured()) {
18
- log("Plugin disabled - memory system not configured");
19
19
  }
20
20
  const GLOBAL_PLUGIN_WARMUP_KEY = Symbol.for("opencode-mem.plugin.warmedup");
21
21
  if (!globalThis[GLOBAL_PLUGIN_WARMUP_KEY] && isConfigured()) {
22
22
  try {
23
23
  await memoryClient.warmup();
24
24
  globalThis[GLOBAL_PLUGIN_WARMUP_KEY] = true;
25
- log("Plugin warmup completed");
26
25
  }
27
26
  catch (error) {
28
27
  log("Plugin warmup failed", { error: String(error) });
@@ -219,7 +218,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
219
218
  return JSON.stringify({ success: false, error: "Private content blocked" });
220
219
  const tagInfo = tags.project;
221
220
  const parsedTags = args.tags
222
- ? args.tags.split(",").map((t) => t.trim())
221
+ ? args.tags.split(",").map((t) => t.trim().toLowerCase())
223
222
  : undefined;
224
223
  const result = await memoryClient.addMemory(sanitizedContent, tagInfo.tag, {
225
224
  type: args.type,
@@ -292,12 +291,29 @@ export const OpenCodeMemPlugin = async (ctx) => {
292
291
  if (!isConfigured())
293
292
  return;
294
293
  const sessionID = event.properties?.sessionID;
295
- if (sessionID)
296
- await performAutoCapture(ctx, sessionID, directory);
297
- await performUserProfileLearning(ctx, directory);
298
- const { cleanupService } = await import("./services/cleanup-service.js");
299
- if (await cleanupService.shouldRunCleanup())
300
- await cleanupService.runCleanup();
294
+ if (!sessionID)
295
+ return;
296
+ if (idleTimeout)
297
+ clearTimeout(idleTimeout);
298
+ idleTimeout = setTimeout(async () => {
299
+ try {
300
+ await performAutoCapture(ctx, sessionID, directory);
301
+ if (webServer?.isServerOwner()) {
302
+ await performUserProfileLearning(ctx, directory);
303
+ const { cleanupService } = await import("./services/cleanup-service.js");
304
+ if (await cleanupService.shouldRunCleanup())
305
+ await cleanupService.runCleanup();
306
+ const { connectionManager } = await import("./services/sqlite/connection-manager.js");
307
+ connectionManager.checkpointAll();
308
+ }
309
+ }
310
+ catch (error) {
311
+ log("Idle processing error", { error: String(error) });
312
+ }
313
+ finally {
314
+ idleTimeout = null;
315
+ }
316
+ }, 10000);
301
317
  }
302
318
  },
303
319
  };
@@ -1 +1 @@
1
- {"version":3,"file":"openai-chat-completion.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-chat-completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAqBlE,qBAAa,4BAA6B,SAAQ,cAAc;IAC9D,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAI1B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,iCAAiC;IAwCnC,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;CAyO3B"}
1
+ {"version":3,"file":"openai-chat-completion.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-chat-completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAqBlE,qBAAa,4BAA6B,SAAQ,cAAc;IAC9D,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAI1B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,iCAAiC;IAoCnC,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;CAyO3B"}
@@ -51,10 +51,6 @@ export class OpenAIChatCompletionProvider extends BaseAIProvider {
51
51
  i = j;
52
52
  }
53
53
  else {
54
- log("Skipping incomplete tool call sequence", {
55
- assistantMsgIndex: i,
56
- missingToolCallIds: Array.from(toolCallIds),
57
- });
58
54
  break;
59
55
  }
60
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openai-responses.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-responses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAsBvF,qBAAa,uBAAwB,SAAQ,cAAc;IACzD,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAyH1B,OAAO,CAAC,eAAe;IAsCvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,gBAAgB;CAsBzB"}
1
+ {"version":3,"file":"openai-responses.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-responses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAsBvF,qBAAa,uBAAwB,SAAQ,cAAc;IACzD,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAoH1B,OAAO,CAAC,eAAe;IA+BvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,gBAAgB;CAsBzB"}
@@ -89,10 +89,6 @@ export class OpenAIResponsesProvider extends BaseAIProvider {
89
89
  iterations,
90
90
  };
91
91
  }
92
- log("No tool call found, retrying", {
93
- iteration: iterations,
94
- expectedTool: toolSchema.function.name,
95
- });
96
92
  currentPrompt = this.buildRetryPrompt(data);
97
93
  }
98
94
  catch (error) {
@@ -119,7 +115,6 @@ export class OpenAIResponsesProvider extends BaseAIProvider {
119
115
  }
120
116
  extractToolCall(data, expectedToolName) {
121
117
  if (!data.output || !Array.isArray(data.output)) {
122
- log("Extract tool call: no output array", { hasOutput: !!data.output });
123
118
  return null;
124
119
  }
125
120
  for (const item of data.output) {
@@ -146,11 +141,6 @@ export class OpenAIResponsesProvider extends BaseAIProvider {
146
141
  }
147
142
  }
148
143
  }
149
- log("No matching function call found", {
150
- expectedTool: expectedToolName,
151
- foundTypes: data.output.map((item) => item.type),
152
- foundNames: data.output.map((item) => item.name).filter(Boolean),
153
- });
154
144
  return null;
155
145
  }
156
146
  buildRetryPrompt(data) {
@@ -1 +1 @@
1
- {"version":3,"file":"api-handlers.d.ts","sourceRoot":"","sources":["../../src/services/api-handlers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api-handlers.d.ts","sourceRoot":"","sources":["../../src/services/api-handlers.ts"],"names":[],"mappings":"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"}
@@ -228,7 +228,7 @@ export async function handleAddMemory(data) {
228
228
  return { success: false, error: "content and containerTag are required" };
229
229
  }
230
230
  await embeddingService.warmup();
231
- const tags = data.tags || [];
231
+ const tags = (data.tags || []).map((t) => t.trim().toLowerCase());
232
232
  const embeddingInput = tags.length > 0 ? `${data.content}\nTags: ${tags.join(", ")}` : data.content;
233
233
  const vector = await embeddingService.embedWithTimeout(embeddingInput);
234
234
  let tagsVector = undefined;
@@ -822,7 +822,7 @@ export async function handleRunTagMigration() {
822
822
  let currentTags = m.tags
823
823
  ? m.tags
824
824
  .split(",")
825
- .map((t) => t.trim())
825
+ .map((t) => t.trim().toLowerCase())
826
826
  .filter((t) => t)
827
827
  : [];
828
828
  if (currentTags.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"auto-capture.d.ts","sourceRoot":"","sources":["../../src/services/auto-capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAcvD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAqGf"}
1
+ {"version":3,"file":"auto-capture.d.ts","sourceRoot":"","sources":["../../src/services/auto-capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAgBvD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA2Ff"}
@@ -4,12 +4,19 @@ import { log } from "./logger.js";
4
4
  import { CONFIG } from "../config.js";
5
5
  import { userPromptManager } from "./user-prompt/user-prompt-manager.js";
6
6
  const MAX_TOOL_INPUT_LENGTH = 100;
7
+ let isCaptureRunning = false;
7
8
  export async function performAutoCapture(ctx, sessionID, directory) {
9
+ if (isCaptureRunning)
10
+ return;
11
+ isCaptureRunning = true;
8
12
  try {
9
13
  const prompt = userPromptManager.getLastUncapturedPrompt(sessionID);
10
14
  if (!prompt) {
11
15
  return;
12
16
  }
17
+ if (!userPromptManager.claimPrompt(prompt.id)) {
18
+ return;
19
+ }
13
20
  if (!ctx.client) {
14
21
  throw new Error("Client not available");
15
22
  }
@@ -17,13 +24,11 @@ export async function performAutoCapture(ctx, sessionID, directory) {
17
24
  path: { id: sessionID },
18
25
  });
19
26
  if (!response.data) {
20
- log("Auto-capture: no messages in session", { sessionID });
21
27
  return;
22
28
  }
23
29
  const messages = response.data;
24
30
  const promptIndex = messages.findIndex((m) => m.info?.id === prompt.messageId);
25
31
  if (promptIndex === -1) {
26
- log("Auto-capture: prompt message not found", { sessionID, messageId: prompt.messageId });
27
32
  return;
28
33
  }
29
34
  const aiMessages = messages.slice(promptIndex + 1);
@@ -39,7 +44,6 @@ export async function performAutoCapture(ctx, sessionID, directory) {
39
44
  const context = buildMarkdownContext(prompt.content, textResponses, toolCalls, latestMemory);
40
45
  const summaryResult = await generateSummary(context, sessionID, prompt.content);
41
46
  if (!summaryResult || summaryResult.type === "skip") {
42
- log("Auto-capture: skipped non-technical conversation", { sessionID });
43
47
  userPromptManager.deletePrompt(prompt.id);
44
48
  return;
45
49
  }
@@ -74,20 +78,8 @@ export async function performAutoCapture(ctx, sessionID, directory) {
74
78
  }
75
79
  }
76
80
  }
77
- catch (error) {
78
- log("Auto-capture error", { sessionID, error: String(error) });
79
- if (CONFIG.showErrorToasts) {
80
- await ctx.client?.tui
81
- .showToast({
82
- body: {
83
- title: "Auto-Capture Failed",
84
- message: String(error),
85
- variant: "error",
86
- duration: 5000,
87
- },
88
- })
89
- .catch(() => { });
90
- }
81
+ finally {
82
+ isCaptureRunning = false;
91
83
  }
92
84
  }
93
85
  function extractAIContent(messages) {
@@ -133,8 +125,6 @@ function extractAIContent(messages) {
133
125
  async function getLatestProjectMemory(containerTag) {
134
126
  try {
135
127
  const result = await memoryClient.listMemories(containerTag, 1);
136
- log("Auto-capture: latest memory list result", { result });
137
- log("Auto-capture: container tag", { containerTag });
138
128
  if (!result.success || result.memories.length === 0) {
139
129
  return null;
140
130
  }
@@ -258,6 +248,6 @@ Analyze this conversation. If it contains technical work (code, bugs, features,
258
248
  return {
259
249
  summary: result.data.summary,
260
250
  type: result.data.type,
261
- tags: result.data.tags || [],
251
+ tags: (result.data.tags || []).map((t) => t.toLowerCase().trim()),
262
252
  };
263
253
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cleanup-service.d.ts","sourceRoot":"","sources":["../../src/services/cleanup-service.ts"],"names":[],"mappings":"AAOA,UAAU,aAAa;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,SAAS,CAAkB;IAE7B,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAcpC,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC;IAqG1C,SAAS;;;;;;CAQV;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
1
+ {"version":3,"file":"cleanup-service.d.ts","sourceRoot":"","sources":["../../src/services/cleanup-service.ts"],"names":[],"mappings":"AAOA,UAAU,aAAa;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,SAAS,CAAkB;IAE7B,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAcpC,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC;IAsF1C,SAAS;;;;;;CAQV;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
@@ -26,7 +26,6 @@ export class CleanupService {
26
26
  this.isRunning = true;
27
27
  this.lastCleanupTime = Date.now();
28
28
  try {
29
- log("Cleanup: starting", { retentionDays: CONFIG.autoCleanupRetentionDays });
30
29
  const cutoffTime = Date.now() - CONFIG.autoCleanupRetentionDays * 24 * 60 * 60 * 1000;
31
30
  const userShards = shardManager.getAllShards("user", "");
32
31
  const projectShards = shardManager.getAllShards("project", "");
@@ -60,9 +59,6 @@ export class CleanupService {
60
59
  continue;
61
60
  }
62
61
  if (protectedMemoryIds.has(memory.id)) {
63
- if (linkedMemoryIds.has(memory.id)) {
64
- log("Cleanup: skipped linked memory", { memoryId: memory.id });
65
- }
66
62
  continue;
67
63
  }
68
64
  vectorSearch.deleteVector(db, memory.id);
@@ -81,15 +77,6 @@ export class CleanupService {
81
77
  }
82
78
  }
83
79
  const promptsDeleted = promptCleanupResult.deleted - linkedMemoryIds.size;
84
- log("Cleanup: completed", {
85
- totalDeleted,
86
- userDeleted,
87
- projectDeleted,
88
- promptsDeleted,
89
- linkedMemoriesProtected: linkedMemoryIds.size,
90
- pinnedMemoriesSkipped: pinnedSkipped,
91
- cutoffTime: new Date(cutoffTime).toISOString(),
92
- });
93
80
  return {
94
81
  deletedCount: totalDeleted,
95
82
  userCount: userDeleted,
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/services/client.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA4CpD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,aAAa,CAAkB;;YAIzB,UAAU;IAiBlB,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,SAAS,IAAI;QACX,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,KAAK,EAAE,OAAO,CAAC;KAChB;IAQD,KAAK,IAAI,IAAI;IAIP,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;;;;;;;;;;;;;IA6BlD,SAAS,CACb,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,UAAU,CAAC;QAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,KAAK,CAAC;QACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB;;;;;;;;;IA+DG,YAAY,CAAC,QAAQ,EAAE,MAAM;;;;;;;IA2B7B,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,SAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuDpD;AAED,eAAO,MAAM,YAAY,mBAA0B,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/services/client.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA4CpD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,aAAa,CAAkB;;YAIzB,UAAU;IAiBlB,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,SAAS,IAAI;QACX,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,KAAK,EAAE,OAAO,CAAC;KAChB;IAQD,KAAK,IAAI,IAAI;IAIP,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;;;;;;;;;;;;;IA6BlD,SAAS,CACb,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,UAAU,CAAC;QAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,KAAK,CAAC;QACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB;;;;;;;;;IA+DG,YAAY,CAAC,QAAQ,EAAE,MAAM;;;;;;;IA0B7B,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,SAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDpD;AAED,eAAO,MAAM,YAAY,mBAA0B,CAAC"}
@@ -84,10 +84,9 @@ export class LocalMemoryClient {
84
84
  const { scope, hash } = extractScopeFromContainerTag(containerTag);
85
85
  const shards = shardManager.getAllShards(scope, hash);
86
86
  if (shards.length === 0) {
87
- log("searchMemories: no shards found", { containerTag });
88
87
  return { success: true, results: [], total: 0, timing: 0 };
89
88
  }
90
- const results = await vectorSearch.searchAcrossShards(shards, queryVector, containerTag, CONFIG.maxMemories, CONFIG.similarityThreshold);
89
+ const results = await vectorSearch.searchAcrossShards(shards, queryVector, containerTag, CONFIG.maxMemories, CONFIG.similarityThreshold, query);
91
90
  return { success: true, results, total: results.length, timing: 0 };
92
91
  }
93
92
  catch (error) {
@@ -153,7 +152,6 @@ export class LocalMemoryClient {
153
152
  return { success: true };
154
153
  }
155
154
  }
156
- log("deleteMemory: not found", { memoryId });
157
155
  return { success: false, error: "Memory not found" };
158
156
  }
159
157
  catch (error) {
@@ -168,7 +166,6 @@ export class LocalMemoryClient {
168
166
  const { scope, hash } = extractScopeFromContainerTag(containerTag);
169
167
  const shards = shardManager.getAllShards(scope, hash);
170
168
  if (shards.length === 0) {
171
- log("listMemories: no shards found", { containerTag });
172
169
  return {
173
170
  success: true,
174
171
  memories: [],
@@ -1 +1 @@
1
- {"version":3,"file":"deduplication-service.d.ts","sourceRoot":"","sources":["../../src/services/deduplication-service.ts"],"names":[],"mappings":"AAMA,UAAU,cAAc;IACtB,cAAc,EAAE;QACd,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,UAAU,EAAE,KAAK,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,UAAU,mBAAmB;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mBAAmB,EAAE,cAAc,EAAE,CAAC;CACvC;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,SAAS,CAAkB;IAE7B,yBAAyB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IA+G/D,OAAO,CAAC,gBAAgB;IAoBxB,SAAS;;;;;CAOV;AAED,eAAO,MAAM,oBAAoB,sBAA6B,CAAC"}
1
+ {"version":3,"file":"deduplication-service.d.ts","sourceRoot":"","sources":["../../src/services/deduplication-service.ts"],"names":[],"mappings":"AAMA,UAAU,cAAc;IACtB,cAAc,EAAE;QACd,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,UAAU,EAAE,KAAK,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,UAAU,mBAAmB;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mBAAmB,EAAE,cAAc,EAAE,CAAC;CACvC;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,SAAS,CAAkB;IAE7B,yBAAyB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAwG/D,OAAO,CAAC,gBAAgB;IAoBxB,SAAS;;;;;CAOV;AAED,eAAO,MAAM,oBAAoB,sBAA6B,CAAC"}
@@ -14,9 +14,6 @@ export class DeduplicationService {
14
14
  }
15
15
  this.isRunning = true;
16
16
  try {
17
- log("Deduplication: starting", {
18
- threshold: CONFIG.deduplicationSimilarityThreshold,
19
- });
20
17
  const userShards = shardManager.getAllShards("user", "");
21
18
  const projectShards = shardManager.getAllShards("project", "");
22
19
  const allShards = [...userShards, ...projectShards];
@@ -53,9 +50,10 @@ export class DeduplicationService {
53
50
  }
54
51
  }
55
52
  const uniqueMemories = Array.from(contentMap.values()).map((arr) => arr[0]);
53
+ const processedIds = new Set();
56
54
  for (let i = 0; i < uniqueMemories.length; i++) {
57
55
  const mem1 = uniqueMemories[i];
58
- if (!mem1.vector)
56
+ if (!mem1.vector || processedIds.has(mem1.id))
59
57
  continue;
60
58
  const vector1 = new Float32Array(new Uint8Array(mem1.vector).buffer);
61
59
  const similarGroup = {
@@ -69,7 +67,7 @@ export class DeduplicationService {
69
67
  };
70
68
  for (let j = i + 1; j < uniqueMemories.length; j++) {
71
69
  const mem2 = uniqueMemories[j];
72
- if (!mem2.vector)
70
+ if (!mem2.vector || processedIds.has(mem2.id))
73
71
  continue;
74
72
  if (mem1.container_tag !== mem2.container_tag)
75
73
  continue;
@@ -81,6 +79,7 @@ export class DeduplicationService {
81
79
  content: mem2.content,
82
80
  similarity,
83
81
  });
82
+ processedIds.add(mem2.id);
84
83
  }
85
84
  }
86
85
  if (similarGroup.duplicates.length > 0) {
@@ -88,10 +87,6 @@ export class DeduplicationService {
88
87
  }
89
88
  }
90
89
  }
91
- log("Deduplication: completed", {
92
- exactDeleted,
93
- nearDuplicateGroupsFound: nearDuplicateGroups.length,
94
- });
95
90
  return {
96
91
  exactDuplicatesDeleted: exactDeleted,
97
92
  nearDuplicateGroups,
@@ -2,11 +2,14 @@ export declare class EmbeddingService {
2
2
  private pipe;
3
3
  private initPromise;
4
4
  isWarmedUp: boolean;
5
+ private cache;
6
+ private cachedModelName;
5
7
  static getInstance(): EmbeddingService;
6
8
  warmup(progressCallback?: (progress: any) => void): Promise<void>;
7
9
  private initializeModel;
8
10
  embed(text: string): Promise<Float32Array>;
9
11
  embedWithTimeout(text: string): Promise<Float32Array>;
12
+ clearCache(): void;
10
13
  }
11
14
  export declare const embeddingService: EmbeddingService;
12
15
  //# sourceMappingURL=embedding.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../src/services/embedding.ts"],"names":[],"mappings":"AAmBA,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,WAAW,CAA8B;IAC1C,UAAU,EAAE,OAAO,CAAS;IAEnC,MAAM,CAAC,WAAW,IAAI,gBAAgB;IAOhC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAQzD,eAAe;IAuBvB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAkC1C,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CAG5D;AAED,eAAO,MAAM,gBAAgB,kBAAiC,CAAC"}
1
+ {"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../src/services/embedding.ts"],"names":[],"mappings":"AAoBA,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,WAAW,CAA8B;IAC1C,UAAU,EAAE,OAAO,CAAS;IACnC,OAAO,CAAC,KAAK,CAAwC;IACrD,OAAO,CAAC,eAAe,CAAuB;IAE9C,MAAM,CAAC,WAAW,IAAI,gBAAgB;IAOhC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAOzD,eAAe;IAiBvB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAmD1C,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAI3D,UAAU,IAAI,IAAI;CAGnB;AAED,eAAO,MAAM,gBAAgB,kBAAiC,CAAC"}
@@ -7,6 +7,7 @@ env.allowRemoteModels = true;
7
7
  env.cacheDir = join(CONFIG.storagePath, ".cache");
8
8
  const TIMEOUT_MS = 30000;
9
9
  const GLOBAL_EMBEDDING_KEY = Symbol.for("opencode-mem.embedding.instance");
10
+ const MAX_CACHE_SIZE = 100;
10
11
  function withTimeout(promise, ms) {
11
12
  return Promise.race([
12
13
  promise,
@@ -17,6 +18,8 @@ export class EmbeddingService {
17
18
  pipe = null;
18
19
  initPromise = null;
19
20
  isWarmedUp = false;
21
+ cache = new Map();
22
+ cachedModelName = null;
20
23
  static getInstance() {
21
24
  if (!globalThis[GLOBAL_EMBEDDING_KEY]) {
22
25
  globalThis[GLOBAL_EMBEDDING_KEY] = new EmbeddingService();
@@ -34,16 +37,13 @@ export class EmbeddingService {
34
37
  async initializeModel(progressCallback) {
35
38
  try {
36
39
  if (CONFIG.embeddingApiUrl && CONFIG.embeddingApiKey) {
37
- log("Using OpenAI-compatible API for embeddings");
38
40
  this.isWarmedUp = true;
39
41
  return;
40
42
  }
41
- log("Downloading embedding model", { model: CONFIG.embeddingModel });
42
43
  this.pipe = await pipeline("feature-extraction", CONFIG.embeddingModel, {
43
44
  progress_callback: progressCallback,
44
45
  });
45
46
  this.isWarmedUp = true;
46
- log("Embedding model ready");
47
47
  }
48
48
  catch (error) {
49
49
  this.initPromise = null;
@@ -52,12 +52,20 @@ export class EmbeddingService {
52
52
  }
53
53
  }
54
54
  async embed(text) {
55
+ if (this.cachedModelName !== CONFIG.embeddingModel) {
56
+ this.clearCache();
57
+ this.cachedModelName = CONFIG.embeddingModel;
58
+ }
59
+ const cached = this.cache.get(text);
60
+ if (cached)
61
+ return cached;
55
62
  if (!this.isWarmedUp && !this.initPromise) {
56
63
  await this.warmup();
57
64
  }
58
65
  if (this.initPromise) {
59
66
  await this.initPromise;
60
67
  }
68
+ let result;
61
69
  if (CONFIG.embeddingApiUrl && CONFIG.embeddingApiKey) {
62
70
  const response = await fetch(`${CONFIG.embeddingApiUrl}/embeddings`, {
63
71
  method: "POST",
@@ -74,13 +82,25 @@ export class EmbeddingService {
74
82
  throw new Error(`API embedding failed: ${response.statusText}`);
75
83
  }
76
84
  const data = await response.json();
77
- return new Float32Array(data.data[0].embedding);
85
+ result = new Float32Array(data.data[0].embedding);
86
+ }
87
+ else {
88
+ const output = await this.pipe(text, { pooling: "mean", normalize: true });
89
+ result = new Float32Array(output.data);
78
90
  }
79
- const output = await this.pipe(text, { pooling: "mean", normalize: true });
80
- return new Float32Array(output.data);
91
+ if (this.cache.size >= MAX_CACHE_SIZE) {
92
+ const firstKey = this.cache.keys().next().value;
93
+ if (firstKey !== undefined)
94
+ this.cache.delete(firstKey);
95
+ }
96
+ this.cache.set(text, result);
97
+ return result;
81
98
  }
82
99
  async embedWithTimeout(text) {
83
100
  return withTimeout(this.embed(text), TIMEOUT_MS);
84
101
  }
102
+ clearCache() {
103
+ this.cache.clear();
104
+ }
85
105
  }
86
106
  export const embeddingService = EmbeddingService.getInstance();
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/services/logger.ts"],"names":[],"mappings":"AAoBA,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,QAOlD"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/services/logger.ts"],"names":[],"mappings":"AA0CA,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,QAOlD"}
@@ -1,15 +1,31 @@
1
- import { appendFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
1
+ import { appendFileSync, writeFileSync, existsSync, mkdirSync, statSync, renameSync, unlinkSync, } from "fs";
2
2
  import { homedir } from "os";
3
3
  import { join } from "path";
4
4
  const LOG_DIR = join(homedir(), ".opencode-mem");
5
5
  const LOG_FILE = join(LOG_DIR, "opencode-mem.log");
6
+ const MAX_LOG_SIZE = 5 * 1024 * 1024;
6
7
  const GLOBAL_LOGGER_KEY = Symbol.for("opencode-mem.logger.initialized");
8
+ function rotateLog() {
9
+ try {
10
+ if (!existsSync(LOG_FILE))
11
+ return;
12
+ const stats = statSync(LOG_FILE);
13
+ if (stats.size < MAX_LOG_SIZE)
14
+ return;
15
+ const oldLog = LOG_FILE + ".old";
16
+ if (existsSync(oldLog))
17
+ unlinkSync(oldLog);
18
+ renameSync(LOG_FILE, oldLog);
19
+ }
20
+ catch { }
21
+ }
7
22
  function ensureLoggerInitialized() {
8
23
  if (globalThis[GLOBAL_LOGGER_KEY])
9
24
  return;
10
25
  if (!existsSync(LOG_DIR)) {
11
26
  mkdirSync(LOG_DIR, { recursive: true });
12
27
  }
28
+ rotateLog();
13
29
  writeFileSync(LOG_FILE, `\n--- Session started: ${new Date().toISOString()} ---\n`, {
14
30
  flag: "a",
15
31
  });
@@ -1 +1 @@
1
- {"version":3,"file":"migration-service.d.ts","sourceRoot":"","sources":["../../src/services/migration-service.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,KAAK,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,WAAW,GAAG,cAAc,GAAG,SAAS,GAAG,UAAU,CAAC;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,aAAa,GAAG,UAAU,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,gBAAgB,CAAC,CAAwC;IAE3D,uBAAuB,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAoDrD,iBAAiB,CACrB,QAAQ,EAAE,aAAa,GAAG,UAAU,EACpC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,IAAI,GACvD,OAAO,CAAC,eAAe,CAAC;YA6Cb,mBAAmB;YAmDnB,gBAAgB;IA+I9B,OAAO,CAAC,cAAc;IAMtB,SAAS;;;;;CAOV;AAED,eAAO,MAAM,gBAAgB,kBAAyB,CAAC"}
1
+ {"version":3,"file":"migration-service.d.ts","sourceRoot":"","sources":["../../src/services/migration-service.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,KAAK,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,WAAW,GAAG,cAAc,GAAG,SAAS,GAAG,UAAU,CAAC;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,aAAa,GAAG,UAAU,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,gBAAgB,CAAC,CAAwC;IAE3D,uBAAuB,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAoDrD,iBAAiB,CACrB,QAAQ,EAAE,aAAa,GAAG,UAAU,EACpC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,IAAI,GACvD,OAAO,CAAC,eAAe,CAAC;YA2Cb,mBAAmB;YA8CnB,gBAAgB;IA2I9B,OAAO,CAAC,cAAc;IAMtB,SAAS;;;;;CAOV;AAED,eAAO,MAAM,gBAAgB,kBAAyB,CAAC"}
@@ -57,7 +57,6 @@ export class MigrationService {
57
57
  this.progressCallback = progressCallback;
58
58
  const startTime = Date.now();
59
59
  try {
60
- log("Migration: starting", { strategy, model: CONFIG.embeddingModel });
61
60
  const mismatch = await this.detectDimensionMismatch();
62
61
  if (!mismatch.needsMigration) {
63
62
  return {
@@ -108,10 +107,6 @@ export class MigrationService {
108
107
  });
109
108
  shardManager.deleteShard(shardInfo.shardId);
110
109
  deletedShards++;
111
- log("Migration: deleted shard", {
112
- shardId: shardInfo.shardId,
113
- vectorCount: shardInfo.vectorCount,
114
- });
115
110
  }
116
111
  catch (error) {
117
112
  log("Migration: error deleting shard", {
@@ -135,6 +130,7 @@ export class MigrationService {
135
130
  }
136
131
  async reEmbedMigration(mismatch, startTime) {
137
132
  await embeddingService.warmup();
133
+ embeddingService.clearCache();
138
134
  const totalMemories = mismatch.shardMismatches.reduce((sum, s) => sum + s.vectorCount, 0);
139
135
  this.reportProgress({
140
136
  phase: "preparing",
@@ -217,10 +213,6 @@ export class MigrationService {
217
213
  processedCount++;
218
214
  }
219
215
  }
220
- log("Migration: re-embedded shard", {
221
- shardId: shardInfo.shardId,
222
- count: tempMemories.length,
223
- });
224
216
  }
225
217
  catch (error) {
226
218
  log("Migration: error processing shard", {
@@ -8,6 +8,7 @@ export declare class ConnectionManager {
8
8
  getConnection(dbPath: string): Database;
9
9
  closeConnection(dbPath: string): void;
10
10
  closeAll(): void;
11
+ checkpointAll(): void;
11
12
  }
12
13
  export declare const connectionManager: ConnectionManager;
13
14
  //# sourceMappingURL=connection-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection-manager.d.ts","sourceRoot":"","sources":["../../../src/services/sqlite/connection-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAOtC,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAAoC;IACvD,OAAO,CAAC,gBAAgB,CAAS;IAEjC,OAAO,CAAC,eAAe;IA+EvB,OAAO,CAAC,YAAY;IAuBpB,OAAO,CAAC,aAAa;IAqBrB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAmBvC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IASrC,QAAQ,IAAI,IAAI;CAWjB;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
1
+ {"version":3,"file":"connection-manager.d.ts","sourceRoot":"","sources":["../../../src/services/sqlite/connection-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAOtC,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAAoC;IACvD,OAAO,CAAC,gBAAgB,CAAS;IAEjC,OAAO,CAAC,eAAe;IA2EvB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,aAAa;IAoBrB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAmBvC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IASrC,QAAQ,IAAI,IAAI;IAYhB,aAAa,IAAI,IAAI;CAStB;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
@@ -21,12 +21,10 @@ export class ConnectionManager {
21
21
  }
22
22
  try {
23
23
  Database.setCustomSQLite(customPath);
24
- log("Using custom SQLite library", { path: customPath });
25
24
  }
26
25
  catch (error) {
27
26
  const errorStr = String(error);
28
27
  if (errorStr.includes("SQLite already loaded")) {
29
- log("SQLite already loaded, skipping custom path configuration");
30
28
  }
31
29
  else {
32
30
  throw new Error(`Failed to load custom SQLite library: ${error}\n` + `Path: ${customPath}`);
@@ -48,12 +46,10 @@ export class ConnectionManager {
48
46
  if (foundPath) {
49
47
  try {
50
48
  Database.setCustomSQLite(foundPath);
51
- log("Auto-detected and using Homebrew SQLite", { path: foundPath });
52
49
  }
53
50
  catch (error) {
54
51
  const errorStr = String(error);
55
52
  if (errorStr.includes("SQLite already loaded")) {
56
- log("SQLite already loaded, skipping auto-detected path configuration");
57
53
  }
58
54
  else {
59
55
  throw new Error(`Failed to load Homebrew SQLite: ${error}\n` + `Path: ${foundPath}`);
@@ -81,6 +77,7 @@ export class ConnectionManager {
81
77
  this.sqliteConfigured = true;
82
78
  }
83
79
  initDatabase(db) {
80
+ db.run("PRAGMA busy_timeout = 5000");
84
81
  db.run("PRAGMA journal_mode = WAL");
85
82
  db.run("PRAGMA synchronous = NORMAL");
86
83
  db.run("PRAGMA cache_size = -64000");
@@ -105,12 +102,11 @@ export class ConnectionManager {
105
102
  const hasTags = columns.some((c) => c.name === "tags");
106
103
  if (!hasTags && columns.length > 0) {
107
104
  db.run("ALTER TABLE memories ADD COLUMN tags TEXT");
108
- log("Migrated schema: added tags column to memories table");
109
105
  }
110
106
  db.run(`
111
107
  CREATE VIRTUAL TABLE IF NOT EXISTS vec_tags USING vec0(
112
108
  memory_id TEXT PRIMARY KEY,
113
- embedding float32[${CONFIG.embeddingDimensions}]
109
+ embedding float32[${CONFIG.embeddingDimensions}] distance_metric=cosine
114
110
  )
115
111
  `);
116
112
  }
@@ -152,5 +148,15 @@ export class ConnectionManager {
152
148
  }
153
149
  this.connections.clear();
154
150
  }
151
+ checkpointAll() {
152
+ for (const [path, db] of this.connections) {
153
+ try {
154
+ db.run("PRAGMA wal_checkpoint(PASSIVE)");
155
+ }
156
+ catch (error) {
157
+ log("Error checkpointing database", { path, error: String(error) });
158
+ }
159
+ }
160
+ }
155
161
  }
156
162
  export const connectionManager = new ConnectionManager();
@@ -1 +1 @@
1
- {"version":3,"file":"shard-manager.d.ts","sourceRoot":"","sources":["../../../src/services/sqlite/shard-manager.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAW;IAC7B,OAAO,CAAC,YAAY,CAAS;;IAQ7B,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,iBAAiB;IAKzB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAsB9E,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE;IAgCvE,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS;IA6BxF,OAAO,CAAC,WAAW;IA2DnB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS;IAetE,OAAO,CAAC,iBAAiB;IAQzB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAO3C,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAO3C,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAkBhD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAuBnC;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}
1
+ {"version":3,"file":"shard-manager.d.ts","sourceRoot":"","sources":["../../../src/services/sqlite/shard-manager.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAW;IAC7B,OAAO,CAAC,YAAY,CAAS;;IAQ7B,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,iBAAiB;IAKzB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAsB9E,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE;IAgCvE,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS;IA2BxF,OAAO,CAAC,WAAW;IA2DnB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS;IAetE,OAAO,CAAC,iBAAiB;IAOzB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAO3C,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAO3C,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAkBhD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAqBnC;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}
@@ -100,7 +100,6 @@ export class ShardManager {
100
100
  const result = stmt.run(scope, scopeHash, shardIndex, storedPath, now);
101
101
  const db = connectionManager.getConnection(fullPath);
102
102
  this.initShardDb(db);
103
- log("Shard created", { scope, scopeHash, shardIndex, fullPath });
104
103
  return {
105
104
  id: Number(result.lastInsertRowid),
106
105
  scope,
@@ -150,13 +149,13 @@ export class ShardManager {
150
149
  db.run(`
151
150
  CREATE VIRTUAL TABLE IF NOT EXISTS vec_memories USING vec0(
152
151
  memory_id TEXT PRIMARY KEY,
153
- embedding float32[${CONFIG.embeddingDimensions}]
152
+ embedding float32[${CONFIG.embeddingDimensions}] distance_metric=cosine
154
153
  )
155
154
  `);
156
155
  db.run(`
157
156
  CREATE VIRTUAL TABLE IF NOT EXISTS vec_tags USING vec0(
158
157
  memory_id TEXT PRIMARY KEY,
159
- embedding float32[${CONFIG.embeddingDimensions}]
158
+ embedding float32[${CONFIG.embeddingDimensions}] distance_metric=cosine
160
159
  )
161
160
  `);
162
161
  db.run(`CREATE INDEX IF NOT EXISTS idx_container_tag ON memories(container_tag)`);
@@ -180,7 +179,6 @@ export class ShardManager {
180
179
  UPDATE shards SET is_active = 0 WHERE id = ?
181
180
  `);
182
181
  stmt.run(shardId);
183
- log("Shard marked read-only", { shardId });
184
182
  }
185
183
  incrementVectorCount(shardId) {
186
184
  const stmt = this.metadataDb.prepare(`
@@ -228,7 +226,6 @@ export class ShardManager {
228
226
  }
229
227
  const deleteStmt = this.metadataDb.prepare(`DELETE FROM shards WHERE id = ?`);
230
228
  deleteStmt.run(shardId);
231
- log("Shard deleted", { shardId, dbPath: fullPath });
232
229
  }
233
230
  }
234
231
  }
@@ -2,8 +2,8 @@ import { Database } from "bun:sqlite";
2
2
  import type { MemoryRecord, SearchResult, ShardInfo } from "./types.js";
3
3
  export declare class VectorSearch {
4
4
  insertVector(db: Database, record: MemoryRecord): void;
5
- searchInShard(shard: ShardInfo, queryVector: Float32Array, containerTag: string, limit: number): SearchResult[];
6
- searchAcrossShards(shards: ShardInfo[], queryVector: Float32Array, containerTag: string, limit: number, similarityThreshold: number): Promise<SearchResult[]>;
5
+ searchInShard(shard: ShardInfo, queryVector: Float32Array, containerTag: string, limit: number, queryText?: string): SearchResult[];
6
+ searchAcrossShards(shards: ShardInfo[], queryVector: Float32Array, containerTag: string, limit: number, similarityThreshold: number, queryText?: string): Promise<SearchResult[]>;
7
7
  deleteVector(db: Database, memoryId: string): void;
8
8
  listMemories(db: Database, containerTag: string, limit: number): any[];
9
9
  getAllMemories(db: Database): any[];
@@ -1 +1 @@
1
- {"version":3,"file":"vector-search.d.ts","sourceRoot":"","sources":["../../../src/services/sqlite/vector-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExE,qBAAa,YAAY;IACvB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI;IA0CtD,aAAa,CACX,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,GACZ,YAAY,EAAE;IAyEX,kBAAkB,CACtB,MAAM,EAAE,SAAS,EAAE,EACnB,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC;IAgB1B,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAMlD,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE;IAWtE,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,GAAG,EAAE;IAKnC,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAKzD,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAMxD,eAAe,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM;IAMrC,eAAe,CAAC,EAAE,EAAE,QAAQ,GAAG,GAAG,EAAE;IAepC,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK/C,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAIlD;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}
1
+ {"version":3,"file":"vector-search.d.ts","sourceRoot":"","sources":["../../../src/services/sqlite/vector-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExE,qBAAa,YAAY;IACvB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI;IA0CtD,aAAa,CACX,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,GACjB,YAAY,EAAE;IA0FX,kBAAkB,CACtB,MAAM,EAAE,SAAS,EAAE,EACnB,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,mBAAmB,EAAE,MAAM,EAC3B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC;IAiB1B,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAMlD,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE;IAWtE,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,GAAG,EAAE;IAKnC,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAKzD,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAMxD,eAAe,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM;IAMrC,eAAe,CAAC,EAAE,EAAE,QAAQ,GAAG,GAAG,EAAE;IAepC,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK/C,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAIlD;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}
@@ -23,7 +23,7 @@ export class VectorSearch {
23
23
  insertTagsVec.run(record.id, tagsVectorBuffer);
24
24
  }
25
25
  }
26
- searchInShard(shard, queryVector, containerTag, limit) {
26
+ searchInShard(shard, queryVector, containerTag, limit, queryText) {
27
27
  const db = connectionManager.getConnection(shard.dbPath);
28
28
  const queryBuffer = new Uint8Array(queryVector.buffer);
29
29
  const contentResults = db
@@ -42,11 +42,11 @@ export class VectorSearch {
42
42
  .all(queryBuffer, limit * 4);
43
43
  const scoreMap = new Map();
44
44
  for (const r of contentResults) {
45
- scoreMap.set(r.memory_id, { contentDist: r.distance, tagsDist: 1 });
45
+ scoreMap.set(r.memory_id, { contentSim: 1 - r.distance, tagsSim: 0 });
46
46
  }
47
47
  for (const r of tagsResults) {
48
- const entry = scoreMap.get(r.memory_id) || { contentDist: 1, tagsDist: 1 };
49
- entry.tagsDist = r.distance;
48
+ const entry = scoreMap.get(r.memory_id) || { contentSim: 0, tagsSim: 0 };
49
+ entry.tagsSim = 1 - r.distance;
50
50
  scoreMap.set(r.memory_id, entry);
51
51
  }
52
52
  const ids = Array.from(scoreMap.keys());
@@ -59,16 +59,28 @@ export class VectorSearch {
59
59
  WHERE id IN (${placeholders}) AND container_tag = ?
60
60
  `)
61
61
  .all(...ids, containerTag);
62
+ const queryWords = queryText
63
+ ? queryText
64
+ .toLowerCase()
65
+ .split(/[\s,]+/)
66
+ .filter((w) => w.length > 1)
67
+ : [];
62
68
  return rows.map((row) => {
63
69
  const scores = scoreMap.get(row.id);
64
- const contentSim = 1 - scores.contentDist;
65
- const tagsSim = 1 - scores.tagsDist;
66
- const similarity = tagsSim * 0.8 + contentSim * 0.2;
70
+ const memoryTagsStr = row.tags || "";
71
+ const memoryTags = memoryTagsStr.split(",").map((t) => t.trim().toLowerCase());
72
+ let exactMatchBoost = 0;
73
+ if (queryWords.length > 0 && memoryTags.length > 0) {
74
+ const matches = queryWords.filter((w) => memoryTags.some((t) => t.includes(w) || w.includes(t))).length;
75
+ exactMatchBoost = matches / Math.max(queryWords.length, 1);
76
+ }
77
+ const tagSim = Math.max(scores.tagsSim, exactMatchBoost);
78
+ const similarity = tagSim * 0.8 + scores.contentSim * 0.2;
67
79
  return {
68
80
  id: row.id,
69
81
  memory: row.content,
70
82
  similarity,
71
- tags: row.tags ? row.tags.split(",").map((t) => t.trim()) : [],
83
+ tags: memoryTagsStr ? memoryTagsStr.split(",") : [],
72
84
  metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
73
85
  containerTag: row.container_tag,
74
86
  displayName: row.display_name,
@@ -81,17 +93,18 @@ export class VectorSearch {
81
93
  };
82
94
  });
83
95
  }
84
- async searchAcrossShards(shards, queryVector, containerTag, limit, similarityThreshold) {
85
- const allResults = [];
86
- for (const shard of shards) {
96
+ async searchAcrossShards(shards, queryVector, containerTag, limit, similarityThreshold, queryText) {
97
+ const shardPromises = shards.map(async (shard) => {
87
98
  try {
88
- const results = this.searchInShard(shard, queryVector, containerTag, limit);
89
- allResults.push(...results);
99
+ return this.searchInShard(shard, queryVector, containerTag, limit, queryText);
90
100
  }
91
101
  catch (error) {
92
102
  log("Shard search error", { shardId: shard.id, error: String(error) });
103
+ return [];
93
104
  }
94
- }
105
+ });
106
+ const resultsArray = await Promise.all(shardPromises);
107
+ const allResults = resultsArray.flat();
95
108
  allResults.sort((a, b) => b.similarity - a.similarity);
96
109
  return allResults.filter((r) => r.similarity >= similarityThreshold).slice(0, limit);
97
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"user-memory-learning.d.ts","sourceRoot":"","sources":["../../src/services/user-memory-learning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAuFf"}
1
+ {"version":3,"file":"user-memory-learning.d.ts","sourceRoot":"","sources":["../../src/services/user-memory-learning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAWvD,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAsEf"}
@@ -3,7 +3,11 @@ import { log } from "./logger.js";
3
3
  import { CONFIG } from "../config.js";
4
4
  import { userPromptManager } from "./user-prompt/user-prompt-manager.js";
5
5
  import { userProfileManager } from "./user-profile/user-profile-manager.js";
6
+ let isLearningRunning = false;
6
7
  export async function performUserProfileLearning(ctx, directory) {
8
+ if (isLearningRunning)
9
+ return;
10
+ isLearningRunning = true;
7
11
  try {
8
12
  const count = userPromptManager.countUnanalyzedForUserLearning();
9
13
  const threshold = CONFIG.userProfileAnalysisInterval;
@@ -20,7 +24,6 @@ export async function performUserProfileLearning(ctx, directory) {
20
24
  const context = buildUserAnalysisContext(prompts, existingProfile);
21
25
  const updatedProfileData = await analyzeUserProfile(context, existingProfile);
22
26
  if (!updatedProfileData) {
23
- log("User memory learning: no profile updates", { promptCount: prompts.length });
24
27
  userPromptManager.markMultipleAsUserLearningCaptured(prompts.map((p) => p.id));
25
28
  return;
26
29
  }
@@ -45,25 +48,8 @@ export async function performUserProfileLearning(ctx, directory) {
45
48
  .catch(() => { });
46
49
  }
47
50
  }
48
- catch (error) {
49
- const errorStack = error instanceof Error ? error.stack : undefined;
50
- log("User memory learning error", {
51
- error: String(error),
52
- stack: errorStack,
53
- errorType: error instanceof Error ? error.constructor.name : typeof error,
54
- });
55
- if (CONFIG.showErrorToasts) {
56
- await ctx.client?.tui
57
- .showToast({
58
- body: {
59
- title: "User Profile Update Failed",
60
- message: String(error),
61
- variant: "error",
62
- duration: 5000,
63
- },
64
- })
65
- .catch(() => { });
66
- }
51
+ finally {
52
+ isLearningRunning = false;
67
53
  }
68
54
  }
69
55
  function generateChangeSummary(oldProfile, newProfile) {
@@ -18,6 +18,7 @@ export declare class UserPromptManager {
18
18
  getLastUncapturedPrompt(sessionId: string): UserPrompt | null;
19
19
  deletePrompt(promptId: string): void;
20
20
  markAsCaptured(promptId: string): void;
21
+ claimPrompt(promptId: string): boolean;
21
22
  countUncapturedPrompts(): number;
22
23
  getUncapturedPrompts(limit: number): UserPrompt[];
23
24
  markMultipleAsCaptured(promptIds: string[]): void;
@@ -1 +1 @@
1
- {"version":3,"file":"user-prompt-manager.d.ts","sourceRoot":"","sources":["../../../src/services/user-prompt/user-prompt-manager.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;IAQhC,OAAO,CAAC,YAAY;IA+BpB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAa9F,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAc7D,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKtC,sBAAsB,IAAI,MAAM;IAMhC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAYjD,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAUjD,8BAA8B,IAAI,MAAM;IAQxC,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAYtD,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKlD,kCAAkC,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAU7D,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,EAAE,CAAA;KAAE;IAiBpF,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK5D,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAOlD,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAgBtD,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IAiBpF,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE;IAQ5C,OAAO,CAAC,WAAW;CAapB;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
1
+ {"version":3,"file":"user-prompt-manager.d.ts","sourceRoot":"","sources":["../../../src/services/user-prompt/user-prompt-manager.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;IAQhC,OAAO,CAAC,YAAY;IAiCpB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAa9F,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAc7D,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKtC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQtC,sBAAsB,IAAI,MAAM;IAMhC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAYjD,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAUjD,8BAA8B,IAAI,MAAM;IAQxC,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;IAYtD,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKlD,kCAAkC,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAU7D,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,EAAE,CAAA;KAAE;IAiBpF,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK5D,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAOlD,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAgBtD,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,UAAU,EAAE;IAiBpF,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE;IAQ5C,OAAO,CAAC,WAAW;CAapB;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
@@ -25,6 +25,7 @@ export class UserPromptManager {
25
25
  linked_memory_id TEXT
26
26
  )
27
27
  `);
28
+ this.db.run("UPDATE user_prompts SET captured = 0 WHERE captured = 2");
28
29
  this.db.run("CREATE INDEX IF NOT EXISTS idx_user_prompts_session ON user_prompts(session_id)");
29
30
  this.db.run("CREATE INDEX IF NOT EXISTS idx_user_prompts_captured ON user_prompts(captured)");
30
31
  this.db.run("CREATE INDEX IF NOT EXISTS idx_user_prompts_created ON user_prompts(created_at DESC)");
@@ -62,6 +63,11 @@ export class UserPromptManager {
62
63
  const stmt = this.db.prepare(`UPDATE user_prompts SET captured = 1 WHERE id = ?`);
63
64
  stmt.run(promptId);
64
65
  }
66
+ claimPrompt(promptId) {
67
+ const stmt = this.db.prepare(`UPDATE user_prompts SET captured = 2 WHERE id = ? AND captured = 0`);
68
+ const result = stmt.run(promptId);
69
+ return result.changes > 0;
70
+ }
65
71
  countUncapturedPrompts() {
66
72
  const stmt = this.db.prepare(`SELECT COUNT(*) as count FROM user_prompts WHERE captured = 0`);
67
73
  const row = stmt.get();
@@ -1 +1 @@
1
- {"version":3,"file":"web-server.d.ts","sourceRoot":"","sources":["../../src/services/web-server.ts"],"names":[],"mappings":"AAOA,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAeD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,YAAY,CAA8B;gBAEtC,MAAM,EAAE,eAAe;IAI7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YASd,MAAM;IA0Ed,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3B,SAAS,IAAI,OAAO;IAIpB,aAAa,IAAI,OAAO;IAIxB,MAAM,IAAI,MAAM;IAIV,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;CAW/C;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAIhF"}
1
+ {"version":3,"file":"web-server.d.ts","sourceRoot":"","sources":["../../src/services/web-server.ts"],"names":[],"mappings":"AAOA,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAeD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,YAAY,CAA8B;gBAEtC,MAAM,EAAE,eAAe;IAI7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YASd,MAAM;IAyEd,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3B,SAAS,IAAI,OAAO;IAIpB,aAAa,IAAI,OAAO;IAIxB,MAAM,IAAI,MAAM;IAIV,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;CAW/C;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAIhF"}
@@ -20,7 +20,6 @@ export class WebServer {
20
20
  }
21
21
  async _start() {
22
22
  if (!this.config.enabled) {
23
- log("Web server disabled in config");
24
23
  return;
25
24
  }
26
25
  try {
package/dist/web/app.js CHANGED
@@ -387,7 +387,7 @@ async function addMemory(e) {
387
387
 
388
388
  const content = document.getElementById("add-content").value.trim();
389
389
  const containerTag = document.getElementById("add-tag").value;
390
- const type = document.getElementById("add-type").value.trim();
390
+ const type = document.getElementById("add-type").value;
391
391
  const tagsStr = document.getElementById("add-tags").value.trim();
392
392
  const tags = tagsStr
393
393
  ? tagsStr
@@ -152,7 +152,18 @@
152
152
 
153
153
  <div class="form-group">
154
154
  <label>Type:</label>
155
- <input type="text" id="add-type" placeholder="preference, architecture, etc." />
155
+ <select id="add-type">
156
+ <option value="">other</option>
157
+ <option value="feature">feature</option>
158
+ <option value="bug-fix">bug-fix</option>
159
+ <option value="refactor">refactor</option>
160
+ <option value="architecture">architecture</option>
161
+ <option value="rule">rule</option>
162
+ <option value="documentation">documentation</option>
163
+ <option value="discussion">discussion</option>
164
+ <option value="analysis">analysis</option>
165
+ <option value="configuration">configuration</option>
166
+ </select>
156
167
  </div>
157
168
 
158
169
  <div class="form-group">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-mem",
3
- "version": "2.6.1",
3
+ "version": "2.7.0",
4
4
  "description": "OpenCode plugin that gives coding agents persistent memory using local vector database",
5
5
  "type": "module",
6
6
  "main": "dist/plugin.js",