opencode-mem 1.0.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 (84) hide show
  1. package/README.md +588 -0
  2. package/dist/config.d.ts +33 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +258 -0
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +618 -0
  8. package/dist/plugin.d.ts +5 -0
  9. package/dist/plugin.d.ts.map +1 -0
  10. package/dist/plugin.js +15 -0
  11. package/dist/services/api-handlers.d.ts +102 -0
  12. package/dist/services/api-handlers.d.ts.map +1 -0
  13. package/dist/services/api-handlers.js +494 -0
  14. package/dist/services/auto-capture.d.ts +32 -0
  15. package/dist/services/auto-capture.d.ts.map +1 -0
  16. package/dist/services/auto-capture.js +451 -0
  17. package/dist/services/cleanup-service.d.ts +20 -0
  18. package/dist/services/cleanup-service.d.ts.map +1 -0
  19. package/dist/services/cleanup-service.js +88 -0
  20. package/dist/services/client.d.ts +104 -0
  21. package/dist/services/client.d.ts.map +1 -0
  22. package/dist/services/client.js +251 -0
  23. package/dist/services/compaction.d.ts +92 -0
  24. package/dist/services/compaction.d.ts.map +1 -0
  25. package/dist/services/compaction.js +421 -0
  26. package/dist/services/context.d.ts +17 -0
  27. package/dist/services/context.d.ts.map +1 -0
  28. package/dist/services/context.js +41 -0
  29. package/dist/services/deduplication-service.d.ts +30 -0
  30. package/dist/services/deduplication-service.d.ts.map +1 -0
  31. package/dist/services/deduplication-service.js +131 -0
  32. package/dist/services/embedding.d.ts +10 -0
  33. package/dist/services/embedding.d.ts.map +1 -0
  34. package/dist/services/embedding.js +77 -0
  35. package/dist/services/jsonc.d.ts +7 -0
  36. package/dist/services/jsonc.d.ts.map +1 -0
  37. package/dist/services/jsonc.js +76 -0
  38. package/dist/services/logger.d.ts +2 -0
  39. package/dist/services/logger.d.ts.map +1 -0
  40. package/dist/services/logger.js +16 -0
  41. package/dist/services/migration-service.d.ts +42 -0
  42. package/dist/services/migration-service.d.ts.map +1 -0
  43. package/dist/services/migration-service.js +258 -0
  44. package/dist/services/privacy.d.ts +4 -0
  45. package/dist/services/privacy.d.ts.map +1 -0
  46. package/dist/services/privacy.js +10 -0
  47. package/dist/services/sqlite/connection-manager.d.ts +10 -0
  48. package/dist/services/sqlite/connection-manager.d.ts.map +1 -0
  49. package/dist/services/sqlite/connection-manager.js +45 -0
  50. package/dist/services/sqlite/shard-manager.d.ts +20 -0
  51. package/dist/services/sqlite/shard-manager.d.ts.map +1 -0
  52. package/dist/services/sqlite/shard-manager.js +221 -0
  53. package/dist/services/sqlite/types.d.ts +39 -0
  54. package/dist/services/sqlite/types.d.ts.map +1 -0
  55. package/dist/services/sqlite/types.js +1 -0
  56. package/dist/services/sqlite/vector-search.d.ts +18 -0
  57. package/dist/services/sqlite/vector-search.d.ts.map +1 -0
  58. package/dist/services/sqlite/vector-search.js +129 -0
  59. package/dist/services/sqlite-client.d.ts +116 -0
  60. package/dist/services/sqlite-client.d.ts.map +1 -0
  61. package/dist/services/sqlite-client.js +284 -0
  62. package/dist/services/tags.d.ts +20 -0
  63. package/dist/services/tags.d.ts.map +1 -0
  64. package/dist/services/tags.js +76 -0
  65. package/dist/services/web-server-lock.d.ts +12 -0
  66. package/dist/services/web-server-lock.d.ts.map +1 -0
  67. package/dist/services/web-server-lock.js +157 -0
  68. package/dist/services/web-server-worker.d.ts +2 -0
  69. package/dist/services/web-server-worker.d.ts.map +1 -0
  70. package/dist/services/web-server-worker.js +221 -0
  71. package/dist/services/web-server.d.ts +22 -0
  72. package/dist/services/web-server.d.ts.map +1 -0
  73. package/dist/services/web-server.js +134 -0
  74. package/dist/types/index.d.ts +48 -0
  75. package/dist/types/index.d.ts.map +1 -0
  76. package/dist/types/index.js +1 -0
  77. package/dist/web/app.d.ts +2 -0
  78. package/dist/web/app.d.ts.map +1 -0
  79. package/dist/web/app.js +691 -0
  80. package/dist/web/favicon.ico +0 -0
  81. package/dist/web/favicon.svg +14 -0
  82. package/dist/web/index.html +202 -0
  83. package/dist/web/styles.css +851 -0
  84. package/package.json +52 -0
@@ -0,0 +1,251 @@
1
+ import { embeddingService } from "./embedding.js";
2
+ import { shardManager } from "./sqlite/shard-manager.js";
3
+ import { vectorSearch } from "./sqlite/vector-search.js";
4
+ import { connectionManager } from "./sqlite/connection-manager.js";
5
+ import { CONFIG } from "../config.js";
6
+ import { log } from "./logger.js";
7
+ function safeToISOString(timestamp) {
8
+ try {
9
+ if (timestamp === null || timestamp === undefined) {
10
+ return new Date().toISOString();
11
+ }
12
+ const numValue = typeof timestamp === "bigint" ? Number(timestamp) : Number(timestamp);
13
+ if (isNaN(numValue) || numValue < 0) {
14
+ return new Date().toISOString();
15
+ }
16
+ return new Date(numValue).toISOString();
17
+ }
18
+ catch {
19
+ return new Date().toISOString();
20
+ }
21
+ }
22
+ function safeJSONParse(jsonString) {
23
+ if (!jsonString || typeof jsonString !== "string") {
24
+ return undefined;
25
+ }
26
+ try {
27
+ return JSON.parse(jsonString);
28
+ }
29
+ catch {
30
+ return undefined;
31
+ }
32
+ }
33
+ function extractScopeFromContainerTag(containerTag) {
34
+ const parts = containerTag.split("_");
35
+ if (parts.length >= 3) {
36
+ const scope = parts[1];
37
+ const hash = parts.slice(2).join("_");
38
+ return { scope, hash };
39
+ }
40
+ return { scope: "user", hash: containerTag };
41
+ }
42
+ export class LocalMemoryClient {
43
+ initPromise = null;
44
+ isInitialized = false;
45
+ constructor() { }
46
+ async initialize() {
47
+ if (this.isInitialized)
48
+ return;
49
+ if (this.initPromise)
50
+ return this.initPromise;
51
+ this.initPromise = (async () => {
52
+ try {
53
+ this.isInitialized = true;
54
+ log("SQLite memory client initialized");
55
+ }
56
+ catch (error) {
57
+ this.initPromise = null;
58
+ log("SQLite initialization failed", { error: String(error) });
59
+ throw error;
60
+ }
61
+ })();
62
+ return this.initPromise;
63
+ }
64
+ async warmup(progressCallback) {
65
+ await this.initialize();
66
+ await embeddingService.warmup(progressCallback);
67
+ }
68
+ async isReady() {
69
+ return this.isInitialized && embeddingService.isWarmedUp;
70
+ }
71
+ getStatus() {
72
+ return {
73
+ dbConnected: this.isInitialized,
74
+ modelLoaded: embeddingService.isWarmedUp,
75
+ ready: this.isInitialized && embeddingService.isWarmedUp,
76
+ };
77
+ }
78
+ async searchMemories(query, containerTag) {
79
+ log("searchMemories: start", { containerTag });
80
+ try {
81
+ await this.initialize();
82
+ const queryVector = await embeddingService.embedWithTimeout(query);
83
+ const { scope, hash } = extractScopeFromContainerTag(containerTag);
84
+ const shards = shardManager.getAllShards(scope, hash);
85
+ if (shards.length === 0) {
86
+ log("searchMemories: no shards found", { containerTag });
87
+ return { success: true, results: [], total: 0, timing: 0 };
88
+ }
89
+ const results = await vectorSearch.searchAcrossShards(shards, queryVector, containerTag, CONFIG.maxMemories, CONFIG.similarityThreshold);
90
+ log("searchMemories: success", { count: results.length });
91
+ return { success: true, results, total: results.length, timing: 0 };
92
+ }
93
+ catch (error) {
94
+ const errorMessage = error instanceof Error ? error.message : String(error);
95
+ log("searchMemories: error", { error: errorMessage });
96
+ return { success: false, error: errorMessage, results: [], total: 0, timing: 0 };
97
+ }
98
+ }
99
+ async getProfile(containerTag, query) {
100
+ log("getProfile: start", { containerTag });
101
+ try {
102
+ await this.initialize();
103
+ const { scope, hash } = extractScopeFromContainerTag(containerTag);
104
+ const shards = shardManager.getAllShards(scope, hash);
105
+ if (shards.length === 0) {
106
+ log("getProfile: no shards found", { containerTag });
107
+ return { success: true, profile: { static: [], dynamic: [] } };
108
+ }
109
+ const staticFacts = [];
110
+ const dynamicFacts = [];
111
+ for (const shard of shards) {
112
+ const db = connectionManager.getConnection(shard.dbPath);
113
+ const memories = vectorSearch.listMemories(db, containerTag, CONFIG.maxProfileItems * 2);
114
+ for (const m of memories) {
115
+ if (m.type === "preference") {
116
+ staticFacts.push(m.content);
117
+ }
118
+ else {
119
+ dynamicFacts.push(m.content);
120
+ }
121
+ }
122
+ }
123
+ const profile = {
124
+ static: staticFacts.slice(0, CONFIG.maxProfileItems),
125
+ dynamic: dynamicFacts.slice(0, CONFIG.maxProfileItems),
126
+ };
127
+ log("getProfile: success", { hasProfile: true });
128
+ return { success: true, profile };
129
+ }
130
+ catch (error) {
131
+ const errorMessage = error instanceof Error ? error.message : String(error);
132
+ log("getProfile: error", { error: errorMessage });
133
+ return { success: false, error: errorMessage, profile: null };
134
+ }
135
+ }
136
+ async addMemory(content, containerTag, metadata) {
137
+ log("addMemory: start", { containerTag, contentLength: content.length });
138
+ try {
139
+ await this.initialize();
140
+ const vector = await embeddingService.embedWithTimeout(content);
141
+ const { scope, hash } = extractScopeFromContainerTag(containerTag);
142
+ const shard = shardManager.getWriteShard(scope, hash);
143
+ const id = `mem_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
144
+ const now = Date.now();
145
+ const { displayName, userName, userEmail, projectPath, projectName, gitRepoUrl, type, ...dynamicMetadata } = metadata || {};
146
+ const record = {
147
+ id,
148
+ content,
149
+ vector,
150
+ containerTag,
151
+ type,
152
+ createdAt: now,
153
+ updatedAt: now,
154
+ displayName,
155
+ userName,
156
+ userEmail,
157
+ projectPath,
158
+ projectName,
159
+ gitRepoUrl,
160
+ metadata: Object.keys(dynamicMetadata).length > 0 ? JSON.stringify(dynamicMetadata) : undefined,
161
+ };
162
+ const db = connectionManager.getConnection(shard.dbPath);
163
+ vectorSearch.insertVector(db, record);
164
+ shardManager.incrementVectorCount(shard.id);
165
+ log("addMemory: success", { id, shardId: shard.id });
166
+ return { success: true, id };
167
+ }
168
+ catch (error) {
169
+ const errorMessage = error instanceof Error ? error.message : String(error);
170
+ log("addMemory: error", { error: errorMessage });
171
+ return { success: false, error: errorMessage };
172
+ }
173
+ }
174
+ async deleteMemory(memoryId) {
175
+ log("deleteMemory: start", { memoryId });
176
+ try {
177
+ await this.initialize();
178
+ const { scope, hash } = extractScopeFromContainerTag(memoryId);
179
+ const shards = shardManager.getAllShards(scope, hash);
180
+ for (const shard of shards) {
181
+ const db = connectionManager.getConnection(shard.dbPath);
182
+ const memory = vectorSearch.getMemoryById(db, memoryId);
183
+ if (memory) {
184
+ vectorSearch.deleteVector(db, memoryId);
185
+ shardManager.decrementVectorCount(shard.id);
186
+ log("deleteMemory: success", { memoryId, shardId: shard.id });
187
+ return { success: true };
188
+ }
189
+ }
190
+ log("deleteMemory: not found", { memoryId });
191
+ return { success: false, error: "Memory not found" };
192
+ }
193
+ catch (error) {
194
+ const errorMessage = error instanceof Error ? error.message : String(error);
195
+ log("deleteMemory: error", { memoryId, error: errorMessage });
196
+ return { success: false, error: errorMessage };
197
+ }
198
+ }
199
+ async listMemories(containerTag, limit = 20) {
200
+ log("listMemories: start", { containerTag, limit });
201
+ try {
202
+ await this.initialize();
203
+ const { scope, hash } = extractScopeFromContainerTag(containerTag);
204
+ const shards = shardManager.getAllShards(scope, hash);
205
+ if (shards.length === 0) {
206
+ log("listMemories: no shards found", { containerTag });
207
+ return {
208
+ success: true,
209
+ memories: [],
210
+ pagination: { currentPage: 1, totalItems: 0, totalPages: 0 },
211
+ };
212
+ }
213
+ const allMemories = [];
214
+ for (const shard of shards) {
215
+ const db = connectionManager.getConnection(shard.dbPath);
216
+ const memories = vectorSearch.listMemories(db, containerTag, limit);
217
+ allMemories.push(...memories);
218
+ }
219
+ allMemories.sort((a, b) => Number(b.created_at) - Number(a.created_at));
220
+ const memories = allMemories.slice(0, limit).map((r) => ({
221
+ id: r.id,
222
+ summary: r.content,
223
+ createdAt: safeToISOString(r.created_at),
224
+ metadata: safeJSONParse(r.metadata),
225
+ displayName: r.display_name,
226
+ userName: r.user_name,
227
+ userEmail: r.user_email,
228
+ projectPath: r.project_path,
229
+ projectName: r.project_name,
230
+ gitRepoUrl: r.git_repo_url,
231
+ }));
232
+ log("listMemories: success", { count: memories.length });
233
+ return {
234
+ success: true,
235
+ memories,
236
+ pagination: { currentPage: 1, totalItems: memories.length, totalPages: 1 },
237
+ };
238
+ }
239
+ catch (error) {
240
+ const errorMessage = error instanceof Error ? error.message : String(error);
241
+ log("listMemories: error", { error: errorMessage });
242
+ return {
243
+ success: false,
244
+ error: errorMessage,
245
+ memories: [],
246
+ pagination: { currentPage: 1, totalItems: 0, totalPages: 0 },
247
+ };
248
+ }
249
+ }
250
+ }
251
+ export const memoryClient = new LocalMemoryClient();
@@ -0,0 +1,92 @@
1
+ interface TokenInfo {
2
+ input: number;
3
+ output: number;
4
+ cache: {
5
+ read: number;
6
+ write: number;
7
+ };
8
+ }
9
+ interface MessageInfo {
10
+ id: string;
11
+ role: string;
12
+ sessionID: string;
13
+ providerID?: string;
14
+ modelID?: string;
15
+ tokens?: TokenInfo;
16
+ summary?: boolean;
17
+ finish?: boolean;
18
+ }
19
+ export interface CompactionOptions {
20
+ threshold?: number;
21
+ getModelLimit?: (providerID: string, modelID: string) => number | undefined;
22
+ }
23
+ export interface CompactionContext {
24
+ directory: string;
25
+ client: {
26
+ session: {
27
+ summarize: (params: {
28
+ path: {
29
+ id: string;
30
+ };
31
+ body: {
32
+ providerID: string;
33
+ modelID: string;
34
+ };
35
+ query: {
36
+ directory: string;
37
+ };
38
+ }) => Promise<unknown>;
39
+ messages: (params: {
40
+ path: {
41
+ id: string;
42
+ };
43
+ query: {
44
+ directory: string;
45
+ };
46
+ }) => Promise<{
47
+ data?: Array<{
48
+ info: MessageInfo;
49
+ }>;
50
+ }>;
51
+ promptAsync: (params: {
52
+ path: {
53
+ id: string;
54
+ };
55
+ body: {
56
+ agent?: string;
57
+ parts: Array<{
58
+ type: string;
59
+ text: string;
60
+ }>;
61
+ };
62
+ query: {
63
+ directory: string;
64
+ };
65
+ }) => Promise<unknown>;
66
+ };
67
+ tui: {
68
+ showToast: (params: {
69
+ body: {
70
+ title: string;
71
+ message: string;
72
+ variant: string;
73
+ duration: number;
74
+ };
75
+ }) => Promise<unknown>;
76
+ };
77
+ };
78
+ }
79
+ export declare function createCompactionHook(ctx: CompactionContext, tags: {
80
+ user: string;
81
+ project: string;
82
+ }, options?: CompactionOptions): {
83
+ compactionTracker: Map<string, number>;
84
+ event({ event }: {
85
+ event: {
86
+ type: string;
87
+ properties?: unknown;
88
+ };
89
+ }): Promise<void>;
90
+ };
91
+ export {};
92
+ //# sourceMappingURL=compaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../src/services/compaction.ts"],"names":[],"mappings":"AAsBA,UAAU,SAAS;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAgBD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CAC7E;AAuLD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE;QACN,OAAO,EAAE;YACP,SAAS,EAAE,CAAC,MAAM,EAAE;gBAAE,IAAI,EAAE;oBAAE,EAAE,EAAE,MAAM,CAAA;iBAAE,CAAC;gBAAC,IAAI,EAAE;oBAAE,UAAU,EAAE,MAAM,CAAC;oBAAC,OAAO,EAAE,MAAM,CAAA;iBAAE,CAAC;gBAAC,KAAK,EAAE;oBAAE,SAAS,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;YAC/I,QAAQ,EAAE,CAAC,MAAM,EAAE;gBAAE,IAAI,EAAE;oBAAE,EAAE,EAAE,MAAM,CAAA;iBAAE,CAAC;gBAAC,KAAK,EAAE;oBAAE,SAAS,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,KAAK,OAAO,CAAC;gBAAE,IAAI,CAAC,EAAE,KAAK,CAAC;oBAAE,IAAI,EAAE,WAAW,CAAA;iBAAE,CAAC,CAAA;aAAE,CAAC,CAAC;YAC/H,WAAW,EAAE,CAAC,MAAM,EAAE;gBAAE,IAAI,EAAE;oBAAE,EAAE,EAAE,MAAM,CAAA;iBAAE,CAAC;gBAAC,IAAI,EAAE;oBAAE,KAAK,CAAC,EAAE,MAAM,CAAC;oBAAC,KAAK,EAAE,KAAK,CAAC;wBAAE,IAAI,EAAE,MAAM,CAAC;wBAAC,IAAI,EAAE,MAAM,CAAA;qBAAE,CAAC,CAAA;iBAAE,CAAC;gBAAC,KAAK,EAAE;oBAAE,SAAS,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;SAC3K,CAAC;QACF,GAAG,EAAE;YACH,SAAS,EAAE,CAAC,MAAM,EAAE;gBAAE,IAAI,EAAE;oBAAE,KAAK,EAAE,MAAM,CAAC;oBAAC,OAAO,EAAE,MAAM,CAAC;oBAAC,OAAO,EAAE,MAAM,CAAC;oBAAC,QAAQ,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;SAC1H,CAAC;KACH,CAAC;CACH;AAED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EACvC,OAAO,CAAC,EAAE,iBAAiB;;qBAsOF;QAAE,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE;EAgE3E"}