@memrosetta/cli 0.4.8 → 0.5.1
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.
- package/dist/chunk-4LNXT25H.js +891 -0
- package/dist/chunk-5PH2RDAS.js +750 -0
- package/dist/chunk-IKIJVRHU.js +16 -0
- package/dist/chunk-PMQKXYS6.js +752 -0
- package/dist/chunk-SYPVELIW.js +64 -0
- package/dist/chunk-TSA67QME.js +56 -0
- package/dist/chunk-UKGD7QXV.js +81 -0
- package/dist/chunk-UOT33X3Q.js +750 -0
- package/dist/chunk-VR3TRSC7.js +148 -0
- package/dist/clear-HNVVALWL.js +39 -0
- package/dist/compress-VZJHSVJK.js +33 -0
- package/dist/count-WRCFIWWS.js +24 -0
- package/dist/enforce-PHO4L7C2.js +381 -0
- package/dist/feedback-O6NKG46O.js +51 -0
- package/dist/hooks/enforce-claude-code.js +119 -0
- package/dist/hooks/enforce-codex.js +88 -0
- package/dist/hooks/on-prompt.js +9 -5
- package/dist/hooks/on-stop.js +8 -4
- package/dist/index.js +22 -16
- package/dist/ingest-JWLBIFEI.js +97 -0
- package/dist/init-ARU2CIOH.js +205 -0
- package/dist/init-C2MCDVWL.js +205 -0
- package/dist/init-ISP73KEC.js +210 -0
- package/dist/init-LIWL7Y3H.js +205 -0
- package/dist/init-VUJX3RRW.js +205 -0
- package/dist/invalidate-VUHHNZUX.js +40 -0
- package/dist/maintain-UUZ76QET.js +37 -0
- package/dist/relate-TEZ3GIIY.js +57 -0
- package/dist/reset-HQFOMYVP.js +129 -0
- package/dist/reset-OVU4A575.js +129 -0
- package/dist/reset-P62B444X.js +132 -0
- package/dist/reset-T6DPQCWI.js +129 -0
- package/dist/reset-WMDSMCAR.js +129 -0
- package/dist/search-IXV43G2C.js +48 -0
- package/dist/status-BLHKHB34.js +184 -0
- package/dist/status-CNGR7YDV.js +184 -0
- package/dist/status-FWHUUZ4R.js +184 -0
- package/dist/status-IHYARQXU.js +184 -0
- package/dist/store-DTN3PTFQ.js +101 -0
- package/dist/sync-EHYMBZHE.js +542 -0
- package/dist/working-memory-CH524PJA.js +53 -0
- package/package.json +8 -6
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
isValidTranscriptPath
|
|
4
|
+
} from "../chunk-IKIJVRHU.js";
|
|
5
|
+
|
|
6
|
+
// src/hooks/enforce-claude-code.ts
|
|
7
|
+
import { spawnSync } from "child_process";
|
|
8
|
+
import { mkdtempSync, readFileSync, writeFileSync, existsSync } from "fs";
|
|
9
|
+
import { tmpdir } from "os";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
function readStdinSync() {
|
|
12
|
+
try {
|
|
13
|
+
return readFileSync(0, "utf-8");
|
|
14
|
+
} catch {
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function parseEvent(raw) {
|
|
19
|
+
if (!raw.trim()) return {};
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(raw);
|
|
22
|
+
} catch {
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function normalizeContent(content) {
|
|
27
|
+
if (typeof content === "string") return content;
|
|
28
|
+
if (Array.isArray(content)) {
|
|
29
|
+
return content.map((part) => {
|
|
30
|
+
if (typeof part === "string") return part;
|
|
31
|
+
if (part && typeof part === "object" && "text" in part && typeof part.text === "string") {
|
|
32
|
+
return part.text;
|
|
33
|
+
}
|
|
34
|
+
return "";
|
|
35
|
+
}).filter((s) => s.length > 0).join("\n");
|
|
36
|
+
}
|
|
37
|
+
return "";
|
|
38
|
+
}
|
|
39
|
+
function findLastAssistantMessage(transcriptPath) {
|
|
40
|
+
if (!isValidTranscriptPath(transcriptPath) || !existsSync(transcriptPath)) {
|
|
41
|
+
return { assistantMessage: "" };
|
|
42
|
+
}
|
|
43
|
+
const lines = readFileSync(transcriptPath, "utf-8").split("\n").filter((l) => l.trim().length > 0);
|
|
44
|
+
let lastAssistant = "";
|
|
45
|
+
let userPromptBeforeAssistant = "";
|
|
46
|
+
let pendingUserPrompt = "";
|
|
47
|
+
for (const line of lines) {
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(line);
|
|
51
|
+
} catch {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const role = parsed.role ?? parsed.message?.role;
|
|
55
|
+
const content = normalizeContent(parsed.message?.content);
|
|
56
|
+
if (!role || !content) continue;
|
|
57
|
+
if (role === "user") {
|
|
58
|
+
pendingUserPrompt = content;
|
|
59
|
+
} else if (role === "assistant") {
|
|
60
|
+
lastAssistant = content;
|
|
61
|
+
userPromptBeforeAssistant = pendingUserPrompt;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
assistantMessage: lastAssistant,
|
|
66
|
+
userPrompt: userPromptBeforeAssistant || void 0
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function resolveMemrosettaCli() {
|
|
70
|
+
return process.env.MEMROSETTA_BIN ?? "memrosetta";
|
|
71
|
+
}
|
|
72
|
+
function main() {
|
|
73
|
+
try {
|
|
74
|
+
const stdin = readStdinSync();
|
|
75
|
+
const event = parseEvent(stdin);
|
|
76
|
+
if (!event.transcript_path) {
|
|
77
|
+
process.stdout.write("{}\n");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const turn = findLastAssistantMessage(event.transcript_path);
|
|
81
|
+
if (!turn.assistantMessage) {
|
|
82
|
+
process.stdout.write("{}\n");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const dir = mkdtempSync(join(tmpdir(), "mr-enforce-"));
|
|
86
|
+
const eventFile = join(dir, "event.json");
|
|
87
|
+
writeFileSync(
|
|
88
|
+
eventFile,
|
|
89
|
+
JSON.stringify({
|
|
90
|
+
client: "claude-code",
|
|
91
|
+
turnId: event.session_id,
|
|
92
|
+
assistantMessage: turn.assistantMessage,
|
|
93
|
+
userPrompt: turn.userPrompt,
|
|
94
|
+
cwd: event.cwd,
|
|
95
|
+
transcriptPath: event.transcript_path,
|
|
96
|
+
attempt: 1
|
|
97
|
+
}),
|
|
98
|
+
"utf-8"
|
|
99
|
+
);
|
|
100
|
+
const cli = resolveMemrosettaCli();
|
|
101
|
+
const res = spawnSync(
|
|
102
|
+
cli,
|
|
103
|
+
["enforce", "stop", "--client", "claude-code", "--event-json", eventFile, "--format", "json"],
|
|
104
|
+
{ encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
|
|
105
|
+
);
|
|
106
|
+
if (res.stdout) {
|
|
107
|
+
process.stdout.write(res.stdout);
|
|
108
|
+
}
|
|
109
|
+
if (res.stderr) {
|
|
110
|
+
process.stderr.write(res.stderr);
|
|
111
|
+
}
|
|
112
|
+
} catch (err) {
|
|
113
|
+
process.stderr.write(
|
|
114
|
+
`[memrosetta enforce wrapper] ${err instanceof Error ? err.message : String(err)}
|
|
115
|
+
`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
main();
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/hooks/enforce-codex.ts
|
|
4
|
+
import { spawnSync } from "child_process";
|
|
5
|
+
import { mkdtempSync, readFileSync, writeFileSync } from "fs";
|
|
6
|
+
import { tmpdir } from "os";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
function readStdinSync() {
|
|
9
|
+
try {
|
|
10
|
+
return readFileSync(0, "utf-8");
|
|
11
|
+
} catch {
|
|
12
|
+
return "";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function parseEvent(raw) {
|
|
16
|
+
if (!raw.trim()) return {};
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(raw);
|
|
19
|
+
} catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function resolveMemrosettaCli() {
|
|
24
|
+
return process.env.MEMROSETTA_BIN ?? "memrosetta";
|
|
25
|
+
}
|
|
26
|
+
function main() {
|
|
27
|
+
try {
|
|
28
|
+
const stdin = readStdinSync();
|
|
29
|
+
const event = parseEvent(stdin);
|
|
30
|
+
if (event.stop_hook_active) {
|
|
31
|
+
process.stdout.write("{}\n");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const assistantMessage = event.last_assistant_message ?? "";
|
|
35
|
+
if (!assistantMessage.trim()) {
|
|
36
|
+
process.stdout.write("{}\n");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const dir = mkdtempSync(join(tmpdir(), "mr-enforce-codex-"));
|
|
40
|
+
const eventFile = join(dir, "event.json");
|
|
41
|
+
writeFileSync(
|
|
42
|
+
eventFile,
|
|
43
|
+
JSON.stringify({
|
|
44
|
+
client: "codex",
|
|
45
|
+
turnId: event.turn_id ?? event.session_id,
|
|
46
|
+
assistantMessage,
|
|
47
|
+
cwd: event.cwd,
|
|
48
|
+
transcriptPath: event.transcript_path ?? void 0,
|
|
49
|
+
attempt: 1
|
|
50
|
+
}),
|
|
51
|
+
"utf-8"
|
|
52
|
+
);
|
|
53
|
+
const cli = resolveMemrosettaCli();
|
|
54
|
+
const res = spawnSync(
|
|
55
|
+
cli,
|
|
56
|
+
["enforce", "stop", "--client", "codex", "--event-json", eventFile, "--format", "json"],
|
|
57
|
+
{ encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
|
|
58
|
+
);
|
|
59
|
+
if (res.stderr) {
|
|
60
|
+
process.stderr.write(res.stderr);
|
|
61
|
+
}
|
|
62
|
+
let envelope = null;
|
|
63
|
+
if (res.stdout) {
|
|
64
|
+
try {
|
|
65
|
+
envelope = JSON.parse(res.stdout);
|
|
66
|
+
} catch {
|
|
67
|
+
envelope = null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (envelope?.status === "needs-continuation" && envelope.reason) {
|
|
71
|
+
process.stdout.write(
|
|
72
|
+
JSON.stringify({
|
|
73
|
+
decision: "block",
|
|
74
|
+
reason: `MemRosetta enforce: ${envelope.reason} \u2014 please revisit the turn and call memrosetta_store for anything worth keeping.`
|
|
75
|
+
}) + "\n"
|
|
76
|
+
);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
process.stdout.write("{}\n");
|
|
80
|
+
} catch (err) {
|
|
81
|
+
process.stderr.write(
|
|
82
|
+
`[memrosetta enforce codex wrapper] ${err instanceof Error ? err.message : String(err)}
|
|
83
|
+
`
|
|
84
|
+
);
|
|
85
|
+
process.stdout.write("{}\n");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
main();
|
package/dist/hooks/on-prompt.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
closeEngine,
|
|
4
|
-
getEngineWithTimeout
|
|
4
|
+
getEngineWithTimeout
|
|
5
|
+
} from "../chunk-TSA67QME.js";
|
|
6
|
+
import {
|
|
5
7
|
isValidTranscriptPath,
|
|
6
8
|
sanitizeSessionId
|
|
7
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-IKIJVRHU.js";
|
|
8
10
|
import {
|
|
9
|
-
extractMemories,
|
|
10
11
|
parseTranscript,
|
|
11
|
-
resolveUserId,
|
|
12
12
|
stripSystemReminders
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-UKGD7QXV.js";
|
|
14
|
+
import {
|
|
15
|
+
extractMemories,
|
|
16
|
+
resolveUserId
|
|
17
|
+
} from "../chunk-VR3TRSC7.js";
|
|
14
18
|
import {
|
|
15
19
|
getConfig
|
|
16
20
|
} from "../chunk-SEPYQK3J.js";
|
package/dist/hooks/on-stop.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
closeEngine,
|
|
4
|
-
getEngine
|
|
4
|
+
getEngine
|
|
5
|
+
} from "../chunk-TSA67QME.js";
|
|
6
|
+
import {
|
|
5
7
|
isValidTranscriptPath,
|
|
6
8
|
sanitizeSessionId
|
|
7
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-IKIJVRHU.js";
|
|
10
|
+
import {
|
|
11
|
+
parseTranscript
|
|
12
|
+
} from "../chunk-UKGD7QXV.js";
|
|
8
13
|
import {
|
|
9
14
|
extractMemories,
|
|
10
|
-
parseTranscript,
|
|
11
15
|
resolveUserId
|
|
12
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-VR3TRSC7.js";
|
|
13
17
|
import {
|
|
14
18
|
getConfig
|
|
15
19
|
} from "../chunk-SEPYQK3J.js";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
parseGlobalArgs
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-SYPVELIW.js";
|
|
5
5
|
import {
|
|
6
6
|
closeEngine
|
|
7
7
|
} from "./chunk-VAVUPQZA.js";
|
|
@@ -33,6 +33,7 @@ Commands:
|
|
|
33
33
|
compress Run compression only
|
|
34
34
|
update Update to latest version
|
|
35
35
|
sync Manage multi-device sync (enable/disable/status/now/device-id)
|
|
36
|
+
enforce Run the enforce backend for client Stop hooks (advanced)
|
|
36
37
|
|
|
37
38
|
Init Options:
|
|
38
39
|
(no flag) Initialize DB + MCP server (base setup)
|
|
@@ -116,17 +117,17 @@ async function main() {
|
|
|
116
117
|
try {
|
|
117
118
|
switch (command) {
|
|
118
119
|
case "store": {
|
|
119
|
-
const mod = await import("./store-
|
|
120
|
+
const mod = await import("./store-DTN3PTFQ.js");
|
|
120
121
|
await mod.run(commandOptions);
|
|
121
122
|
break;
|
|
122
123
|
}
|
|
123
124
|
case "search": {
|
|
124
|
-
const mod = await import("./search-
|
|
125
|
+
const mod = await import("./search-IXV43G2C.js");
|
|
125
126
|
await mod.run(commandOptions);
|
|
126
127
|
break;
|
|
127
128
|
}
|
|
128
129
|
case "ingest": {
|
|
129
|
-
const mod = await import("./ingest-
|
|
130
|
+
const mod = await import("./ingest-JWLBIFEI.js");
|
|
130
131
|
await mod.run(commandOptions);
|
|
131
132
|
break;
|
|
132
133
|
}
|
|
@@ -136,57 +137,57 @@ async function main() {
|
|
|
136
137
|
break;
|
|
137
138
|
}
|
|
138
139
|
case "count": {
|
|
139
|
-
const mod = await import("./count-
|
|
140
|
+
const mod = await import("./count-WRCFIWWS.js");
|
|
140
141
|
await mod.run(commandOptions);
|
|
141
142
|
break;
|
|
142
143
|
}
|
|
143
144
|
case "clear": {
|
|
144
|
-
const mod = await import("./clear-
|
|
145
|
+
const mod = await import("./clear-HNVVALWL.js");
|
|
145
146
|
await mod.run(commandOptions);
|
|
146
147
|
break;
|
|
147
148
|
}
|
|
148
149
|
case "relate": {
|
|
149
|
-
const mod = await import("./relate-
|
|
150
|
+
const mod = await import("./relate-TEZ3GIIY.js");
|
|
150
151
|
await mod.run(commandOptions);
|
|
151
152
|
break;
|
|
152
153
|
}
|
|
153
154
|
case "invalidate": {
|
|
154
|
-
const mod = await import("./invalidate-
|
|
155
|
+
const mod = await import("./invalidate-VUHHNZUX.js");
|
|
155
156
|
await mod.run(commandOptions);
|
|
156
157
|
break;
|
|
157
158
|
}
|
|
158
159
|
case "feedback": {
|
|
159
|
-
const mod = await import("./feedback-
|
|
160
|
+
const mod = await import("./feedback-O6NKG46O.js");
|
|
160
161
|
await mod.run(commandOptions);
|
|
161
162
|
break;
|
|
162
163
|
}
|
|
163
164
|
case "working-memory": {
|
|
164
|
-
const mod = await import("./working-memory-
|
|
165
|
+
const mod = await import("./working-memory-CH524PJA.js");
|
|
165
166
|
await mod.run(commandOptions);
|
|
166
167
|
break;
|
|
167
168
|
}
|
|
168
169
|
case "maintain": {
|
|
169
|
-
const mod = await import("./maintain-
|
|
170
|
+
const mod = await import("./maintain-UUZ76QET.js");
|
|
170
171
|
await mod.run(commandOptions);
|
|
171
172
|
break;
|
|
172
173
|
}
|
|
173
174
|
case "compress": {
|
|
174
|
-
const mod = await import("./compress-
|
|
175
|
+
const mod = await import("./compress-VZJHSVJK.js");
|
|
175
176
|
await mod.run(commandOptions);
|
|
176
177
|
break;
|
|
177
178
|
}
|
|
178
179
|
case "status": {
|
|
179
|
-
const mod = await import("./status-
|
|
180
|
+
const mod = await import("./status-FWHUUZ4R.js");
|
|
180
181
|
await mod.run(commandOptions);
|
|
181
182
|
break;
|
|
182
183
|
}
|
|
183
184
|
case "init": {
|
|
184
|
-
const mod = await import("./init-
|
|
185
|
+
const mod = await import("./init-ISP73KEC.js");
|
|
185
186
|
await mod.run(commandOptions);
|
|
186
187
|
break;
|
|
187
188
|
}
|
|
188
189
|
case "reset": {
|
|
189
|
-
const mod = await import("./reset-
|
|
190
|
+
const mod = await import("./reset-P62B444X.js");
|
|
190
191
|
await mod.run(commandOptions);
|
|
191
192
|
break;
|
|
192
193
|
}
|
|
@@ -196,7 +197,12 @@ async function main() {
|
|
|
196
197
|
break;
|
|
197
198
|
}
|
|
198
199
|
case "sync": {
|
|
199
|
-
const mod = await import("./sync-
|
|
200
|
+
const mod = await import("./sync-EHYMBZHE.js");
|
|
201
|
+
await mod.run(commandOptions);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
case "enforce": {
|
|
205
|
+
const mod = await import("./enforce-PHO4L7C2.js");
|
|
200
206
|
await mod.run(commandOptions);
|
|
201
207
|
break;
|
|
202
208
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseTranscriptContent
|
|
3
|
+
} from "./chunk-UKGD7QXV.js";
|
|
4
|
+
import {
|
|
5
|
+
classifyTurn
|
|
6
|
+
} from "./chunk-VR3TRSC7.js";
|
|
7
|
+
import {
|
|
8
|
+
optionalOption
|
|
9
|
+
} from "./chunk-SYPVELIW.js";
|
|
10
|
+
import {
|
|
11
|
+
getEngine
|
|
12
|
+
} from "./chunk-VAVUPQZA.js";
|
|
13
|
+
import {
|
|
14
|
+
output,
|
|
15
|
+
outputError
|
|
16
|
+
} from "./chunk-ET6TNQOJ.js";
|
|
17
|
+
import {
|
|
18
|
+
getDefaultUserId
|
|
19
|
+
} from "./chunk-SEPYQK3J.js";
|
|
20
|
+
|
|
21
|
+
// src/commands/ingest.ts
|
|
22
|
+
import { readFileSync } from "fs";
|
|
23
|
+
function turnsToMemories(turns, userId, namespace, sessionShort) {
|
|
24
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25
|
+
const memories = [];
|
|
26
|
+
for (let i = 0; i < turns.length; i++) {
|
|
27
|
+
const turn = turns[i];
|
|
28
|
+
if (turn.content.length < 20) continue;
|
|
29
|
+
const content = turn.content.length > 500 ? turn.content.slice(0, 497) + "..." : turn.content;
|
|
30
|
+
memories.push({
|
|
31
|
+
userId,
|
|
32
|
+
namespace: namespace ?? `session-${sessionShort}`,
|
|
33
|
+
memoryType: classifyTurn(turn),
|
|
34
|
+
content,
|
|
35
|
+
documentDate: now,
|
|
36
|
+
sourceId: `cc-${sessionShort}-${i}`,
|
|
37
|
+
confidence: turn.role === "user" ? 0.9 : 0.8
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return memories;
|
|
41
|
+
}
|
|
42
|
+
async function readStdin() {
|
|
43
|
+
const chunks = [];
|
|
44
|
+
for await (const chunk of process.stdin) {
|
|
45
|
+
chunks.push(chunk);
|
|
46
|
+
}
|
|
47
|
+
return Buffer.concat(chunks).toString("utf-8").trim();
|
|
48
|
+
}
|
|
49
|
+
async function run(options) {
|
|
50
|
+
const { args, format, db, noEmbeddings } = options;
|
|
51
|
+
const userId = optionalOption(args, "--user") ?? getDefaultUserId();
|
|
52
|
+
const file = optionalOption(args, "--file");
|
|
53
|
+
const namespace = optionalOption(args, "--namespace");
|
|
54
|
+
let content;
|
|
55
|
+
if (file) {
|
|
56
|
+
try {
|
|
57
|
+
content = readFileSync(file, "utf-8");
|
|
58
|
+
} catch (err) {
|
|
59
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
60
|
+
outputError(`Failed to read file: ${msg}`, format);
|
|
61
|
+
process.exitCode = 1;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
content = await readStdin();
|
|
66
|
+
}
|
|
67
|
+
if (!content) {
|
|
68
|
+
outputError("No transcript content provided", format);
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const parsed = parseTranscriptContent(content);
|
|
73
|
+
const sessionShort = parsed.sessionId ? parsed.sessionId.slice(0, 8) : "unknown";
|
|
74
|
+
const memories = turnsToMemories(
|
|
75
|
+
parsed.turns,
|
|
76
|
+
userId,
|
|
77
|
+
namespace,
|
|
78
|
+
sessionShort
|
|
79
|
+
);
|
|
80
|
+
if (memories.length === 0) {
|
|
81
|
+
output({ stored: 0, message: "No memories extracted from transcript" }, format);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const engine = await getEngine({ db, noEmbeddings });
|
|
85
|
+
const stored = await engine.storeBatch(memories);
|
|
86
|
+
output(
|
|
87
|
+
{
|
|
88
|
+
stored: stored.length,
|
|
89
|
+
sessionId: parsed.sessionId || void 0,
|
|
90
|
+
namespace: namespace ?? `session-${sessionShort}`
|
|
91
|
+
},
|
|
92
|
+
format
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
run
|
|
97
|
+
};
|
|
@@ -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-SYPVELIW.js";
|
|
21
|
+
import {
|
|
22
|
+
getDefaultDbPath,
|
|
23
|
+
getEngine
|
|
24
|
+
} from "./chunk-VAVUPQZA.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
|
+
};
|