@memrosetta/cli 0.4.6 → 0.4.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.
@@ -0,0 +1,134 @@
1
+ import {
2
+ getConfig
3
+ } from "./chunk-SEPYQK3J.js";
4
+
5
+ // src/sync/cli-sync.ts
6
+ import { randomUUID } from "crypto";
7
+ import { userInfo } from "os";
8
+ var DISABLED = {
9
+ enabled: false,
10
+ userId: "",
11
+ deviceId: "",
12
+ enqueue() {
13
+ },
14
+ close() {
15
+ }
16
+ };
17
+ async function openCliSyncContext(dbPath) {
18
+ const config = getConfig();
19
+ if (!config.syncEnabled || !config.syncServerUrl || !config.syncApiKey || !config.syncDeviceId) {
20
+ return DISABLED;
21
+ }
22
+ const userId = config.syncUserId ?? userInfo().username;
23
+ const deviceId = config.syncDeviceId;
24
+ try {
25
+ const { default: Database } = await import("better-sqlite3");
26
+ const { SyncClient, ensureSyncSchema } = await import("@memrosetta/sync-client");
27
+ const db = new Database(dbPath);
28
+ ensureSyncSchema(db);
29
+ const client = new SyncClient(db, {
30
+ serverUrl: config.syncServerUrl,
31
+ apiKey: config.syncApiKey,
32
+ deviceId,
33
+ userId
34
+ });
35
+ const outbox = client.getOutbox();
36
+ return {
37
+ enabled: true,
38
+ userId,
39
+ deviceId,
40
+ enqueue(op) {
41
+ try {
42
+ outbox.addOp(op);
43
+ } catch (err) {
44
+ process.stderr.write(
45
+ `[sync] enqueue failed: ${err instanceof Error ? err.message : String(err)}
46
+ `
47
+ );
48
+ }
49
+ },
50
+ close() {
51
+ try {
52
+ db.close();
53
+ } catch {
54
+ }
55
+ }
56
+ };
57
+ } catch (err) {
58
+ process.stderr.write(
59
+ `[sync] disabled for this command: ${err instanceof Error ? err.message : String(err)}
60
+ `
61
+ );
62
+ return DISABLED;
63
+ }
64
+ }
65
+ function buildMemoryCreatedOp(ctx, memory) {
66
+ return {
67
+ opId: randomUUID(),
68
+ opType: "memory_created",
69
+ deviceId: ctx.deviceId,
70
+ userId: ctx.userId,
71
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
72
+ payload: {
73
+ memoryId: memory.memoryId,
74
+ userId: memory.userId,
75
+ namespace: memory.namespace,
76
+ memoryType: memory.memoryType,
77
+ content: memory.content,
78
+ rawText: memory.rawText,
79
+ documentDate: memory.documentDate,
80
+ sourceId: memory.sourceId,
81
+ confidence: memory.confidence,
82
+ salience: memory.salience,
83
+ keywords: memory.keywords,
84
+ eventDateStart: memory.eventDateStart,
85
+ eventDateEnd: memory.eventDateEnd,
86
+ invalidatedAt: memory.invalidatedAt,
87
+ learnedAt: memory.learnedAt
88
+ }
89
+ };
90
+ }
91
+ function buildRelationCreatedOp(ctx, relation) {
92
+ return {
93
+ opId: randomUUID(),
94
+ opType: "relation_created",
95
+ deviceId: ctx.deviceId,
96
+ userId: ctx.userId,
97
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
98
+ payload: {
99
+ srcMemoryId: relation.srcMemoryId,
100
+ dstMemoryId: relation.dstMemoryId,
101
+ relationType: relation.relationType,
102
+ reason: relation.reason,
103
+ createdAt: relation.createdAt
104
+ }
105
+ };
106
+ }
107
+ function buildMemoryInvalidatedOp(ctx, memoryId, invalidatedAt, reason) {
108
+ return {
109
+ opId: randomUUID(),
110
+ opType: "memory_invalidated",
111
+ deviceId: ctx.deviceId,
112
+ userId: ctx.userId,
113
+ createdAt: invalidatedAt,
114
+ payload: { memoryId, invalidatedAt, reason }
115
+ };
116
+ }
117
+ function buildFeedbackGivenOp(ctx, memoryId, helpful, recordedAt) {
118
+ return {
119
+ opId: randomUUID(),
120
+ opType: "feedback_given",
121
+ deviceId: ctx.deviceId,
122
+ userId: ctx.userId,
123
+ createdAt: recordedAt,
124
+ payload: { memoryId, helpful, recordedAt }
125
+ };
126
+ }
127
+
128
+ export {
129
+ openCliSyncContext,
130
+ buildMemoryCreatedOp,
131
+ buildRelationCreatedOp,
132
+ buildMemoryInvalidatedOp,
133
+ buildFeedbackGivenOp
134
+ };
@@ -0,0 +1,64 @@
1
+ import {
2
+ getConfig
3
+ } from "./chunk-SEPYQK3J.js";
4
+
5
+ // src/engine.ts
6
+ import { join, dirname } from "path";
7
+ import { homedir } from "os";
8
+ import { mkdirSync, existsSync } from "fs";
9
+ var DEFAULT_DB = join(homedir(), ".memrosetta", "memories.db");
10
+ var cachedEngine = null;
11
+ var cachedDbPath = null;
12
+ async function createEngineInstance(options) {
13
+ const config = getConfig();
14
+ const dbPath = options.db ?? config.dbPath ?? DEFAULT_DB;
15
+ const dir = dirname(dbPath);
16
+ if (!existsSync(dir)) {
17
+ mkdirSync(dir, { recursive: true });
18
+ }
19
+ const { SqliteMemoryEngine } = await import("@memrosetta/core");
20
+ let embedder;
21
+ if (!options.noEmbeddings && config.enableEmbeddings !== false) {
22
+ try {
23
+ const { HuggingFaceEmbedder } = await import("@memrosetta/embeddings");
24
+ const preset = options.embeddingPreset ?? config.embeddingPreset ?? "en";
25
+ embedder = new HuggingFaceEmbedder({ preset });
26
+ await embedder.initialize();
27
+ } catch {
28
+ }
29
+ }
30
+ const engine = new SqliteMemoryEngine({ dbPath, embedder });
31
+ await engine.initialize();
32
+ return engine;
33
+ }
34
+ async function getEngine(options) {
35
+ const config = getConfig();
36
+ const dbPath = options.db ?? config.dbPath ?? DEFAULT_DB;
37
+ if (cachedEngine && cachedDbPath === dbPath) {
38
+ return cachedEngine;
39
+ }
40
+ cachedEngine = await createEngineInstance(options);
41
+ cachedDbPath = dbPath;
42
+ return cachedEngine;
43
+ }
44
+ function getDefaultDbPath() {
45
+ return DEFAULT_DB;
46
+ }
47
+ function resolveDbPath(dbOverride) {
48
+ const config = getConfig();
49
+ return dbOverride ?? config.dbPath ?? DEFAULT_DB;
50
+ }
51
+ async function closeEngine() {
52
+ if (cachedEngine) {
53
+ await cachedEngine.close();
54
+ cachedEngine = null;
55
+ cachedDbPath = null;
56
+ }
57
+ }
58
+
59
+ export {
60
+ getEngine,
61
+ getDefaultDbPath,
62
+ resolveDbPath,
63
+ closeEngine
64
+ };
@@ -0,0 +1,39 @@
1
+ import {
2
+ hasFlag,
3
+ optionalOption
4
+ } from "./chunk-NU5ZJJXP.js";
5
+ import {
6
+ getEngine
7
+ } from "./chunk-VAVUPQZA.js";
8
+ import {
9
+ output,
10
+ outputError
11
+ } from "./chunk-ET6TNQOJ.js";
12
+ import {
13
+ getDefaultUserId
14
+ } from "./chunk-SEPYQK3J.js";
15
+
16
+ // src/commands/clear.ts
17
+ async function run(options) {
18
+ const { args, format, db, noEmbeddings } = options;
19
+ const userId = optionalOption(args, "--user") ?? getDefaultUserId();
20
+ const confirm = hasFlag(args, "--confirm");
21
+ if (!confirm) {
22
+ outputError(
23
+ "This will delete all memories for the user. Use --confirm to proceed.",
24
+ format
25
+ );
26
+ process.exitCode = 1;
27
+ return;
28
+ }
29
+ const engine = await getEngine({ db, noEmbeddings });
30
+ const countBefore = await engine.count(userId);
31
+ await engine.clear(userId);
32
+ output(
33
+ { userId, cleared: countBefore, message: `Cleared ${countBefore} memories` },
34
+ format
35
+ );
36
+ }
37
+ export {
38
+ run
39
+ };
@@ -0,0 +1,33 @@
1
+ import {
2
+ optionalOption
3
+ } from "./chunk-NU5ZJJXP.js";
4
+ import {
5
+ getEngine
6
+ } from "./chunk-VAVUPQZA.js";
7
+ import {
8
+ output
9
+ } from "./chunk-ET6TNQOJ.js";
10
+ import {
11
+ getDefaultUserId
12
+ } from "./chunk-SEPYQK3J.js";
13
+
14
+ // src/commands/compress.ts
15
+ async function run(options) {
16
+ const { args, format, db, noEmbeddings } = options;
17
+ const userId = optionalOption(args, "--user") ?? getDefaultUserId();
18
+ const engine = await getEngine({ db, noEmbeddings });
19
+ const result = await engine.compress(userId);
20
+ if (format === "text") {
21
+ process.stdout.write(`Compression completed for user: ${userId}
22
+ `);
23
+ process.stdout.write(` Groups compressed: ${result.compressed}
24
+ `);
25
+ process.stdout.write(` Memories archived: ${result.removed}
26
+ `);
27
+ return;
28
+ }
29
+ output({ userId, ...result }, format);
30
+ }
31
+ export {
32
+ run
33
+ };
@@ -0,0 +1,24 @@
1
+ import {
2
+ optionalOption
3
+ } from "./chunk-NU5ZJJXP.js";
4
+ import {
5
+ getEngine
6
+ } from "./chunk-VAVUPQZA.js";
7
+ import {
8
+ output
9
+ } from "./chunk-ET6TNQOJ.js";
10
+ import {
11
+ getDefaultUserId
12
+ } from "./chunk-SEPYQK3J.js";
13
+
14
+ // src/commands/count.ts
15
+ async function run(options) {
16
+ const { args, format, db, noEmbeddings } = options;
17
+ const userId = optionalOption(args, "--user") ?? getDefaultUserId();
18
+ const engine = await getEngine({ db, noEmbeddings });
19
+ const count = await engine.count(userId);
20
+ output({ userId, count }, format);
21
+ }
22
+ export {
23
+ run
24
+ };
@@ -0,0 +1,51 @@
1
+ import {
2
+ buildFeedbackGivenOp,
3
+ openCliSyncContext
4
+ } from "./chunk-KPASMEV7.js";
5
+ import {
6
+ hasFlag
7
+ } from "./chunk-NU5ZJJXP.js";
8
+ import {
9
+ getEngine,
10
+ resolveDbPath
11
+ } from "./chunk-VAVUPQZA.js";
12
+ import {
13
+ output,
14
+ outputError
15
+ } from "./chunk-ET6TNQOJ.js";
16
+ import "./chunk-SEPYQK3J.js";
17
+
18
+ // src/commands/feedback.ts
19
+ async function run(options) {
20
+ const { args, format, db, noEmbeddings } = options;
21
+ const memoryId = args.find((a) => !a.startsWith("-"));
22
+ if (!memoryId) {
23
+ outputError("Usage: memrosetta feedback <memoryId> --helpful | --not-helpful", format);
24
+ process.exitCode = 1;
25
+ return;
26
+ }
27
+ const helpful = hasFlag(args, "--helpful");
28
+ const notHelpful = hasFlag(args, "--not-helpful");
29
+ if (!helpful && !notHelpful) {
30
+ outputError("Specify --helpful or --not-helpful", format);
31
+ process.exitCode = 1;
32
+ return;
33
+ }
34
+ if (helpful && notHelpful) {
35
+ outputError("Specify either --helpful or --not-helpful, not both", format);
36
+ process.exitCode = 1;
37
+ return;
38
+ }
39
+ const engine = await getEngine({ db, noEmbeddings });
40
+ const now = (/* @__PURE__ */ new Date()).toISOString();
41
+ await engine.feedback(memoryId, helpful);
42
+ const sync = await openCliSyncContext(resolveDbPath(db));
43
+ if (sync.enabled) {
44
+ sync.enqueue(buildFeedbackGivenOp(sync, memoryId, helpful, now));
45
+ sync.close();
46
+ }
47
+ output({ memoryId, helpful }, format);
48
+ }
49
+ export {
50
+ run
51
+ };
@@ -0,0 +1,30 @@
1
+ import {
2
+ getEngine
3
+ } from "./chunk-VAVUPQZA.js";
4
+ import {
5
+ output,
6
+ outputError
7
+ } from "./chunk-ET6TNQOJ.js";
8
+ import "./chunk-SEPYQK3J.js";
9
+
10
+ // src/commands/get.ts
11
+ async function run(options) {
12
+ const { args, format, db, noEmbeddings } = options;
13
+ const memoryId = args.find((a) => !a.startsWith("-") && a !== "get");
14
+ if (!memoryId) {
15
+ outputError("Missing memory ID. Usage: memrosetta get <memory-id>", format);
16
+ process.exitCode = 1;
17
+ return;
18
+ }
19
+ const engine = await getEngine({ db, noEmbeddings });
20
+ const memory = await engine.getById(memoryId);
21
+ if (!memory) {
22
+ outputError(`Memory not found: ${memoryId}`, format);
23
+ process.exitCode = 1;
24
+ return;
25
+ }
26
+ output(memory, format);
27
+ }
28
+ export {
29
+ run
30
+ };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-NU5ZJJXP.js";
5
5
  import {
6
6
  closeEngine
7
- } from "./chunk-72IW6TAV.js";
7
+ } from "./chunk-VAVUPQZA.js";
8
8
  import {
9
9
  outputError
10
10
  } from "./chunk-ET6TNQOJ.js";
@@ -71,6 +71,9 @@ Sync Subcommands:
71
71
  memrosetta sync status # Show sync state + pending ops
72
72
  memrosetta sync now [--push-only | --pull-only]
73
73
  memrosetta sync device-id # Print current device id
74
+ memrosetta sync backfill [--user <id>] [--namespace <ns>] [--memories-only] [--dry-run]
75
+ # Enqueue existing local memories
76
+ # + relations into the outbox.
74
77
 
75
78
  Examples:
76
79
  memrosetta init # DB + MCP server
@@ -113,72 +116,72 @@ async function main() {
113
116
  try {
114
117
  switch (command) {
115
118
  case "store": {
116
- const mod = await import("./store-2USP33HQ.js");
119
+ const mod = await import("./store-UL35UYIV.js");
117
120
  await mod.run(commandOptions);
118
121
  break;
119
122
  }
120
123
  case "search": {
121
- const mod = await import("./search-PT4POELX.js");
124
+ const mod = await import("./search-TVOCWXRB.js");
122
125
  await mod.run(commandOptions);
123
126
  break;
124
127
  }
125
128
  case "ingest": {
126
- const mod = await import("./ingest-GSJMWDV5.js");
129
+ const mod = await import("./ingest-PQFTEAFQ.js");
127
130
  await mod.run(commandOptions);
128
131
  break;
129
132
  }
130
133
  case "get": {
131
- const mod = await import("./get-NY5H3MUA.js");
134
+ const mod = await import("./get-Q77SEO5A.js");
132
135
  await mod.run(commandOptions);
133
136
  break;
134
137
  }
135
138
  case "count": {
136
- const mod = await import("./count-AMSEVDWR.js");
139
+ const mod = await import("./count-KSE5XYCT.js");
137
140
  await mod.run(commandOptions);
138
141
  break;
139
142
  }
140
143
  case "clear": {
141
- const mod = await import("./clear-5SZVGYBX.js");
144
+ const mod = await import("./clear-XVW4R7ZD.js");
142
145
  await mod.run(commandOptions);
143
146
  break;
144
147
  }
145
148
  case "relate": {
146
- const mod = await import("./relate-SGZLG7JU.js");
149
+ const mod = await import("./relate-BQVTTMLF.js");
147
150
  await mod.run(commandOptions);
148
151
  break;
149
152
  }
150
153
  case "invalidate": {
151
- const mod = await import("./invalidate-BY5VNFSE.js");
154
+ const mod = await import("./invalidate-WXFGQHOK.js");
152
155
  await mod.run(commandOptions);
153
156
  break;
154
157
  }
155
158
  case "feedback": {
156
- const mod = await import("./feedback-XGBKFQXC.js");
159
+ const mod = await import("./feedback-Z7YIFV6D.js");
157
160
  await mod.run(commandOptions);
158
161
  break;
159
162
  }
160
163
  case "working-memory": {
161
- const mod = await import("./working-memory-UYVEJJYW.js");
164
+ const mod = await import("./working-memory-LJ2XMUE2.js");
162
165
  await mod.run(commandOptions);
163
166
  break;
164
167
  }
165
168
  case "maintain": {
166
- const mod = await import("./maintain-SGM56XKE.js");
169
+ const mod = await import("./maintain-5QUJACCJ.js");
167
170
  await mod.run(commandOptions);
168
171
  break;
169
172
  }
170
173
  case "compress": {
171
- const mod = await import("./compress-YNY6YNFU.js");
174
+ const mod = await import("./compress-LYRY4WUY.js");
172
175
  await mod.run(commandOptions);
173
176
  break;
174
177
  }
175
178
  case "status": {
176
- const mod = await import("./status-HLKL32NP.js");
179
+ const mod = await import("./status-RSXRXD7C.js");
177
180
  await mod.run(commandOptions);
178
181
  break;
179
182
  }
180
183
  case "init": {
181
- const mod = await import("./init-GRVRJ6RO.js");
184
+ const mod = await import("./init-US5IURGE.js");
182
185
  await mod.run(commandOptions);
183
186
  break;
184
187
  }
@@ -193,7 +196,7 @@ async function main() {
193
196
  break;
194
197
  }
195
198
  case "sync": {
196
- const mod = await import("./sync-JSEQ4AM3.js");
199
+ const mod = await import("./sync-QJQYXJIV.js");
197
200
  await mod.run(commandOptions);
198
201
  break;
199
202
  }
@@ -0,0 +1,95 @@
1
+ import {
2
+ classifyTurn,
3
+ parseTranscriptContent
4
+ } from "./chunk-KR63XYFW.js";
5
+ import {
6
+ optionalOption
7
+ } from "./chunk-NU5ZJJXP.js";
8
+ import {
9
+ getEngine
10
+ } from "./chunk-VAVUPQZA.js";
11
+ import {
12
+ output,
13
+ outputError
14
+ } from "./chunk-ET6TNQOJ.js";
15
+ import {
16
+ getDefaultUserId
17
+ } from "./chunk-SEPYQK3J.js";
18
+
19
+ // src/commands/ingest.ts
20
+ import { readFileSync } from "fs";
21
+ function turnsToMemories(turns, userId, namespace, sessionShort) {
22
+ const now = (/* @__PURE__ */ new Date()).toISOString();
23
+ const memories = [];
24
+ for (let i = 0; i < turns.length; i++) {
25
+ const turn = turns[i];
26
+ if (turn.content.length < 20) continue;
27
+ const content = turn.content.length > 500 ? turn.content.slice(0, 497) + "..." : turn.content;
28
+ memories.push({
29
+ userId,
30
+ namespace: namespace ?? `session-${sessionShort}`,
31
+ memoryType: classifyTurn(turn),
32
+ content,
33
+ documentDate: now,
34
+ sourceId: `cc-${sessionShort}-${i}`,
35
+ confidence: turn.role === "user" ? 0.9 : 0.8
36
+ });
37
+ }
38
+ return memories;
39
+ }
40
+ async function readStdin() {
41
+ const chunks = [];
42
+ for await (const chunk of process.stdin) {
43
+ chunks.push(chunk);
44
+ }
45
+ return Buffer.concat(chunks).toString("utf-8").trim();
46
+ }
47
+ async function run(options) {
48
+ const { args, format, db, noEmbeddings } = options;
49
+ const userId = optionalOption(args, "--user") ?? getDefaultUserId();
50
+ const file = optionalOption(args, "--file");
51
+ const namespace = optionalOption(args, "--namespace");
52
+ let content;
53
+ if (file) {
54
+ try {
55
+ content = readFileSync(file, "utf-8");
56
+ } catch (err) {
57
+ const msg = err instanceof Error ? err.message : String(err);
58
+ outputError(`Failed to read file: ${msg}`, format);
59
+ process.exitCode = 1;
60
+ return;
61
+ }
62
+ } else {
63
+ content = await readStdin();
64
+ }
65
+ if (!content) {
66
+ outputError("No transcript content provided", format);
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+ const parsed = parseTranscriptContent(content);
71
+ const sessionShort = parsed.sessionId ? parsed.sessionId.slice(0, 8) : "unknown";
72
+ const memories = turnsToMemories(
73
+ parsed.turns,
74
+ userId,
75
+ namespace,
76
+ sessionShort
77
+ );
78
+ if (memories.length === 0) {
79
+ output({ stored: 0, message: "No memories extracted from transcript" }, format);
80
+ return;
81
+ }
82
+ const engine = await getEngine({ db, noEmbeddings });
83
+ const stored = await engine.storeBatch(memories);
84
+ output(
85
+ {
86
+ stored: stored.length,
87
+ sessionId: parsed.sessionId || void 0,
88
+ namespace: namespace ?? `session-${sessionShort}`
89
+ },
90
+ format
91
+ );
92
+ }
93
+ export {
94
+ run
95
+ };