@memrosetta/cli 0.4.0 → 0.4.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 (39) hide show
  1. package/dist/chunk-72IW6TAV.js +59 -0
  2. package/dist/chunk-MISLIVUL.js +70 -0
  3. package/dist/chunk-NU5ZJJXP.js +63 -0
  4. package/dist/chunk-SEPYQK3J.js +60 -0
  5. package/dist/clear-47OFIDME.js +39 -0
  6. package/dist/clear-5SZVGYBX.js +39 -0
  7. package/dist/compress-SEFTKZMU.js +33 -0
  8. package/dist/compress-YNY6YNFU.js +33 -0
  9. package/dist/count-AMSEVDWR.js +24 -0
  10. package/dist/count-Z67KBEMV.js +24 -0
  11. package/dist/feedback-QDOWDWHM.js +40 -0
  12. package/dist/feedback-XGBKFQXC.js +40 -0
  13. package/dist/get-NY5H3MUA.js +30 -0
  14. package/dist/hooks/on-prompt.js +2 -2
  15. package/dist/hooks/on-stop.js +2 -2
  16. package/dist/index.js +35 -18
  17. package/dist/ingest-GSJMWDV5.js +95 -0
  18. package/dist/ingest-TZEVA25F.js +95 -0
  19. package/dist/init-GRVRJ6RO.js +205 -0
  20. package/dist/init-LK4UQISR.js +205 -0
  21. package/dist/invalidate-BY5VNFSE.js +25 -0
  22. package/dist/maintain-SGM56XKE.js +37 -0
  23. package/dist/maintain-VX2VWB2L.js +37 -0
  24. package/dist/relate-L5464WV5.js +47 -0
  25. package/dist/relate-SGZLG7JU.js +47 -0
  26. package/dist/reset-CYY4KYAB.js +129 -0
  27. package/dist/search-BJ2YV5IS.js +48 -0
  28. package/dist/search-PT4POELX.js +48 -0
  29. package/dist/status-TVY32MZD.js +218 -0
  30. package/dist/store-2USP33HQ.js +91 -0
  31. package/dist/store-XCFYGYBE.js +91 -0
  32. package/dist/sync-643GTA5X.js +319 -0
  33. package/dist/sync-7TONPJBY.js +351 -0
  34. package/dist/sync-BPVMHW34.js +319 -0
  35. package/dist/sync-OZQLBYT2.js +317 -0
  36. package/dist/sync-WURX2HJZ.js +321 -0
  37. package/dist/working-memory-UYVEJJYW.js +53 -0
  38. package/dist/working-memory-VP6L2QV6.js +53 -0
  39. package/package.json +5 -4
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  parseGlobalArgs
4
- } from "./chunk-VZQURGWB.js";
4
+ } from "./chunk-NU5ZJJXP.js";
5
5
  import {
6
6
  closeEngine
7
- } from "./chunk-POK32V2J.js";
7
+ } from "./chunk-72IW6TAV.js";
8
8
  import {
9
9
  outputError
10
10
  } from "./chunk-ET6TNQOJ.js";
11
- import "./chunk-TU5EHSDE.js";
11
+ import "./chunk-SEPYQK3J.js";
12
12
 
13
13
  // src/index.ts
14
14
  var HELP_TEXT = `memrosetta - AI long-term memory engine CLI
@@ -32,6 +32,7 @@ Commands:
32
32
  maintain Run maintenance (recompute scores, update tiers, compress)
33
33
  compress Run compression only
34
34
  update Update to latest version
35
+ sync Manage multi-device sync (enable/disable/status/now/device-id)
35
36
 
36
37
  Init Options:
37
38
  (no flag) Initialize DB + MCP server (base setup)
@@ -54,6 +55,15 @@ Global Options:
54
55
  --help, -h Show help
55
56
  --version, -v Show version
56
57
 
58
+ Sync Subcommands:
59
+ memrosetta sync enable --server <url> # Enable sync, hidden API key prompt
60
+ memrosetta sync enable --server <url> --key-stdin # Read API key from stdin
61
+ memrosetta sync disable # Disable sync (keeps server/key)
62
+ memrosetta sync status # Show sync state + pending ops
63
+ memrosetta sync now # Push + pull now
64
+ memrosetta sync now --push-only # Push only
65
+ memrosetta sync device-id # Print current device id
66
+
57
67
  Examples:
58
68
  memrosetta init # DB + MCP server
59
69
  memrosetta init --claude-code # DB + MCP + Claude Code hooks
@@ -65,6 +75,8 @@ Examples:
65
75
  memrosetta reset --all # Remove all integrations
66
76
  memrosetta store --user obst --content "Prefers TypeScript" --type preference
67
77
  memrosetta search --user obst --query "language preference" --format text
78
+ memrosetta sync enable --server https://your-sync.example.com
79
+ memrosetta sync status --format text
68
80
  `;
69
81
  async function main() {
70
82
  const rawArgs = process.argv.slice(2);
@@ -93,77 +105,77 @@ async function main() {
93
105
  try {
94
106
  switch (command) {
95
107
  case "store": {
96
- const mod = await import("./store-NCML2EVB.js");
108
+ const mod = await import("./store-2USP33HQ.js");
97
109
  await mod.run(commandOptions);
98
110
  break;
99
111
  }
100
112
  case "search": {
101
- const mod = await import("./search-PY4WJY4R.js");
113
+ const mod = await import("./search-PT4POELX.js");
102
114
  await mod.run(commandOptions);
103
115
  break;
104
116
  }
105
117
  case "ingest": {
106
- const mod = await import("./ingest-3QY5PCXN.js");
118
+ const mod = await import("./ingest-GSJMWDV5.js");
107
119
  await mod.run(commandOptions);
108
120
  break;
109
121
  }
110
122
  case "get": {
111
- const mod = await import("./get-DFXKCLEE.js");
123
+ const mod = await import("./get-NY5H3MUA.js");
112
124
  await mod.run(commandOptions);
113
125
  break;
114
126
  }
115
127
  case "count": {
116
- const mod = await import("./count-GNJPEZIS.js");
128
+ const mod = await import("./count-AMSEVDWR.js");
117
129
  await mod.run(commandOptions);
118
130
  break;
119
131
  }
120
132
  case "clear": {
121
- const mod = await import("./clear-HXD23CIT.js");
133
+ const mod = await import("./clear-5SZVGYBX.js");
122
134
  await mod.run(commandOptions);
123
135
  break;
124
136
  }
125
137
  case "relate": {
126
- const mod = await import("./relate-GSYCXDNM.js");
138
+ const mod = await import("./relate-SGZLG7JU.js");
127
139
  await mod.run(commandOptions);
128
140
  break;
129
141
  }
130
142
  case "invalidate": {
131
- const mod = await import("./invalidate-F4DU7RJG.js");
143
+ const mod = await import("./invalidate-BY5VNFSE.js");
132
144
  await mod.run(commandOptions);
133
145
  break;
134
146
  }
135
147
  case "feedback": {
136
- const mod = await import("./feedback-UIQWMA4O.js");
148
+ const mod = await import("./feedback-XGBKFQXC.js");
137
149
  await mod.run(commandOptions);
138
150
  break;
139
151
  }
140
152
  case "working-memory": {
141
- const mod = await import("./working-memory-F264EUCD.js");
153
+ const mod = await import("./working-memory-UYVEJJYW.js");
142
154
  await mod.run(commandOptions);
143
155
  break;
144
156
  }
145
157
  case "maintain": {
146
- const mod = await import("./maintain-NVHVBOBQ.js");
158
+ const mod = await import("./maintain-SGM56XKE.js");
147
159
  await mod.run(commandOptions);
148
160
  break;
149
161
  }
150
162
  case "compress": {
151
- const mod = await import("./compress-QR64SDRL.js");
163
+ const mod = await import("./compress-YNY6YNFU.js");
152
164
  await mod.run(commandOptions);
153
165
  break;
154
166
  }
155
167
  case "status": {
156
- const mod = await import("./status-TLK2LKG6.js");
168
+ const mod = await import("./status-TVY32MZD.js");
157
169
  await mod.run(commandOptions);
158
170
  break;
159
171
  }
160
172
  case "init": {
161
- const mod = await import("./init-Z53FKT6J.js");
173
+ const mod = await import("./init-GRVRJ6RO.js");
162
174
  await mod.run(commandOptions);
163
175
  break;
164
176
  }
165
177
  case "reset": {
166
- const mod = await import("./reset-LWRG2LIM.js");
178
+ const mod = await import("./reset-CYY4KYAB.js");
167
179
  await mod.run(commandOptions);
168
180
  break;
169
181
  }
@@ -172,6 +184,11 @@ async function main() {
172
184
  await mod.run();
173
185
  break;
174
186
  }
187
+ case "sync": {
188
+ const mod = await import("./sync-7TONPJBY.js");
189
+ await mod.run(commandOptions);
190
+ break;
191
+ }
175
192
  default:
176
193
  outputError(`Unknown command: ${command}`, opts.format);
177
194
  process.exitCode = 1;
@@ -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-72IW6TAV.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
+ };
@@ -0,0 +1,95 @@
1
+ import {
2
+ classifyTurn,
3
+ parseTranscriptContent
4
+ } from "./chunk-KR63XYFW.js";
5
+ import {
6
+ optionalOption
7
+ } from "./chunk-VZQURGWB.js";
8
+ import {
9
+ getEngine
10
+ } from "./chunk-72IW6TAV.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
+ };
@@ -0,0 +1,205 @@
1
+ import {
2
+ getAgentsMdPath,
3
+ getCodexConfigFilePath,
4
+ getCursorMcpConfigPath,
5
+ getCursorRulesPath,
6
+ getGeminiMdPath,
7
+ getGeminiSettingsFilePath,
8
+ getGenericMCPPath,
9
+ isClaudeCodeInstalled,
10
+ registerClaudeCodeHooks,
11
+ registerCodexMCP,
12
+ registerCursorMCP,
13
+ registerGeminiMCP,
14
+ registerGenericMCP,
15
+ updateClaudeMd
16
+ } from "./chunk-IS4IKWPL.js";
17
+ import {
18
+ hasFlag,
19
+ optionalOption
20
+ } from "./chunk-NU5ZJJXP.js";
21
+ import {
22
+ getDefaultDbPath,
23
+ getEngine
24
+ } from "./chunk-72IW6TAV.js";
25
+ import {
26
+ output
27
+ } from "./chunk-ET6TNQOJ.js";
28
+ import {
29
+ getConfig,
30
+ writeConfig
31
+ } from "./chunk-SEPYQK3J.js";
32
+
33
+ // src/commands/init.ts
34
+ import { existsSync } from "fs";
35
+ var LANG_FLAG_TO_PRESET = {
36
+ en: "en",
37
+ multi: "multilingual",
38
+ ko: "ko"
39
+ };
40
+ async function run(options) {
41
+ const { args, format, db, noEmbeddings } = options;
42
+ const wantClaudeCode = hasFlag(args, "--claude-code");
43
+ const wantCursor = hasFlag(args, "--cursor");
44
+ const wantCodex = hasFlag(args, "--codex");
45
+ const wantGemini = hasFlag(args, "--gemini");
46
+ const langFlag = optionalOption(args, "--lang");
47
+ const embeddingPreset = langFlag ? LANG_FLAG_TO_PRESET[langFlag] : void 0;
48
+ if (langFlag && !LANG_FLAG_TO_PRESET[langFlag]) {
49
+ process.stderr.write(
50
+ `Unknown --lang value: "${langFlag}". Supported: en, multi, ko
51
+ `
52
+ );
53
+ process.exitCode = 1;
54
+ return;
55
+ }
56
+ {
57
+ const config2 = getConfig();
58
+ const updates = {};
59
+ if (db) {
60
+ updates.dbPath = db;
61
+ }
62
+ if (noEmbeddings) {
63
+ updates.enableEmbeddings = false;
64
+ }
65
+ if (embeddingPreset) {
66
+ updates.embeddingPreset = embeddingPreset;
67
+ }
68
+ if (Object.keys(updates).length > 0) {
69
+ writeConfig({ ...config2, ...updates });
70
+ }
71
+ }
72
+ const config = getConfig();
73
+ const dbPath = db ?? config.dbPath ?? getDefaultDbPath();
74
+ const existed = existsSync(dbPath);
75
+ const engine = await getEngine({ db: dbPath, noEmbeddings });
76
+ await engine.close();
77
+ const result = {
78
+ database: {
79
+ path: dbPath,
80
+ created: !existed
81
+ },
82
+ integrations: {}
83
+ };
84
+ registerGenericMCP();
85
+ result.integrations.mcp = {
86
+ registered: true,
87
+ path: getGenericMCPPath()
88
+ };
89
+ if (wantClaudeCode) {
90
+ const hooksOk = registerClaudeCodeHooks();
91
+ const claudeMdOk = updateClaudeMd();
92
+ result.integrations.claudeCode = {
93
+ hooks: hooksOk,
94
+ mcp: true,
95
+ claudeMd: claudeMdOk
96
+ };
97
+ }
98
+ if (wantCursor) {
99
+ const cursorRulesUpdated = registerCursorMCP();
100
+ result.integrations.cursor = {
101
+ mcp: true,
102
+ path: getCursorMcpConfigPath(),
103
+ cursorRules: cursorRulesUpdated,
104
+ cursorRulesPath: getCursorRulesPath()
105
+ };
106
+ }
107
+ if (wantCodex) {
108
+ const agentsMdUpdated = registerCodexMCP();
109
+ result.integrations.codex = {
110
+ mcp: true,
111
+ path: getCodexConfigFilePath(),
112
+ agentsMd: agentsMdUpdated,
113
+ agentsMdPath: getAgentsMdPath()
114
+ };
115
+ }
116
+ if (wantGemini) {
117
+ const geminiMdUpdated = registerGeminiMCP();
118
+ result.integrations.gemini = {
119
+ mcp: true,
120
+ path: getGeminiSettingsFilePath(),
121
+ geminiMd: geminiMdUpdated,
122
+ geminiMdPath: getGeminiMdPath()
123
+ };
124
+ }
125
+ if (format === "text") {
126
+ printTextOutput(result, wantClaudeCode, wantCursor, wantCodex, wantGemini);
127
+ return;
128
+ }
129
+ output(result, format);
130
+ }
131
+ function printTextOutput(result, claudeCode, cursor, codex = false, gemini = false) {
132
+ const w = (s) => process.stdout.write(s);
133
+ w("\nMemRosetta initialized successfully.\n\n");
134
+ w(" What was set up:\n");
135
+ w(" ----------------------------------------\n");
136
+ w(` Database: ${result.database.path}`);
137
+ w(result.database.created ? " (created)\n" : " (already exists)\n");
138
+ w(` MCP Server: ${result.integrations.mcp.path} (always included)
139
+ `);
140
+ const currentConfig = getConfig();
141
+ if (currentConfig.embeddingPreset && currentConfig.embeddingPreset !== "en") {
142
+ const presetLabels = {
143
+ multilingual: "multilingual (multilingual-e5-small)",
144
+ ko: "Korean (ko-sroberta-multitask)"
145
+ };
146
+ w(` Embeddings: ${presetLabels[currentConfig.embeddingPreset] ?? currentConfig.embeddingPreset}
147
+ `);
148
+ }
149
+ if (claudeCode) {
150
+ const cc = result.integrations.claudeCode;
151
+ if (cc.hooks) {
152
+ w(" Stop Hook: ~/.claude/settings.json (auto-save on session end)\n");
153
+ } else if (!isClaudeCodeInstalled()) {
154
+ w(" Stop Hook: SKIPPED (Claude Code not found at ~/.claude)\n");
155
+ w(' Install Claude Code first, then run "memrosetta init --claude-code" again.\n');
156
+ }
157
+ if (cc.claudeMd) {
158
+ w(" CLAUDE.md: ~/.claude/CLAUDE.md (memory instructions added)\n");
159
+ } else {
160
+ w(" CLAUDE.md: already configured\n");
161
+ }
162
+ }
163
+ if (cursor) {
164
+ w(` Cursor MCP: ${result.integrations.cursor.path}
165
+ `);
166
+ if (result.integrations.cursor.cursorRules) {
167
+ w(` .cursorrules: ${result.integrations.cursor.cursorRulesPath} (memory instructions added)
168
+ `);
169
+ } else {
170
+ w(" .cursorrules: already configured\n");
171
+ }
172
+ }
173
+ if (codex) {
174
+ w(` Codex MCP: ${result.integrations.codex.path}
175
+ `);
176
+ if (result.integrations.codex.agentsMd) {
177
+ w(` AGENTS.md: ${result.integrations.codex.agentsMdPath} (memory instructions added)
178
+ `);
179
+ } else {
180
+ w(" AGENTS.md: already configured\n");
181
+ }
182
+ }
183
+ if (gemini) {
184
+ w(` Gemini MCP: ${result.integrations.gemini.path}
185
+ `);
186
+ if (result.integrations.gemini.geminiMd) {
187
+ w(` GEMINI.md: ${result.integrations.gemini.geminiMdPath} (memory instructions added)
188
+ `);
189
+ } else {
190
+ w(" GEMINI.md: already configured\n");
191
+ }
192
+ }
193
+ w("\n");
194
+ if (!claudeCode && !cursor && !codex && !gemini) {
195
+ w(" MCP is ready. Add --claude-code, --cursor, --codex, or --gemini for tool-specific setup.\n");
196
+ w(" Example: memrosetta init --claude-code\n");
197
+ w("\n");
198
+ }
199
+ if (claudeCode) {
200
+ w(" Restart Claude Code to activate.\n\n");
201
+ }
202
+ }
203
+ export {
204
+ run
205
+ };