@melandlabs/memory-store 0.1.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 (46) hide show
  1. package/LICENSE +17 -0
  2. package/README.md +377 -0
  3. package/dist/config-MlK9f9CM.d.ts +147 -0
  4. package/dist/contracts.d.ts +62 -0
  5. package/dist/contracts.js +27 -0
  6. package/dist/contracts.js.map +1 -0
  7. package/dist/http.d.ts +38 -0
  8. package/dist/http.js +545 -0
  9. package/dist/http.js.map +1 -0
  10. package/dist/index.d.ts +35 -0
  11. package/dist/index.js +442 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/mcp.d.ts +29 -0
  14. package/dist/mcp.js +589 -0
  15. package/dist/mcp.js.map +1 -0
  16. package/dist/policies/memory-graph-correction-policy.d.ts +14 -0
  17. package/dist/policies/memory-graph-correction-policy.js +41 -0
  18. package/dist/policies/memory-graph-correction-policy.js.map +1 -0
  19. package/dist/policies/memory-graph-write-policy.d.ts +35 -0
  20. package/dist/policies/memory-graph-write-policy.js +78 -0
  21. package/dist/policies/memory-graph-write-policy.js.map +1 -0
  22. package/dist/search/unified-search.d.ts +81 -0
  23. package/dist/search/unified-search.js +399 -0
  24. package/dist/search/unified-search.js.map +1 -0
  25. package/dist/server/cli-http.d.ts +1 -0
  26. package/dist/server/cli-http.js +584 -0
  27. package/dist/server/cli-http.js.map +1 -0
  28. package/dist/server/cli-mcp.d.ts +1 -0
  29. package/dist/server/cli-mcp.js +603 -0
  30. package/dist/server/cli-mcp.js.map +1 -0
  31. package/dist/storage/chroma-memory-index.d.ts +76 -0
  32. package/dist/storage/chroma-memory-index.js +249 -0
  33. package/dist/storage/chroma-memory-index.js.map +1 -0
  34. package/dist/storage/postgres-raw-message-factory.d.ts +48 -0
  35. package/dist/storage/postgres-raw-message-factory.js +19 -0
  36. package/dist/storage/postgres-raw-message-factory.js.map +1 -0
  37. package/dist/storage/raw-message-store.d.ts +47 -0
  38. package/dist/storage/raw-message-store.js +140 -0
  39. package/dist/storage/raw-message-store.js.map +1 -0
  40. package/dist/storage/sqlite-raw-message-store.d.ts +19 -0
  41. package/dist/storage/sqlite-raw-message-store.js +68 -0
  42. package/dist/storage/sqlite-raw-message-store.js.map +1 -0
  43. package/dist/storage/sqlite-vector-index.d.ts +42 -0
  44. package/dist/storage/sqlite-vector-index.js +92 -0
  45. package/dist/storage/sqlite-vector-index.js.map +1 -0
  46. package/package.json +87 -0
@@ -0,0 +1,584 @@
1
+ #!/usr/bin/env node
2
+ import { serve } from '@hono/node-server';
3
+ import { Hono } from 'hono';
4
+ import { buildMemoryRecordEmbeddingDocument } from '@melandlabs/ai/memory';
5
+ import { ChromaVectorStore } from '@melandlabs/rag';
6
+ import { mkdirSync } from 'fs';
7
+ import { dirname } from 'path';
8
+ import { SQLiteRawMessageManager } from '@melandlabs/sqlite';
9
+
10
+ // src/contracts.ts
11
+ function normalizeTimestampToMs(value) {
12
+ if (!Number.isFinite(value)) {
13
+ return 0;
14
+ }
15
+ if (value < 1e11) {
16
+ return Math.floor(value * 1e3);
17
+ }
18
+ return Math.floor(value);
19
+ }
20
+ function rawMessageToMemoryRecord(message) {
21
+ return {
22
+ id: message.messageId,
23
+ userId: message.userId,
24
+ timestamp: normalizeTimestampToMs(message.timestamp),
25
+ text: message.archivedAt ? void 0 : message.content,
26
+ mediaRefs: message.attachments?.map((item) => item.url).filter(Boolean),
27
+ embedding: message.embedding,
28
+ embeddingModel: message.embeddingModel,
29
+ embeddingContentHash: message.embeddingContentHash
30
+ };
31
+ }
32
+
33
+ // src/storage/chroma-memory-index.ts
34
+ var DEFAULT_RAW_MESSAGES_COLLECTION = "opencontext_raw_messages";
35
+ var RAW_VECTOR_BACKEND_ENV_KEYS = [
36
+ "RAW_MESSAGE_VECTOR_STORE_BACKEND",
37
+ "MEMORY_VECTOR_STORE_BACKEND",
38
+ "VECTOR_STORE_BACKEND"
39
+ ];
40
+ function getBackend(keys) {
41
+ for (const key of keys) {
42
+ const value = process.env[key]?.trim().toLowerCase();
43
+ if (value) {
44
+ return value;
45
+ }
46
+ }
47
+ return "";
48
+ }
49
+ function isRawMessageChromaEnabled() {
50
+ return getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === "chroma";
51
+ }
52
+ function getRawMessagesCollectionName() {
53
+ return process.env.CHROMA_RAW_MESSAGES_COLLECTION || process.env.CHROMA_MEMORY_COLLECTION || DEFAULT_RAW_MESSAGES_COLLECTION;
54
+ }
55
+ function getChromaStore(collectionName) {
56
+ return new ChromaVectorStore({
57
+ url: process.env.CHROMA_URL,
58
+ collectionName
59
+ });
60
+ }
61
+ function normalizeTimestampToMs2(value) {
62
+ if (!Number.isFinite(value)) {
63
+ return 0;
64
+ }
65
+ if (value < 1e11) {
66
+ return Math.floor(value * 1e3);
67
+ }
68
+ return Math.floor(value);
69
+ }
70
+ function toBooleanValue(value) {
71
+ return value === true || value === "true" || value === 1 || value === "1";
72
+ }
73
+ function rawMessageToChunk(message) {
74
+ if (!message.embedding || message.embedding.length === 0) {
75
+ return null;
76
+ }
77
+ const record = rawMessageToMemoryRecord(message);
78
+ const document = buildMemoryRecordEmbeddingDocument(record);
79
+ if (!document.content) {
80
+ return null;
81
+ }
82
+ return {
83
+ id: message.messageId,
84
+ documentId: message.messageId,
85
+ content: document.content,
86
+ embedding: message.embedding,
87
+ metadata: {
88
+ sourceType: "raw_message",
89
+ userId: message.userId,
90
+ platform: message.platform,
91
+ botId: message.botId,
92
+ channel: message.channel,
93
+ person: message.person,
94
+ timestamp: normalizeTimestampToMs2(message.timestamp),
95
+ memoryStage: message.memoryStage,
96
+ embeddingModel: message.embeddingModel,
97
+ embeddingDimensions: message.embeddingDimensions,
98
+ contentHash: message.embeddingContentHash,
99
+ archived: Boolean(message.archivedAt),
100
+ role: typeof message.metadata?.role === "string" ? message.metadata.role : void 0
101
+ }
102
+ };
103
+ }
104
+ async function upsertRawMessagesToChroma(messages) {
105
+ if (!isRawMessageChromaEnabled() || messages.length === 0) {
106
+ return 0;
107
+ }
108
+ const chunks = messages.map(rawMessageToChunk).filter((chunk) => chunk !== null);
109
+ if (chunks.length === 0) {
110
+ return 0;
111
+ }
112
+ const store = getChromaStore(getRawMessagesCollectionName());
113
+ await store.addChunks(chunks);
114
+ return chunks.length;
115
+ }
116
+ async function searchRawMessagesWithChroma(input) {
117
+ if (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {
118
+ return [];
119
+ }
120
+ const store = getChromaStore(getRawMessagesCollectionName());
121
+ const results = await store.similaritySearch(
122
+ input.queryEmbedding,
123
+ Math.max(input.limit * 5, input.limit),
124
+ input.userId
125
+ );
126
+ return results.filter((result) => {
127
+ const metadata = result.metadata ?? {};
128
+ if (toBooleanValue(metadata.archived)) {
129
+ return false;
130
+ }
131
+ if (input.botId && metadata.botId !== input.botId) {
132
+ return false;
133
+ }
134
+ return result.score >= input.threshold;
135
+ }).map((result) => ({
136
+ id: result.id,
137
+ content: result.content,
138
+ similarity: result.score,
139
+ metadata: result.metadata ?? {}
140
+ })).slice(0, input.limit);
141
+ }
142
+
143
+ // src/storage/postgres-raw-message-factory.ts
144
+ var factory = null;
145
+ async function resolvePostgresFactory(env) {
146
+ return null;
147
+ }
148
+ function hasPostgresFactory() {
149
+ return factory !== null;
150
+ }
151
+ var manager = null;
152
+ function isSQLiteRawMessageStorageAvailable(env) {
153
+ return resolveEnv(env).isTauriMode();
154
+ }
155
+ async function getSQLiteRawMessageManager(env) {
156
+ const e = resolveEnv(env);
157
+ if (!e.isTauriMode()) {
158
+ throw new Error("SQLite raw message storage is only available in Tauri mode.");
159
+ }
160
+ if (!manager) {
161
+ const dbPath = e.getTauriDbPath?.() ?? process.env.TAURI_DB_PATH ?? "";
162
+ mkdirSync(dirname(dbPath), { recursive: true });
163
+ manager = new SQLiteRawMessageManager({
164
+ dbPath,
165
+ enableVectorSearch: !isRawMessageChromaEnabled()
166
+ });
167
+ await manager.init();
168
+ }
169
+ return manager;
170
+ }
171
+ async function closeSQLiteRawMessageManager() {
172
+ if (!manager) {
173
+ return;
174
+ }
175
+ await manager.close();
176
+ manager = null;
177
+ }
178
+ function resolveEnv(env) {
179
+ if (env) return env;
180
+ return {
181
+ isTauriMode: () => process.env.IS_TAURI === "true" || typeof process.env.TAURI_MODE === "string",
182
+ getTauriDbPath: () => process.env.TAURI_DB_PATH ?? "",
183
+ getTauriDataDir: () => process.env.TAURI_DATA_DIR ?? ""
184
+ };
185
+ }
186
+
187
+ // src/storage/raw-message-store.ts
188
+ function resolveEnv2(env) {
189
+ if (env) return env;
190
+ return {
191
+ isTauriMode: () => process.env.IS_TAURI === "true" || typeof process.env.TAURI_MODE === "string",
192
+ getTauriDbPath: () => process.env.TAURI_DB_PATH ?? "",
193
+ getTauriDataDir: () => process.env.TAURI_DATA_DIR ?? ""
194
+ };
195
+ }
196
+ function createRawMessageStore(options = {}) {
197
+ const env = resolveEnv2(options.env);
198
+ return {
199
+ getBackend() {
200
+ return isSQLiteRawMessageStorageAvailable(env) ? "sqlite" : "postgres";
201
+ },
202
+ isAvailable() {
203
+ return isSQLiteRawMessageStorageAvailable(env) || hasPostgresFactory();
204
+ },
205
+ async getManager() {
206
+ if (isSQLiteRawMessageStorageAvailable(env)) {
207
+ return await getSQLiteRawMessageManager(env);
208
+ }
209
+ const pg = await resolvePostgresFactory();
210
+ if (!pg) {
211
+ throw new Error(
212
+ "No raw-message backend available. SQLite is disabled (not Tauri) and no Postgres factory is registered."
213
+ );
214
+ }
215
+ return pg;
216
+ },
217
+ async close() {
218
+ if (isSQLiteRawMessageStorageAvailable(env)) {
219
+ await closeSQLiteRawMessageManager();
220
+ }
221
+ }
222
+ };
223
+ }
224
+ var moduleStore = null;
225
+ var moduleConfig = null;
226
+ function isRawMessageStorageAvailable() {
227
+ if (!moduleStore) {
228
+ moduleStore = createRawMessageStore({ env: moduleConfig?.env });
229
+ }
230
+ return moduleStore.isAvailable();
231
+ }
232
+
233
+ // src/search/utilities.ts
234
+ var DEFAULT_LIMIT = 10;
235
+ var DEFAULT_THRESHOLD = 0.7;
236
+ var DEFAULT_SOURCES = ["memory", "insights", "knowledge"];
237
+ var SOURCE_SET = new Set(DEFAULT_SOURCES);
238
+ function normalizeUnifiedMemorySearchSources(sources) {
239
+ if (!Array.isArray(sources) || sources.length === 0) {
240
+ return [...DEFAULT_SOURCES];
241
+ }
242
+ const normalized = sources.filter((source) => typeof source === "string").map((source) => source.trim().toLowerCase()).filter(
243
+ (source) => SOURCE_SET.has(source)
244
+ );
245
+ return normalized.length > 0 ? Array.from(new Set(normalized)) : [...DEFAULT_SOURCES];
246
+ }
247
+ function clampUnifiedMemorySearchLimit(limit) {
248
+ const parsed = typeof limit === "number" ? limit : Number(limit ?? DEFAULT_LIMIT);
249
+ if (!Number.isFinite(parsed)) {
250
+ return DEFAULT_LIMIT;
251
+ }
252
+ return Math.min(50, Math.max(1, Math.floor(parsed)));
253
+ }
254
+ function clampUnifiedMemorySearchThreshold(threshold) {
255
+ const parsed = typeof threshold === "number" ? threshold : Number(threshold ?? DEFAULT_THRESHOLD);
256
+ if (!Number.isFinite(parsed)) {
257
+ return DEFAULT_THRESHOLD;
258
+ }
259
+ return Math.min(1, Math.max(-1, parsed));
260
+ }
261
+ function mergeUnifiedMemorySearchResults(results, limit) {
262
+ return [...results].sort((a, b) => {
263
+ const scoreDelta = b.similarity - a.similarity;
264
+ if (scoreDelta !== 0) {
265
+ return scoreDelta;
266
+ }
267
+ return a.type.localeCompare(b.type) || a.id.localeCompare(b.id);
268
+ }).slice(0, limit);
269
+ }
270
+ function toKnowledgeResult(result) {
271
+ return {
272
+ type: "knowledge",
273
+ id: result.chunkId,
274
+ content: result.content,
275
+ similarity: result.similarity,
276
+ metadata: {
277
+ documentId: result.documentId,
278
+ documentName: result.documentName,
279
+ chunkIndex: result.chunkIndex
280
+ }
281
+ };
282
+ }
283
+ function toMemoryResult(result) {
284
+ return {
285
+ type: "memory",
286
+ id: result.id,
287
+ content: result.content,
288
+ similarity: result.similarity,
289
+ metadata: result.metadata
290
+ };
291
+ }
292
+ function isRawMemorySemanticResult(result) {
293
+ if (!result || typeof result !== "object") {
294
+ return false;
295
+ }
296
+ const item = result;
297
+ return typeof item.id === "string" && typeof item.content === "string" && typeof item.similarity === "number" && Boolean(item.metadata) && typeof item.metadata === "object";
298
+ }
299
+
300
+ // src/search/unified-search.ts
301
+ function createUnifiedSearch(deps = {}) {
302
+ const logger = deps.logger ?? console;
303
+ async function searchUnifiedMemory(input) {
304
+ const query = input.query.trim();
305
+ const sources = normalizeUnifiedMemorySearchSources(input.sources);
306
+ const limit = clampUnifiedMemorySearchLimit(input.limit);
307
+ const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
308
+ const warnings = [];
309
+ const results = [];
310
+ if (!query) {
311
+ return {
312
+ query,
313
+ sources,
314
+ results: [],
315
+ count: 0,
316
+ warnings
317
+ };
318
+ }
319
+ if (sources.includes("memory")) {
320
+ if (isRawMessageStorageAvailable()) {
321
+ try {
322
+ const memoryHits = await runMemorySource(input, limit, threshold);
323
+ results.push(...memoryHits);
324
+ } catch (error) {
325
+ logger.warn?.("[memory-store] memory source failed:", error);
326
+ warnings.push({
327
+ source: "memory",
328
+ code: "memory_search_failed",
329
+ message: error.message ?? "memory_search_failed"
330
+ });
331
+ }
332
+ } else {
333
+ warnings.push({
334
+ source: "memory",
335
+ code: "raw_message_storage_unavailable",
336
+ message: "Raw memory storage is not available in this environment."
337
+ });
338
+ }
339
+ }
340
+ if (sources.includes("insights") && typeof deps.searchInsights === "function") {
341
+ try {
342
+ const insightHits = await deps.searchInsights({
343
+ userId: input.userId,
344
+ query: input.query,
345
+ limit,
346
+ threshold,
347
+ botIds: input.botIds,
348
+ includeArchived: input.includeArchivedInsights,
349
+ authToken: input.authToken
350
+ });
351
+ for (const hit of insightHits) {
352
+ results.push({
353
+ type: "insight",
354
+ id: hit.id,
355
+ content: hit.content,
356
+ similarity: hit.similarity,
357
+ metadata: hit.metadata
358
+ });
359
+ }
360
+ } catch (error) {
361
+ logger.warn?.("[memory-store] insights source failed:", error);
362
+ warnings.push({
363
+ source: "insights",
364
+ code: "insights_search_failed",
365
+ message: error.message ?? "insights_search_failed"
366
+ });
367
+ }
368
+ } else if (sources.includes("insights")) {
369
+ warnings.push({
370
+ source: "insights",
371
+ code: "insights_search_not_configured",
372
+ message: "Insights search is not configured for this host."
373
+ });
374
+ }
375
+ if (sources.includes("knowledge") && typeof deps.searchKnowledge === "function") {
376
+ try {
377
+ const knowledgeHits = await deps.searchKnowledge({
378
+ userId: input.userId,
379
+ query: input.query,
380
+ options: {
381
+ limit,
382
+ threshold,
383
+ documentIds: input.documentIds
384
+ },
385
+ authToken: input.authToken
386
+ });
387
+ for (const hit of knowledgeHits) {
388
+ results.push(toKnowledgeResult(hit));
389
+ }
390
+ } catch (error) {
391
+ logger.warn?.("[memory-store] knowledge source failed:", error);
392
+ warnings.push({
393
+ source: "knowledge",
394
+ code: "knowledge_search_failed",
395
+ message: error.message ?? "knowledge_search_failed"
396
+ });
397
+ }
398
+ } else if (sources.includes("knowledge")) {
399
+ warnings.push({
400
+ source: "knowledge",
401
+ code: "knowledge_search_not_configured",
402
+ message: "Knowledge search is not configured for this host."
403
+ });
404
+ }
405
+ const merged = mergeUnifiedMemorySearchResults(results, limit);
406
+ return {
407
+ query: input.query,
408
+ sources,
409
+ results: merged,
410
+ count: merged.length,
411
+ warnings
412
+ };
413
+ }
414
+ async function runMemorySource(input, limit, threshold) {
415
+ if (typeof deps.embedQuery !== "function") {
416
+ throw new Error("embedQuery is not configured");
417
+ }
418
+ const queryEmbedding = await deps.embedQuery({
419
+ userId: input.userId,
420
+ query: input.query,
421
+ authToken: input.authToken
422
+ });
423
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];
424
+ if (isRawMessageChromaEnabled()) {
425
+ try {
426
+ const chromaHits = (await Promise.all(
427
+ filters.map((filter) => {
428
+ const botId = "botId" in filter ? filter.botId : void 0;
429
+ return searchRawMessagesWithChroma({
430
+ userId: input.userId,
431
+ queryEmbedding,
432
+ limit,
433
+ threshold,
434
+ botId
435
+ });
436
+ })
437
+ )).flat().map(toMemoryResult);
438
+ logger.log?.("[memory-store] Raw message semantic search completed", {
439
+ backend: "chroma",
440
+ dimensions: queryEmbedding.length,
441
+ count: chromaHits.length
442
+ });
443
+ return chromaHits;
444
+ } catch (error) {
445
+ logger.warn?.(
446
+ "[memory-store] Chroma raw message search failed; falling back to database search:",
447
+ error
448
+ );
449
+ }
450
+ }
451
+ if (typeof deps.searchRawMessagesAnn === "function") {
452
+ const rows = (await Promise.all(
453
+ filters.map(
454
+ (filter) => deps.searchRawMessagesAnn({
455
+ userId: input.userId,
456
+ queryEmbedding,
457
+ limit,
458
+ threshold,
459
+ botId: "botId" in filter ? filter.botId : void 0
460
+ })
461
+ )
462
+ )).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
463
+ return rows;
464
+ }
465
+ return [];
466
+ }
467
+ async function searchRawMemorySemantically(input) {
468
+ const limit = clampUnifiedMemorySearchLimit(input.limit);
469
+ const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
470
+ return runMemorySource(input, limit, threshold);
471
+ }
472
+ return { searchUnifiedMemory, searchRawMemorySemantically };
473
+ }
474
+
475
+ // src/http.ts
476
+ async function startHttpServer(options = {}) {
477
+ const port = options.port ?? Number.parseInt(process.env.MEMORY_HTTP_PORT ?? "7421", 10);
478
+ const host = options.host ?? process.env.MEMORY_HTTP_HOST ?? "127.0.0.1";
479
+ const rawStore = createRawMessageStore({
480
+ env: options.env
481
+ });
482
+ const search = createUnifiedSearch(options.unified);
483
+ const app = new Hono();
484
+ app.get("/health", (c) => c.json({ ok: true, store: "memory", ts: Date.now() }));
485
+ app.post("/v1/search", async (c) => {
486
+ const body = await c.req.json().catch(() => ({}));
487
+ const userId = typeof body.userId === "string" ? body.userId : null;
488
+ const query = typeof body.query === "string" ? body.query : "";
489
+ if (!userId || !query) {
490
+ return c.json({ error: "userId and query are required" }, 400);
491
+ }
492
+ const result = await search.searchUnifiedMemory({
493
+ userId,
494
+ query,
495
+ sources: body.sources,
496
+ limit: body.limit,
497
+ threshold: body.threshold,
498
+ botIds: body.botIds,
499
+ documentIds: body.documentIds,
500
+ includeArchivedInsights: body.includeArchivedInsights,
501
+ authToken: body.authToken
502
+ });
503
+ return c.json(result);
504
+ });
505
+ app.post("/v1/raw-messages", async (c) => {
506
+ const body = await c.req.json().catch(() => ({}));
507
+ if (!Array.isArray(body.messages) || !body.userId) {
508
+ return c.json({ error: "userId and messages[] required" }, 400);
509
+ }
510
+ const manager2 = await rawStore.getManager();
511
+ const result = await manager2.upsertRawMessages?.({
512
+ userId: body.userId,
513
+ messages: body.messages
514
+ });
515
+ try {
516
+ await upsertRawMessagesToChroma(body.messages);
517
+ } catch (error) {
518
+ console.warn("[memory-store/http] chroma upsert failed:", error);
519
+ }
520
+ return c.json({ ok: true, result });
521
+ });
522
+ app.get("/v1/raw-messages/:id", async (c) => {
523
+ const id = c.req.param("id");
524
+ const userId = c.req.query("userId");
525
+ if (!userId) return c.json({ error: "userId query param required" }, 400);
526
+ const manager2 = await rawStore.getManager();
527
+ const row = await manager2.getMessageById?.(id);
528
+ if (!row) return c.json({ error: "not found" }, 404);
529
+ return c.json({ message: row });
530
+ });
531
+ const server = serve({ fetch: app.fetch, port, hostname: host });
532
+ return {
533
+ url: `http://${host}:${port}`,
534
+ port,
535
+ async stop() {
536
+ await rawStore.close();
537
+ server.close();
538
+ }
539
+ };
540
+ }
541
+
542
+ // src/server/cli-http.ts
543
+ function parseArgs(argv) {
544
+ const args = {
545
+ port: Number.parseInt(process.env.MEMORY_HTTP_PORT ?? "7421", 10),
546
+ host: process.env.MEMORY_HTTP_HOST ?? "127.0.0.1"
547
+ };
548
+ for (let i = 0; i < argv.length; i += 1) {
549
+ const arg = argv[i];
550
+ const next = argv[i + 1];
551
+ if (arg === "--port" && next) {
552
+ args.port = Number.parseInt(next, 10);
553
+ i += 1;
554
+ } else if (arg === "--host" && next) {
555
+ args.host = next;
556
+ i += 1;
557
+ } else if (arg === "--help" || arg === "-h") {
558
+ console.log("Usage: opencontext-memory-http [--port <port>] [--host <host>]");
559
+ process.exit(0);
560
+ }
561
+ }
562
+ return args;
563
+ }
564
+ async function main() {
565
+ const args = parseArgs(process.argv.slice(2));
566
+ const { url, port, stop } = await startHttpServer({
567
+ port: args.port,
568
+ host: args.host
569
+ });
570
+ console.log(`[memory-store/http] listening at ${url}`);
571
+ const shutdown = async (signal) => {
572
+ console.log(`[memory-store/http] ${signal} received, shutting down\u2026`);
573
+ await stop();
574
+ process.exit(0);
575
+ };
576
+ process.once("SIGINT", shutdown);
577
+ process.once("SIGTERM", shutdown);
578
+ }
579
+ main().catch((error) => {
580
+ console.error("[memory-store/http] fatal:", error);
581
+ process.exit(1);
582
+ });
583
+ //# sourceMappingURL=cli-http.js.map
584
+ //# sourceMappingURL=cli-http.js.map