opencode-mem 2.7.5 → 2.7.7

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/README.md CHANGED
@@ -28,7 +28,7 @@ Add to your OpenCode configuration at `~/.config/opencode/opencode.json`:
28
28
 
29
29
  ```jsonc
30
30
  {
31
- "plugins": ["opencode-mem"],
31
+ "plugin": ["opencode-mem"],
32
32
  }
33
33
  ```
34
34
 
@@ -72,6 +72,18 @@ Configure at `~/.config/opencode/opencode-mem.jsonc`:
72
72
 
73
73
  "userProfileAnalysisInterval": 10,
74
74
  "maxMemories": 10,
75
+
76
+ "compaction": {
77
+ "enabled": true,
78
+ "memoryLimit": 10,
79
+ },
80
+ "chatMessage": {
81
+ "enabled": true,
82
+ "maxMemories": 3,
83
+ "excludeCurrentSession": true,
84
+ "maxAgeDays": undefined,
85
+ "injectOn": "first",
86
+ },
75
87
  }
76
88
  ```
77
89
 
package/dist/config.d.ts CHANGED
@@ -39,6 +39,17 @@ export declare const CONFIG: {
39
39
  showAutoCaptureToasts: boolean;
40
40
  showUserProfileToasts: boolean;
41
41
  showErrorToasts: boolean;
42
+ compaction: {
43
+ enabled: boolean | undefined;
44
+ memoryLimit: number | undefined;
45
+ };
46
+ chatMessage: {
47
+ enabled: boolean | undefined;
48
+ maxMemories: number | undefined;
49
+ excludeCurrentSession: boolean | undefined;
50
+ maxAgeDays: number | undefined;
51
+ injectOn: "first" | "always";
52
+ };
42
53
  };
43
54
  export declare function isConfigured(): boolean;
44
55
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAwYA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;oBA2Bb,aAAa,GACb,kBAAkB,GAClB,WAAW;;;;;;;;;;;;;;;;;;;;;;;CA6BhB,CAAC;AAEF,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AA8ZA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;oBA2Bb,aAAa,GACb,kBAAkB,GAClB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAwCT,OAAO,GACP,QAAQ;;CAEf,CAAC;AAEF,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
package/dist/config.js CHANGED
@@ -45,6 +45,17 @@ const DEFAULTS = {
45
45
  showAutoCaptureToasts: true,
46
46
  showUserProfileToasts: true,
47
47
  showErrorToasts: true,
48
+ compaction: {
49
+ enabled: true,
50
+ memoryLimit: 10,
51
+ },
52
+ chatMessage: {
53
+ enabled: true,
54
+ maxMemories: 3,
55
+ excludeCurrentSession: true,
56
+ maxAgeDays: undefined,
57
+ injectOn: "first",
58
+ },
48
59
  };
49
60
  function expandPath(path) {
50
61
  if (path.startsWith("~/")) {
@@ -355,6 +366,17 @@ export const CONFIG = {
355
366
  showAutoCaptureToasts: fileConfig.showAutoCaptureToasts ?? DEFAULTS.showAutoCaptureToasts,
356
367
  showUserProfileToasts: fileConfig.showUserProfileToasts ?? DEFAULTS.showUserProfileToasts,
357
368
  showErrorToasts: fileConfig.showErrorToasts ?? DEFAULTS.showErrorToasts,
369
+ compaction: {
370
+ enabled: fileConfig.compaction?.enabled ?? DEFAULTS.compaction.enabled,
371
+ memoryLimit: fileConfig.compaction?.memoryLimit ?? DEFAULTS.compaction.memoryLimit,
372
+ },
373
+ chatMessage: {
374
+ enabled: fileConfig.chatMessage?.enabled ?? DEFAULTS.chatMessage.enabled,
375
+ maxMemories: fileConfig.chatMessage?.maxMemories ?? DEFAULTS.chatMessage.maxMemories,
376
+ excludeCurrentSession: fileConfig.chatMessage?.excludeCurrentSession ?? DEFAULTS.chatMessage.excludeCurrentSession,
377
+ maxAgeDays: fileConfig.chatMessage?.maxAgeDays,
378
+ injectOn: (fileConfig.chatMessage?.injectOn ?? DEFAULTS.chatMessage.injectOn),
379
+ },
358
380
  };
359
381
  export function isConfigured() {
360
382
  return true;
@@ -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,MAiV/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,MA+Z/B,CAAC"}
package/dist/index.js CHANGED
@@ -98,7 +98,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
98
98
  process.on("SIGTERM", shutdownHandler);
99
99
  return {
100
100
  "chat.message": async (input, output) => {
101
- if (!isConfigured())
101
+ if (!isConfigured() || !CONFIG.chatMessage.enabled)
102
102
  return;
103
103
  try {
104
104
  const textParts = output.parts.filter((p) => p.type === "text");
@@ -108,42 +108,52 @@ export const OpenCodeMemPlugin = async (ctx) => {
108
108
  if (!userMessage.trim())
109
109
  return;
110
110
  userPromptManager.savePrompt(input.sessionID, output.message.id, directory, userMessage);
111
- const searchResult = await memoryClient.searchMemories(userMessage, tags.project.tag);
112
- if (searchResult.success && searchResult.results.length > 0) {
113
- const relevantMemories = searchResult.results
114
- .filter((m) => {
115
- const memorySessionId = m.metadata?.sessionID;
116
- const isFromOtherSession = memorySessionId !== input.sessionID;
117
- const isRelevant = m.similarity > 0.65;
118
- return isFromOtherSession && isRelevant;
119
- })
120
- .slice(0, 3);
121
- if (relevantMemories.length > 0) {
122
- const projectMemories = {
123
- results: relevantMemories.map((m) => ({
124
- id: m.id,
125
- memory: m.memory,
126
- similarity: m.similarity,
127
- title: m.displayName,
128
- metadata: m.metadata,
129
- })),
130
- total: relevantMemories.length,
131
- timing: 0,
132
- };
133
- const userId = tags.user.userEmail || null;
134
- const memoryContext = formatContextForPrompt(userId, projectMemories);
135
- if (memoryContext) {
136
- const contextPart = {
137
- id: `memory-context-${Date.now()}`,
138
- sessionID: input.sessionID,
139
- messageID: output.message.id,
140
- type: "text",
141
- text: memoryContext,
142
- synthetic: true,
143
- };
144
- output.parts.unshift(contextPart);
145
- }
146
- }
111
+ const messagesResponse = await ctx.client.session.messages({
112
+ path: { id: input.sessionID },
113
+ });
114
+ const messages = messagesResponse.data || [];
115
+ const hasNonSyntheticUserMessages = messages.some((m) => m.info.role === "user" &&
116
+ !m.parts.every((p) => p.type !== "text" || p.synthetic === true));
117
+ const lastMessage = messages.length > 0 ? messages[messages.length - 1] : null;
118
+ const isAfterCompaction = lastMessage?.info?.summary === true;
119
+ const shouldInject = CONFIG.chatMessage.injectOn === "always" ||
120
+ !hasNonSyntheticUserMessages ||
121
+ (isAfterCompaction &&
122
+ messages.filter((m) => m.info.role === "user" &&
123
+ !m.parts.every((p) => p.type !== "text" || p.synthetic === true)).length === 1);
124
+ if (!shouldInject)
125
+ return;
126
+ const listResult = await memoryClient.listMemories(tags.project.tag, CONFIG.chatMessage.maxMemories);
127
+ let memories = listResult.success ? listResult.memories : [];
128
+ if (CONFIG.chatMessage.excludeCurrentSession) {
129
+ memories = memories.filter((m) => m.metadata?.sessionID !== input.sessionID);
130
+ }
131
+ if (CONFIG.chatMessage.maxAgeDays) {
132
+ const cutoffDate = Date.now() - CONFIG.chatMessage.maxAgeDays * 86400000;
133
+ memories = memories.filter((m) => new Date(m.createdAt).getTime() > cutoffDate);
134
+ }
135
+ if (memories.length === 0)
136
+ return;
137
+ const projectMemories = {
138
+ results: memories.map((m) => ({
139
+ similarity: 1.0,
140
+ memory: m.summary,
141
+ })),
142
+ total: memories.length,
143
+ timing: 0,
144
+ };
145
+ const userId = tags.user.userEmail || null;
146
+ const memoryContext = formatContextForPrompt(userId, projectMemories);
147
+ if (memoryContext) {
148
+ const contextPart = {
149
+ id: `memory-context-${Date.now()}`,
150
+ sessionID: input.sessionID,
151
+ messageID: output.message.id,
152
+ type: "text",
153
+ text: memoryContext,
154
+ synthetic: true,
155
+ };
156
+ output.parts.unshift(contextPart);
147
157
  }
148
158
  }
149
159
  catch (error) {
@@ -315,6 +325,47 @@ export const OpenCodeMemPlugin = async (ctx) => {
315
325
  }
316
326
  }, 10000);
317
327
  }
328
+ if (event.type === "session.compacted") {
329
+ if (!isConfigured() || !CONFIG.compaction.enabled)
330
+ return;
331
+ const sessionID = event.properties?.sessionID;
332
+ if (!sessionID)
333
+ return;
334
+ try {
335
+ const tags = getTags(directory);
336
+ const memoriesResult = await memoryClient.searchMemoriesBySessionID(sessionID, tags.project.tag, CONFIG.compaction.memoryLimit);
337
+ if (!memoriesResult.success || memoriesResult.results.length === 0) {
338
+ return;
339
+ }
340
+ const memoryContext = formatMemoriesForCompaction(memoriesResult.results);
341
+ await ctx.client.session.prompt({
342
+ path: { id: sessionID },
343
+ body: {
344
+ parts: [{ type: "text", text: memoryContext }],
345
+ noReply: true,
346
+ },
347
+ });
348
+ if (ctx.client?.tui) {
349
+ await ctx.client.tui
350
+ .showToast({
351
+ body: {
352
+ title: "Memory Restored",
353
+ message: `${memoriesResult.results.length} memories injected after compaction`,
354
+ variant: "success",
355
+ duration: 3000,
356
+ },
357
+ })
358
+ .catch(() => { });
359
+ }
360
+ log("Compaction memory injected", {
361
+ sessionID,
362
+ count: memoriesResult.results.length,
363
+ });
364
+ }
365
+ catch (error) {
366
+ log("Compaction handler error", { error: String(error) });
367
+ }
368
+ }
318
369
  },
319
370
  };
320
371
  };
@@ -331,3 +382,14 @@ function formatSearchResults(query, results, limit) {
331
382
  })),
332
383
  });
333
384
  }
385
+ function formatMemoriesForCompaction(memories) {
386
+ let output = `## Restored Session Memory\n\n`;
387
+ memories.forEach((m, i) => {
388
+ output += `### Memory ${i + 1}\n`;
389
+ output += `${m.memory}\n\n`;
390
+ if (m.tags && m.tags.length > 0) {
391
+ output += `Tags: ${m.tags.join(", ")}\n\n`;
392
+ }
393
+ });
394
+ return output;
395
+ }
@@ -86,6 +86,33 @@ export declare class LocalMemoryClient {
86
86
  totalPages: number;
87
87
  };
88
88
  }>;
89
+ searchMemoriesBySessionID(sessionID: string, containerTag: string, limit?: number): Promise<{
90
+ success: true;
91
+ results: {
92
+ id: any;
93
+ memory: any;
94
+ similarity: number;
95
+ tags: any;
96
+ metadata: any;
97
+ containerTag: any;
98
+ displayName: any;
99
+ userName: any;
100
+ userEmail: any;
101
+ projectPath: any;
102
+ projectName: any;
103
+ gitRepoUrl: any;
104
+ createdAt: any;
105
+ }[];
106
+ total: number;
107
+ timing: number;
108
+ error?: undefined;
109
+ } | {
110
+ success: false;
111
+ error: string;
112
+ results: never[];
113
+ total: number;
114
+ timing: number;
115
+ }>;
89
116
  }
90
117
  export declare const memoryClient: LocalMemoryClient;
91
118
  //# sourceMappingURL=client.d.ts.map
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDpD;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;;;;;;;IA2B7B,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,SAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuD7C,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4C5F;AAED,eAAO,MAAM,YAAY,mBAA0B,CAAC"}
@@ -209,5 +209,43 @@ export class LocalMemoryClient {
209
209
  };
210
210
  }
211
211
  }
212
+ async searchMemoriesBySessionID(sessionID, containerTag, limit = 10) {
213
+ try {
214
+ await this.initialize();
215
+ const { scope, hash } = extractScopeFromContainerTag(containerTag);
216
+ const shards = shardManager.getAllShards(scope, hash);
217
+ if (shards.length === 0) {
218
+ return { success: true, results: [], total: 0, timing: 0 };
219
+ }
220
+ const allMemories = [];
221
+ for (const shard of shards) {
222
+ const db = connectionManager.getConnection(shard.dbPath);
223
+ const memories = vectorSearch.getMemoriesBySessionID(db, sessionID);
224
+ allMemories.push(...memories);
225
+ }
226
+ allMemories.sort((a, b) => b.created_at - a.created_at);
227
+ const results = allMemories.slice(0, limit).map((row) => ({
228
+ id: row.id,
229
+ memory: row.content,
230
+ similarity: 1.0,
231
+ tags: row.tags || [],
232
+ metadata: row.metadata || {},
233
+ containerTag: row.container_tag,
234
+ displayName: row.display_name,
235
+ userName: row.user_name,
236
+ userEmail: row.user_email,
237
+ projectPath: row.project_path,
238
+ projectName: row.project_name,
239
+ gitRepoUrl: row.git_repo_url,
240
+ createdAt: row.created_at,
241
+ }));
242
+ return { success: true, results, total: results.length, timing: 0 };
243
+ }
244
+ catch (error) {
245
+ const errorMessage = error instanceof Error ? error.message : String(error);
246
+ log("searchMemoriesBySessionID: error", { error: errorMessage });
247
+ return { success: false, error: errorMessage, results: [], total: 0, timing: 0 };
248
+ }
249
+ }
212
250
  }
213
251
  export const memoryClient = new LocalMemoryClient();
@@ -9,6 +9,7 @@ export declare class VectorSearch {
9
9
  listMemories(db: Database, containerTag: string, limit: number): any[];
10
10
  getAllMemories(db: Database): any[];
11
11
  getMemoryById(db: Database, memoryId: string): any | null;
12
+ getMemoriesBySessionID(db: Database, sessionID: string): any[];
12
13
  countVectors(db: Database, containerTag: string): number;
13
14
  countAllVectors(db: Database): number;
14
15
  getDistinctTags(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,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,CACV,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,EACpB,UAAU,CAAC,EAAE,YAAY,GACxB,IAAI;IAkBP,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,CACV,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,EACpB,UAAU,CAAC,EAAE,YAAY,GACxB,IAAI;IAkBP,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,sBAAsB,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,GAAG,EAAE;IAgB9D,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"}
@@ -140,6 +140,19 @@ export class VectorSearch {
140
140
  const stmt = db.prepare(`SELECT * FROM memories WHERE id = ?`);
141
141
  return stmt.get(memoryId);
142
142
  }
143
+ getMemoriesBySessionID(db, sessionID) {
144
+ const stmt = db.prepare(`
145
+ SELECT * FROM memories
146
+ WHERE metadata LIKE ?
147
+ ORDER BY created_at DESC
148
+ `);
149
+ const rows = stmt.all(`%"sessionID":"${sessionID}"%`);
150
+ return rows.map((row) => ({
151
+ ...row,
152
+ tags: row.tags ? row.tags.split(",") : [],
153
+ metadata: row.metadata ? JSON.parse(row.metadata) : {},
154
+ }));
155
+ }
143
156
  countVectors(db, containerTag) {
144
157
  const stmt = db.prepare(`SELECT COUNT(*) as count FROM memories WHERE container_tag = ?`);
145
158
  const result = stmt.get(containerTag);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-mem",
3
- "version": "2.7.5",
3
+ "version": "2.7.7",
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",
@@ -37,7 +37,7 @@
37
37
  "@xenova/transformers": "^2.17.2",
38
38
  "franc-min": "^6.2.0",
39
39
  "iso-639-3": "^3.0.1",
40
- "sqlite-vec": "^0.1.7-alpha.2"
40
+ "sqlite-vec": "0.1.7-alpha.2"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/bun": "^1.3.8",