@memrosetta/cli 0.5.0 → 0.5.2

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 (57) hide show
  1. package/dist/chunk-47SU2YUJ.js +64 -0
  2. package/dist/chunk-4LNXT25H.js +891 -0
  3. package/dist/chunk-C4ANKSCI.js +151 -0
  4. package/dist/chunk-CEHRM6IW.js +151 -0
  5. package/dist/chunk-G2W4YK2T.js +56 -0
  6. package/dist/chunk-GGXC7TAJ.js +139 -0
  7. package/dist/chunk-GRNZVSAF.js +56 -0
  8. package/dist/chunk-GZINXXM4.js +139 -0
  9. package/dist/chunk-RZFCVYTK.js +71 -0
  10. package/dist/chunk-US6CEDMU.js +66 -0
  11. package/dist/chunk-VMGX5FCY.js +64 -0
  12. package/dist/chunk-WYHEAKPC.js +71 -0
  13. package/dist/clear-32Y3U2WR.js +39 -0
  14. package/dist/clear-AFEJPCDA.js +39 -0
  15. package/dist/compress-CL5D4VVJ.js +33 -0
  16. package/dist/compress-UUEO7WCU.js +33 -0
  17. package/dist/count-U2ML5ZON.js +24 -0
  18. package/dist/count-VVOGYSM7.js +24 -0
  19. package/dist/duplicates-CEJ7WSGW.js +149 -0
  20. package/dist/duplicates-IBUS7CJS.js +149 -0
  21. package/dist/enforce-T7AS4PVD.js +381 -0
  22. package/dist/enforce-TC5SDPEZ.js +381 -0
  23. package/dist/feedback-3PJTTEOD.js +51 -0
  24. package/dist/feedback-IB7BHIRP.js +51 -0
  25. package/dist/get-TQ2U7HCD.js +30 -0
  26. package/dist/get-WPZIHQKW.js +30 -0
  27. package/dist/hooks/enforce-codex.js +88 -0
  28. package/dist/hooks/on-prompt.js +3 -3
  29. package/dist/hooks/on-stop.js +3 -3
  30. package/dist/index.js +30 -20
  31. package/dist/ingest-37UXPVT5.js +97 -0
  32. package/dist/ingest-TPQRH34A.js +97 -0
  33. package/dist/init-6YQL3RCQ.js +210 -0
  34. package/dist/init-ISP73KEC.js +210 -0
  35. package/dist/init-LHXRCCLX.js +210 -0
  36. package/dist/invalidate-ER2TFFWK.js +40 -0
  37. package/dist/invalidate-PVHUGAJ6.js +40 -0
  38. package/dist/maintain-NICAXFK6.js +37 -0
  39. package/dist/maintain-Q553GBSF.js +37 -0
  40. package/dist/migrate-CZL3YNQK.js +255 -0
  41. package/dist/migrate-FI26FSBP.js +255 -0
  42. package/dist/relate-5TN2WEG3.js +57 -0
  43. package/dist/relate-KLBMYWB3.js +57 -0
  44. package/dist/reset-IPOAKTJM.js +132 -0
  45. package/dist/reset-P62B444X.js +132 -0
  46. package/dist/search-AYZBKRXF.js +48 -0
  47. package/dist/search-JQ3MLRKS.js +48 -0
  48. package/dist/status-FWHUUZ4R.js +184 -0
  49. package/dist/status-JF2V7ZBX.js +184 -0
  50. package/dist/status-UV66PWUD.js +184 -0
  51. package/dist/store-AAJCT3PX.js +101 -0
  52. package/dist/store-OVDS57U5.js +101 -0
  53. package/dist/sync-56KJTKE7.js +542 -0
  54. package/dist/sync-BCKBYRXY.js +542 -0
  55. package/dist/working-memory-CJARSGEK.js +53 -0
  56. package/dist/working-memory-Z3RUGSTQ.js +53 -0
  57. package/package.json +6 -5
@@ -0,0 +1,151 @@
1
+ import {
2
+ resolveCanonicalUserId
3
+ } from "./chunk-RZFCVYTK.js";
4
+
5
+ // src/hooks/memory-extractor.ts
6
+ var KEYWORD_PATTERNS = {
7
+ typescript: "TypeScript",
8
+ sqlite: "SQLite",
9
+ api: "API",
10
+ benchmark: "benchmark",
11
+ docker: "Docker",
12
+ git: "Git",
13
+ react: "React",
14
+ hono: "Hono",
15
+ test: "test",
16
+ deploy: "deploy",
17
+ refactor: "refactor",
18
+ bug: "bug",
19
+ memrosetta: "MemRosetta",
20
+ vector: "vector",
21
+ embedding: "embedding",
22
+ fts5: "FTS5",
23
+ search: "search",
24
+ memory: "memory",
25
+ database: "database",
26
+ postgresql: "PostgreSQL",
27
+ nextjs: "Next.js",
28
+ "next.js": "Next.js",
29
+ node: "Node.js",
30
+ python: "Python",
31
+ rust: "Rust",
32
+ kubernetes: "Kubernetes",
33
+ ci: "CI/CD",
34
+ security: "security",
35
+ auth: "authentication",
36
+ cache: "cache",
37
+ performance: "performance"
38
+ };
39
+ function classifyTurn(turn) {
40
+ const lower = turn.content.toLowerCase();
41
+ if (turn.role === "user") {
42
+ if (lower.includes("decide") || lower.includes("go with") || lower.includes("let's do") || lower.includes("proceed") || lower.includes("approved")) {
43
+ return "decision";
44
+ }
45
+ if (lower.includes("prefer") || lower.includes("i like") || lower.includes("i want") || lower.includes("i need")) {
46
+ return "preference";
47
+ }
48
+ return "event";
49
+ }
50
+ return "fact";
51
+ }
52
+ function extractKeywords(text) {
53
+ const keywords = /* @__PURE__ */ new Set();
54
+ const lower = text.toLowerCase();
55
+ for (const [pattern, keyword] of Object.entries(KEYWORD_PATTERNS)) {
56
+ if (lower.includes(pattern)) {
57
+ keywords.add(keyword);
58
+ }
59
+ }
60
+ return [...keywords];
61
+ }
62
+ function resolveUserId(_cwd) {
63
+ return resolveCanonicalUserId();
64
+ }
65
+ function extractFirstSentence(text, maxLen = 200) {
66
+ const lines = text.split("\n");
67
+ for (const line of lines) {
68
+ const trimmed = line.trim();
69
+ if (!trimmed) continue;
70
+ if (trimmed.startsWith("```")) continue;
71
+ if (trimmed.startsWith("|")) continue;
72
+ if (trimmed.startsWith("- [")) continue;
73
+ if (trimmed.startsWith("> ")) continue;
74
+ if (trimmed.startsWith("import ") || trimmed.startsWith("export ") || trimmed.startsWith("const ") || trimmed.startsWith("function ")) continue;
75
+ if (trimmed.startsWith("{") || trimmed.startsWith("}")) continue;
76
+ if (/^[\s\-=*#]+$/.test(trimmed)) continue;
77
+ if (trimmed.startsWith("#")) {
78
+ const headerText = trimmed.replace(/^#+\s*/, "");
79
+ if (headerText.length > 10) {
80
+ return headerText.length > maxLen ? headerText.slice(0, maxLen - 3) + "..." : headerText;
81
+ }
82
+ continue;
83
+ }
84
+ if (trimmed.startsWith("/") || trimmed.startsWith("./") || trimmed.startsWith("$")) continue;
85
+ if (trimmed.length < 15) continue;
86
+ if (!/[a-zA-Z\uAC00-\uD7AF]{3,}/.test(trimmed)) continue;
87
+ return trimmed.length > maxLen ? trimmed.slice(0, maxLen - 3) + "..." : trimmed;
88
+ }
89
+ const clean = text.replace(/\s+/g, " ").trim();
90
+ return clean.length > maxLen ? clean.slice(0, maxLen - 3) + "..." : clean;
91
+ }
92
+ function isWorthStoring(turn) {
93
+ const content = turn.content;
94
+ if (content.length < 30) return false;
95
+ if (turn.role === "user") {
96
+ const lower = content.toLowerCase().trim();
97
+ if (lower.length < 20) return false;
98
+ if (lower.startsWith("/")) return false;
99
+ if (/^(y|n|yes|no|ok|ㅇㅇ|ㅋㅋ|ㄱㄱ|네|아니|진행|계속|좋아|해봐)$/i.test(lower)) return false;
100
+ return true;
101
+ }
102
+ const codeBlockCount = (content.match(/```/g) || []).length / 2;
103
+ if (codeBlockCount >= 2) return false;
104
+ const toolPatterns = [
105
+ /^(reading|writing|creating|editing|deleting|running|checking|searching|looking)/i,
106
+ /^(file|directory|folder) (created|modified|deleted|found)/i,
107
+ /^(let me|i'll|i will) (read|check|look|search|find|create|write|edit)/i,
108
+ /^(here('s| is| are) (the|a|an))/i,
109
+ /^\d+ (files?|tests?|errors?|warnings?) (found|passed|failed|created)/i,
110
+ /^(done|completed|finished|success|failed|error)/i,
111
+ /^(installing|building|compiling|running tests)/i
112
+ ];
113
+ for (const pattern of toolPatterns) {
114
+ if (pattern.test(content.trim())) return false;
115
+ }
116
+ if (content.length > 2e3) return false;
117
+ const wordCount = content.split(/\s+/).length;
118
+ const codeChars = (content.match(/[{}();=<>]/g) || []).length;
119
+ if (codeChars > wordCount * 0.3) return false;
120
+ return true;
121
+ }
122
+ function extractMemories(data, userId) {
123
+ const memories = [];
124
+ const sessionShort = data.sessionId ? data.sessionId.slice(0, 8) : "unknown";
125
+ const now = (/* @__PURE__ */ new Date()).toISOString();
126
+ const seen = /* @__PURE__ */ new Set();
127
+ for (let i = 0; i < data.turns.length; i++) {
128
+ const turn = data.turns[i];
129
+ if (!isWorthStoring(turn)) continue;
130
+ const content = extractFirstSentence(turn.content);
131
+ if (seen.has(content)) continue;
132
+ seen.add(content);
133
+ memories.push({
134
+ userId,
135
+ namespace: `session-${sessionShort}`,
136
+ memoryType: classifyTurn(turn),
137
+ content,
138
+ documentDate: now,
139
+ sourceId: `cc-${sessionShort}-${i}`,
140
+ confidence: turn.role === "user" ? 0.9 : 0.8,
141
+ keywords: extractKeywords(content)
142
+ });
143
+ }
144
+ return memories;
145
+ }
146
+
147
+ export {
148
+ classifyTurn,
149
+ resolveUserId,
150
+ extractMemories
151
+ };
@@ -0,0 +1,151 @@
1
+ import {
2
+ resolveCanonicalUserId
3
+ } from "./chunk-WYHEAKPC.js";
4
+
5
+ // src/hooks/memory-extractor.ts
6
+ var KEYWORD_PATTERNS = {
7
+ typescript: "TypeScript",
8
+ sqlite: "SQLite",
9
+ api: "API",
10
+ benchmark: "benchmark",
11
+ docker: "Docker",
12
+ git: "Git",
13
+ react: "React",
14
+ hono: "Hono",
15
+ test: "test",
16
+ deploy: "deploy",
17
+ refactor: "refactor",
18
+ bug: "bug",
19
+ memrosetta: "MemRosetta",
20
+ vector: "vector",
21
+ embedding: "embedding",
22
+ fts5: "FTS5",
23
+ search: "search",
24
+ memory: "memory",
25
+ database: "database",
26
+ postgresql: "PostgreSQL",
27
+ nextjs: "Next.js",
28
+ "next.js": "Next.js",
29
+ node: "Node.js",
30
+ python: "Python",
31
+ rust: "Rust",
32
+ kubernetes: "Kubernetes",
33
+ ci: "CI/CD",
34
+ security: "security",
35
+ auth: "authentication",
36
+ cache: "cache",
37
+ performance: "performance"
38
+ };
39
+ function classifyTurn(turn) {
40
+ const lower = turn.content.toLowerCase();
41
+ if (turn.role === "user") {
42
+ if (lower.includes("decide") || lower.includes("go with") || lower.includes("let's do") || lower.includes("proceed") || lower.includes("approved")) {
43
+ return "decision";
44
+ }
45
+ if (lower.includes("prefer") || lower.includes("i like") || lower.includes("i want") || lower.includes("i need")) {
46
+ return "preference";
47
+ }
48
+ return "event";
49
+ }
50
+ return "fact";
51
+ }
52
+ function extractKeywords(text) {
53
+ const keywords = /* @__PURE__ */ new Set();
54
+ const lower = text.toLowerCase();
55
+ for (const [pattern, keyword] of Object.entries(KEYWORD_PATTERNS)) {
56
+ if (lower.includes(pattern)) {
57
+ keywords.add(keyword);
58
+ }
59
+ }
60
+ return [...keywords];
61
+ }
62
+ function resolveUserId(_cwd) {
63
+ return resolveCanonicalUserId();
64
+ }
65
+ function extractFirstSentence(text, maxLen = 200) {
66
+ const lines = text.split("\n");
67
+ for (const line of lines) {
68
+ const trimmed = line.trim();
69
+ if (!trimmed) continue;
70
+ if (trimmed.startsWith("```")) continue;
71
+ if (trimmed.startsWith("|")) continue;
72
+ if (trimmed.startsWith("- [")) continue;
73
+ if (trimmed.startsWith("> ")) continue;
74
+ if (trimmed.startsWith("import ") || trimmed.startsWith("export ") || trimmed.startsWith("const ") || trimmed.startsWith("function ")) continue;
75
+ if (trimmed.startsWith("{") || trimmed.startsWith("}")) continue;
76
+ if (/^[\s\-=*#]+$/.test(trimmed)) continue;
77
+ if (trimmed.startsWith("#")) {
78
+ const headerText = trimmed.replace(/^#+\s*/, "");
79
+ if (headerText.length > 10) {
80
+ return headerText.length > maxLen ? headerText.slice(0, maxLen - 3) + "..." : headerText;
81
+ }
82
+ continue;
83
+ }
84
+ if (trimmed.startsWith("/") || trimmed.startsWith("./") || trimmed.startsWith("$")) continue;
85
+ if (trimmed.length < 15) continue;
86
+ if (!/[a-zA-Z\uAC00-\uD7AF]{3,}/.test(trimmed)) continue;
87
+ return trimmed.length > maxLen ? trimmed.slice(0, maxLen - 3) + "..." : trimmed;
88
+ }
89
+ const clean = text.replace(/\s+/g, " ").trim();
90
+ return clean.length > maxLen ? clean.slice(0, maxLen - 3) + "..." : clean;
91
+ }
92
+ function isWorthStoring(turn) {
93
+ const content = turn.content;
94
+ if (content.length < 30) return false;
95
+ if (turn.role === "user") {
96
+ const lower = content.toLowerCase().trim();
97
+ if (lower.length < 20) return false;
98
+ if (lower.startsWith("/")) return false;
99
+ if (/^(y|n|yes|no|ok|ㅇㅇ|ㅋㅋ|ㄱㄱ|네|아니|진행|계속|좋아|해봐)$/i.test(lower)) return false;
100
+ return true;
101
+ }
102
+ const codeBlockCount = (content.match(/```/g) || []).length / 2;
103
+ if (codeBlockCount >= 2) return false;
104
+ const toolPatterns = [
105
+ /^(reading|writing|creating|editing|deleting|running|checking|searching|looking)/i,
106
+ /^(file|directory|folder) (created|modified|deleted|found)/i,
107
+ /^(let me|i'll|i will) (read|check|look|search|find|create|write|edit)/i,
108
+ /^(here('s| is| are) (the|a|an))/i,
109
+ /^\d+ (files?|tests?|errors?|warnings?) (found|passed|failed|created)/i,
110
+ /^(done|completed|finished|success|failed|error)/i,
111
+ /^(installing|building|compiling|running tests)/i
112
+ ];
113
+ for (const pattern of toolPatterns) {
114
+ if (pattern.test(content.trim())) return false;
115
+ }
116
+ if (content.length > 2e3) return false;
117
+ const wordCount = content.split(/\s+/).length;
118
+ const codeChars = (content.match(/[{}();=<>]/g) || []).length;
119
+ if (codeChars > wordCount * 0.3) return false;
120
+ return true;
121
+ }
122
+ function extractMemories(data, userId) {
123
+ const memories = [];
124
+ const sessionShort = data.sessionId ? data.sessionId.slice(0, 8) : "unknown";
125
+ const now = (/* @__PURE__ */ new Date()).toISOString();
126
+ const seen = /* @__PURE__ */ new Set();
127
+ for (let i = 0; i < data.turns.length; i++) {
128
+ const turn = data.turns[i];
129
+ if (!isWorthStoring(turn)) continue;
130
+ const content = extractFirstSentence(turn.content);
131
+ if (seen.has(content)) continue;
132
+ seen.add(content);
133
+ memories.push({
134
+ userId,
135
+ namespace: `session-${sessionShort}`,
136
+ memoryType: classifyTurn(turn),
137
+ content,
138
+ documentDate: now,
139
+ sourceId: `cc-${sessionShort}-${i}`,
140
+ confidence: turn.role === "user" ? 0.9 : 0.8,
141
+ keywords: extractKeywords(content)
142
+ });
143
+ }
144
+ return memories;
145
+ }
146
+
147
+ export {
148
+ classifyTurn,
149
+ resolveUserId,
150
+ extractMemories
151
+ };
@@ -0,0 +1,56 @@
1
+ import {
2
+ ensureDir,
3
+ getConfig
4
+ } from "./chunk-RZFCVYTK.js";
5
+
6
+ // src/hooks/engine-manager.ts
7
+ import { SqliteMemoryEngine } from "@memrosetta/core";
8
+ var engineInstance = null;
9
+ async function getEngine() {
10
+ if (engineInstance) return engineInstance;
11
+ const config = getConfig();
12
+ ensureDir();
13
+ let embedder;
14
+ if (config.enableEmbeddings) {
15
+ try {
16
+ const { HuggingFaceEmbedder } = await import("@memrosetta/embeddings");
17
+ const preset = config.embeddingPreset ?? "en";
18
+ embedder = new HuggingFaceEmbedder({ preset });
19
+ await embedder.initialize();
20
+ } catch (err) {
21
+ const message = err instanceof Error ? err.message : String(err);
22
+ process.stderr.write(
23
+ `[memrosetta] Failed to load embeddings, continuing without: ${message}
24
+ `
25
+ );
26
+ }
27
+ }
28
+ engineInstance = new SqliteMemoryEngine({
29
+ dbPath: config.dbPath,
30
+ embedder
31
+ });
32
+ await engineInstance.initialize();
33
+ return engineInstance;
34
+ }
35
+ async function closeEngine() {
36
+ if (engineInstance) {
37
+ await engineInstance.close();
38
+ engineInstance = null;
39
+ }
40
+ }
41
+ async function getEngineWithTimeout(timeoutMs) {
42
+ let timer;
43
+ const enginePromise = getEngine();
44
+ const timeoutPromise = new Promise((resolve) => {
45
+ timer = setTimeout(() => resolve(null), timeoutMs);
46
+ });
47
+ const result = await Promise.race([enginePromise, timeoutPromise]);
48
+ clearTimeout(timer);
49
+ return result;
50
+ }
51
+
52
+ export {
53
+ getEngine,
54
+ closeEngine,
55
+ getEngineWithTimeout
56
+ };
@@ -0,0 +1,139 @@
1
+ import {
2
+ getConfig,
3
+ resolveCanonicalUserId
4
+ } from "./chunk-WYHEAKPC.js";
5
+
6
+ // src/sync/cli-sync.ts
7
+ import { createHash, randomUUID } from "crypto";
8
+ function deterministicOpId(kind, key) {
9
+ const hash = createHash("sha256").update(`${kind}:${key}`).digest("hex");
10
+ return `op-${hash.slice(0, 16)}`;
11
+ }
12
+ var DISABLED = {
13
+ enabled: false,
14
+ userId: "",
15
+ deviceId: "",
16
+ enqueue() {
17
+ },
18
+ close() {
19
+ }
20
+ };
21
+ async function openCliSyncContext(dbPath) {
22
+ const config = getConfig();
23
+ if (!config.syncEnabled || !config.syncServerUrl || !config.syncApiKey || !config.syncDeviceId) {
24
+ return DISABLED;
25
+ }
26
+ const userId = resolveCanonicalUserId();
27
+ const deviceId = config.syncDeviceId;
28
+ try {
29
+ const { default: Database } = await import("better-sqlite3");
30
+ const { SyncClient, ensureSyncSchema } = await import("@memrosetta/sync-client");
31
+ const db = new Database(dbPath);
32
+ ensureSyncSchema(db);
33
+ const client = new SyncClient(db, {
34
+ serverUrl: config.syncServerUrl,
35
+ apiKey: config.syncApiKey,
36
+ deviceId,
37
+ userId
38
+ });
39
+ const outbox = client.getOutbox();
40
+ return {
41
+ enabled: true,
42
+ userId,
43
+ deviceId,
44
+ enqueue(op) {
45
+ try {
46
+ outbox.addOp(op);
47
+ } catch (err) {
48
+ process.stderr.write(
49
+ `[sync] enqueue failed: ${err instanceof Error ? err.message : String(err)}
50
+ `
51
+ );
52
+ }
53
+ },
54
+ close() {
55
+ try {
56
+ db.close();
57
+ } catch {
58
+ }
59
+ }
60
+ };
61
+ } catch (err) {
62
+ process.stderr.write(
63
+ `[sync] disabled for this command: ${err instanceof Error ? err.message : String(err)}
64
+ `
65
+ );
66
+ return DISABLED;
67
+ }
68
+ }
69
+ function buildMemoryCreatedOp(ctx, memory) {
70
+ return {
71
+ opId: randomUUID(),
72
+ opType: "memory_created",
73
+ deviceId: ctx.deviceId,
74
+ userId: ctx.userId,
75
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
76
+ payload: {
77
+ memoryId: memory.memoryId,
78
+ userId: memory.userId,
79
+ namespace: memory.namespace,
80
+ memoryType: memory.memoryType,
81
+ content: memory.content,
82
+ rawText: memory.rawText,
83
+ documentDate: memory.documentDate,
84
+ sourceId: memory.sourceId,
85
+ confidence: memory.confidence,
86
+ salience: memory.salience,
87
+ keywords: memory.keywords,
88
+ eventDateStart: memory.eventDateStart,
89
+ eventDateEnd: memory.eventDateEnd,
90
+ invalidatedAt: memory.invalidatedAt,
91
+ learnedAt: memory.learnedAt
92
+ }
93
+ };
94
+ }
95
+ function buildRelationCreatedOp(ctx, relation) {
96
+ return {
97
+ opId: randomUUID(),
98
+ opType: "relation_created",
99
+ deviceId: ctx.deviceId,
100
+ userId: ctx.userId,
101
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
102
+ payload: {
103
+ srcMemoryId: relation.srcMemoryId,
104
+ dstMemoryId: relation.dstMemoryId,
105
+ relationType: relation.relationType,
106
+ reason: relation.reason,
107
+ createdAt: relation.createdAt
108
+ }
109
+ };
110
+ }
111
+ function buildMemoryInvalidatedOp(ctx, memoryId, invalidatedAt, reason) {
112
+ return {
113
+ opId: randomUUID(),
114
+ opType: "memory_invalidated",
115
+ deviceId: ctx.deviceId,
116
+ userId: ctx.userId,
117
+ createdAt: invalidatedAt,
118
+ payload: { memoryId, invalidatedAt, reason }
119
+ };
120
+ }
121
+ function buildFeedbackGivenOp(ctx, memoryId, helpful, recordedAt) {
122
+ return {
123
+ opId: randomUUID(),
124
+ opType: "feedback_given",
125
+ deviceId: ctx.deviceId,
126
+ userId: ctx.userId,
127
+ createdAt: recordedAt,
128
+ payload: { memoryId, helpful, recordedAt }
129
+ };
130
+ }
131
+
132
+ export {
133
+ deterministicOpId,
134
+ openCliSyncContext,
135
+ buildMemoryCreatedOp,
136
+ buildRelationCreatedOp,
137
+ buildMemoryInvalidatedOp,
138
+ buildFeedbackGivenOp
139
+ };
@@ -0,0 +1,56 @@
1
+ import {
2
+ ensureDir,
3
+ getConfig
4
+ } from "./chunk-WYHEAKPC.js";
5
+
6
+ // src/hooks/engine-manager.ts
7
+ import { SqliteMemoryEngine } from "@memrosetta/core";
8
+ var engineInstance = null;
9
+ async function getEngine() {
10
+ if (engineInstance) return engineInstance;
11
+ const config = getConfig();
12
+ ensureDir();
13
+ let embedder;
14
+ if (config.enableEmbeddings) {
15
+ try {
16
+ const { HuggingFaceEmbedder } = await import("@memrosetta/embeddings");
17
+ const preset = config.embeddingPreset ?? "en";
18
+ embedder = new HuggingFaceEmbedder({ preset });
19
+ await embedder.initialize();
20
+ } catch (err) {
21
+ const message = err instanceof Error ? err.message : String(err);
22
+ process.stderr.write(
23
+ `[memrosetta] Failed to load embeddings, continuing without: ${message}
24
+ `
25
+ );
26
+ }
27
+ }
28
+ engineInstance = new SqliteMemoryEngine({
29
+ dbPath: config.dbPath,
30
+ embedder
31
+ });
32
+ await engineInstance.initialize();
33
+ return engineInstance;
34
+ }
35
+ async function closeEngine() {
36
+ if (engineInstance) {
37
+ await engineInstance.close();
38
+ engineInstance = null;
39
+ }
40
+ }
41
+ async function getEngineWithTimeout(timeoutMs) {
42
+ let timer;
43
+ const enginePromise = getEngine();
44
+ const timeoutPromise = new Promise((resolve) => {
45
+ timer = setTimeout(() => resolve(null), timeoutMs);
46
+ });
47
+ const result = await Promise.race([enginePromise, timeoutPromise]);
48
+ clearTimeout(timer);
49
+ return result;
50
+ }
51
+
52
+ export {
53
+ getEngine,
54
+ closeEngine,
55
+ getEngineWithTimeout
56
+ };
@@ -0,0 +1,139 @@
1
+ import {
2
+ getConfig,
3
+ resolveCanonicalUserId
4
+ } from "./chunk-RZFCVYTK.js";
5
+
6
+ // src/sync/cli-sync.ts
7
+ import { createHash, randomUUID } from "crypto";
8
+ function deterministicOpId(kind, key) {
9
+ const hash = createHash("sha256").update(`${kind}:${key}`).digest("hex");
10
+ return `op-${hash.slice(0, 16)}`;
11
+ }
12
+ var DISABLED = {
13
+ enabled: false,
14
+ userId: "",
15
+ deviceId: "",
16
+ enqueue() {
17
+ },
18
+ close() {
19
+ }
20
+ };
21
+ async function openCliSyncContext(dbPath) {
22
+ const config = getConfig();
23
+ if (!config.syncEnabled || !config.syncServerUrl || !config.syncApiKey || !config.syncDeviceId) {
24
+ return DISABLED;
25
+ }
26
+ const userId = resolveCanonicalUserId();
27
+ const deviceId = config.syncDeviceId;
28
+ try {
29
+ const { default: Database } = await import("better-sqlite3");
30
+ const { SyncClient, ensureSyncSchema } = await import("@memrosetta/sync-client");
31
+ const db = new Database(dbPath);
32
+ ensureSyncSchema(db);
33
+ const client = new SyncClient(db, {
34
+ serverUrl: config.syncServerUrl,
35
+ apiKey: config.syncApiKey,
36
+ deviceId,
37
+ userId
38
+ });
39
+ const outbox = client.getOutbox();
40
+ return {
41
+ enabled: true,
42
+ userId,
43
+ deviceId,
44
+ enqueue(op) {
45
+ try {
46
+ outbox.addOp(op);
47
+ } catch (err) {
48
+ process.stderr.write(
49
+ `[sync] enqueue failed: ${err instanceof Error ? err.message : String(err)}
50
+ `
51
+ );
52
+ }
53
+ },
54
+ close() {
55
+ try {
56
+ db.close();
57
+ } catch {
58
+ }
59
+ }
60
+ };
61
+ } catch (err) {
62
+ process.stderr.write(
63
+ `[sync] disabled for this command: ${err instanceof Error ? err.message : String(err)}
64
+ `
65
+ );
66
+ return DISABLED;
67
+ }
68
+ }
69
+ function buildMemoryCreatedOp(ctx, memory) {
70
+ return {
71
+ opId: randomUUID(),
72
+ opType: "memory_created",
73
+ deviceId: ctx.deviceId,
74
+ userId: ctx.userId,
75
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
76
+ payload: {
77
+ memoryId: memory.memoryId,
78
+ userId: memory.userId,
79
+ namespace: memory.namespace,
80
+ memoryType: memory.memoryType,
81
+ content: memory.content,
82
+ rawText: memory.rawText,
83
+ documentDate: memory.documentDate,
84
+ sourceId: memory.sourceId,
85
+ confidence: memory.confidence,
86
+ salience: memory.salience,
87
+ keywords: memory.keywords,
88
+ eventDateStart: memory.eventDateStart,
89
+ eventDateEnd: memory.eventDateEnd,
90
+ invalidatedAt: memory.invalidatedAt,
91
+ learnedAt: memory.learnedAt
92
+ }
93
+ };
94
+ }
95
+ function buildRelationCreatedOp(ctx, relation) {
96
+ return {
97
+ opId: randomUUID(),
98
+ opType: "relation_created",
99
+ deviceId: ctx.deviceId,
100
+ userId: ctx.userId,
101
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
102
+ payload: {
103
+ srcMemoryId: relation.srcMemoryId,
104
+ dstMemoryId: relation.dstMemoryId,
105
+ relationType: relation.relationType,
106
+ reason: relation.reason,
107
+ createdAt: relation.createdAt
108
+ }
109
+ };
110
+ }
111
+ function buildMemoryInvalidatedOp(ctx, memoryId, invalidatedAt, reason) {
112
+ return {
113
+ opId: randomUUID(),
114
+ opType: "memory_invalidated",
115
+ deviceId: ctx.deviceId,
116
+ userId: ctx.userId,
117
+ createdAt: invalidatedAt,
118
+ payload: { memoryId, invalidatedAt, reason }
119
+ };
120
+ }
121
+ function buildFeedbackGivenOp(ctx, memoryId, helpful, recordedAt) {
122
+ return {
123
+ opId: randomUUID(),
124
+ opType: "feedback_given",
125
+ deviceId: ctx.deviceId,
126
+ userId: ctx.userId,
127
+ createdAt: recordedAt,
128
+ payload: { memoryId, helpful, recordedAt }
129
+ };
130
+ }
131
+
132
+ export {
133
+ deterministicOpId,
134
+ openCliSyncContext,
135
+ buildMemoryCreatedOp,
136
+ buildRelationCreatedOp,
137
+ buildMemoryInvalidatedOp,
138
+ buildFeedbackGivenOp
139
+ };