@aeriondyseti/vector-memory-mcp 1.1.0-dev.2 → 1.1.0-dev.3
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/package.json +1 -1
- package/dist/src/config/index.d.ts +17 -10
- package/dist/src/config/index.d.ts.map +1 -1
- package/dist/src/config/index.js +25 -11
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/db/conversation.repository.d.ts +26 -0
- package/dist/src/db/conversation.repository.d.ts.map +1 -0
- package/dist/src/db/conversation.repository.js +72 -0
- package/dist/src/db/conversation.repository.js.map +1 -0
- package/dist/src/db/conversation.schema.d.ts +4 -0
- package/dist/src/db/conversation.schema.d.ts.map +1 -0
- package/dist/src/db/conversation.schema.js +15 -0
- package/dist/src/db/conversation.schema.js.map +1 -0
- package/dist/src/db/lancedb-utils.d.ts +13 -3
- package/dist/src/db/lancedb-utils.d.ts.map +1 -1
- package/dist/src/db/lancedb-utils.js +36 -7
- package/dist/src/db/lancedb-utils.js.map +1 -1
- package/dist/src/db/memory.repository.js +7 -7
- package/dist/src/db/memory.repository.js.map +1 -1
- package/dist/src/http/server.d.ts.map +1 -1
- package/dist/src/http/server.js +26 -7
- package/dist/src/http/server.js.map +1 -1
- package/dist/src/index.js +7 -6
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/handlers.d.ts +1 -1
- package/dist/src/mcp/handlers.d.ts.map +1 -1
- package/dist/src/mcp/handlers.js +106 -117
- package/dist/src/mcp/handlers.js.map +1 -1
- package/dist/src/mcp/tools.d.ts.map +1 -1
- package/dist/src/mcp/tools.js +43 -14
- package/dist/src/mcp/tools.js.map +1 -1
- package/dist/src/services/conversation.service.d.ts +38 -0
- package/dist/src/services/conversation.service.d.ts.map +1 -0
- package/dist/src/services/conversation.service.js +252 -0
- package/dist/src/services/conversation.service.js.map +1 -0
- package/dist/src/services/memory.service.d.ts +7 -25
- package/dist/src/services/memory.service.d.ts.map +1 -1
- package/dist/src/services/memory.service.js +66 -80
- package/dist/src/services/memory.service.js.map +1 -1
- package/dist/src/services/parsers/claude-code.parser.d.ts +8 -0
- package/dist/src/services/parsers/claude-code.parser.d.ts.map +1 -0
- package/dist/src/services/parsers/claude-code.parser.js +191 -0
- package/dist/src/services/parsers/claude-code.parser.js.map +1 -0
- package/dist/src/services/parsers/types.d.ts +9 -0
- package/dist/src/services/parsers/types.d.ts.map +1 -0
- package/dist/src/services/parsers/types.js +2 -0
- package/dist/src/services/parsers/types.js.map +1 -0
- package/dist/src/types/conversation.d.ts +99 -0
- package/dist/src/types/conversation.d.ts.map +1 -0
- package/dist/src/types/conversation.js +2 -0
- package/dist/src/types/conversation.js.map +1 -0
- package/hooks/session-start.ts +60 -42
- package/package.json +1 -1
- package/src/config/index.ts +39 -21
- package/src/db/conversation.repository.ts +120 -0
- package/src/db/conversation.schema.ts +33 -0
- package/src/db/lancedb-utils.ts +35 -7
- package/src/db/memory.repository.ts +7 -7
- package/src/http/server.ts +31 -7
- package/src/index.ts +10 -11
- package/src/mcp/handlers.ts +121 -123
- package/src/mcp/tools.ts +44 -15
- package/src/services/conversation.service.ts +354 -0
- package/src/services/memory.service.ts +101 -105
- package/src/services/parsers/claude-code.parser.ts +242 -0
- package/src/services/parsers/types.ts +14 -0
- package/src/types/conversation.ts +108 -0
- package/dist/src/db/conversation-history.repository.d.ts +0 -24
- package/dist/src/db/conversation-history.repository.d.ts.map +0 -1
- package/dist/src/db/conversation-history.repository.js +0 -184
- package/dist/src/db/conversation-history.repository.js.map +0 -1
- package/dist/src/db/conversation-history.schema.d.ts +0 -10
- package/dist/src/db/conversation-history.schema.d.ts.map +0 -1
- package/dist/src/db/conversation-history.schema.js +0 -31
- package/dist/src/db/conversation-history.schema.js.map +0 -1
- package/dist/src/services/conversation-history.service.d.ts +0 -64
- package/dist/src/services/conversation-history.service.d.ts.map +0 -1
- package/dist/src/services/conversation-history.service.js +0 -244
- package/dist/src/services/conversation-history.service.js.map +0 -1
- package/dist/src/services/session-parser.d.ts +0 -59
- package/dist/src/services/session-parser.d.ts.map +0 -1
- package/dist/src/services/session-parser.js +0 -147
- package/dist/src/services/session-parser.js.map +0 -1
- package/dist/src/types/conversation-history.d.ts +0 -74
- package/dist/src/types/conversation-history.d.ts.map +0 -1
- package/dist/src/types/conversation-history.js +0 -2
- package/dist/src/types/conversation-history.js.map +0 -1
- package/src/db/conversation-history.repository.ts +0 -255
- package/src/db/conversation-history.schema.ts +0 -40
- package/src/services/conversation-history.service.ts +0 -320
- package/src/services/session-parser.ts +0 -232
- package/src/types/conversation-history.ts +0 -82
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { readFile, readdir, stat } from "fs/promises";
|
|
2
|
+
import { basename, dirname, join } from "path";
|
|
3
|
+
// UUID pattern for session IDs
|
|
4
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5
|
+
/** Extract text content from an assistant message's content array */
|
|
6
|
+
function extractAssistantText(content) {
|
|
7
|
+
return content
|
|
8
|
+
.filter((block) => block.type === "text" && block.text)
|
|
9
|
+
.map((block) => block.text)
|
|
10
|
+
.join("\n");
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Extract project name from path-encoded directory name.
|
|
14
|
+
* Claude Code encodes paths by replacing `/` with `-`, e.g. `/home/user/project` → `-home-user-project`.
|
|
15
|
+
* This is a lossy encoding: directory names containing literal dashes (e.g. `my-project`)
|
|
16
|
+
* cannot be distinguished from path separators, so `my-project` decodes as `my/project`.
|
|
17
|
+
* This is a known limitation of Claude Code's encoding scheme.
|
|
18
|
+
*/
|
|
19
|
+
function extractProjectFromDir(dirName) {
|
|
20
|
+
return dirName.startsWith("-")
|
|
21
|
+
? dirName.slice(1).replace(/-/g, "/")
|
|
22
|
+
: dirName;
|
|
23
|
+
}
|
|
24
|
+
export class ClaudeCodeSessionParser {
|
|
25
|
+
async parse(filePath, indexSubagents = false) {
|
|
26
|
+
const fileContent = await readFile(filePath, "utf-8");
|
|
27
|
+
const lines = fileContent.split("\n").filter((line) => line.trim());
|
|
28
|
+
const messages = [];
|
|
29
|
+
let messageIndex = 0;
|
|
30
|
+
// Derive session ID and project from file path
|
|
31
|
+
const fileName = basename(filePath, ".jsonl");
|
|
32
|
+
const parentDir = basename(dirname(filePath));
|
|
33
|
+
// Check if this is inside a subagents directory
|
|
34
|
+
const isSubagentFile = filePath.includes("/subagents/");
|
|
35
|
+
// For subagent files, project dir is 3 levels up: <project>/<session>/subagents/<file>
|
|
36
|
+
// For main files, project dir is direct parent
|
|
37
|
+
const projectDir = isSubagentFile
|
|
38
|
+
? basename(dirname(dirname(dirname(filePath))))
|
|
39
|
+
: parentDir;
|
|
40
|
+
const project = extractProjectFromDir(projectDir);
|
|
41
|
+
for (const line of lines) {
|
|
42
|
+
let entry;
|
|
43
|
+
try {
|
|
44
|
+
entry = JSON.parse(line);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Skip malformed lines
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const type = entry.type;
|
|
51
|
+
// Skip non-message entries
|
|
52
|
+
if (type === "progress" || type === "file-history-snapshot") {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// Skip subagent messages unless configured to include them
|
|
56
|
+
if (!indexSubagents && (entry.isSidechain === true || isSubagentFile)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (type !== "user" && type !== "assistant") {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const message = entry.message;
|
|
63
|
+
if (!message)
|
|
64
|
+
continue;
|
|
65
|
+
const role = message.role;
|
|
66
|
+
if (role !== "user" && role !== "assistant")
|
|
67
|
+
continue;
|
|
68
|
+
let content = null;
|
|
69
|
+
if (role === "user") {
|
|
70
|
+
const msgContent = message.content;
|
|
71
|
+
if (typeof msgContent === "string") {
|
|
72
|
+
content = msgContent;
|
|
73
|
+
}
|
|
74
|
+
else if (Array.isArray(msgContent)) {
|
|
75
|
+
// Array content in user messages = tool_result entries, skip
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (role === "assistant") {
|
|
80
|
+
const msgContent = message.content;
|
|
81
|
+
if (Array.isArray(msgContent)) {
|
|
82
|
+
content = extractAssistantText(msgContent);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Skip empty content
|
|
86
|
+
if (!content || content.trim().length === 0) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const sessionId = entry.sessionId ?? fileName;
|
|
90
|
+
messages.push({
|
|
91
|
+
uuid: entry.uuid ?? `${sessionId}-${messageIndex}`,
|
|
92
|
+
role: role,
|
|
93
|
+
content: content.trim(),
|
|
94
|
+
timestamp: entry.timestamp
|
|
95
|
+
? new Date(entry.timestamp)
|
|
96
|
+
: new Date(),
|
|
97
|
+
messageIndex,
|
|
98
|
+
sessionId,
|
|
99
|
+
project,
|
|
100
|
+
gitBranch: entry.gitBranch,
|
|
101
|
+
isSubagent: entry.isSidechain ?? isSubagentFile,
|
|
102
|
+
agentId: entry.agentId,
|
|
103
|
+
});
|
|
104
|
+
messageIndex++;
|
|
105
|
+
}
|
|
106
|
+
return messages;
|
|
107
|
+
}
|
|
108
|
+
async findSessionFiles(dirPath, since, indexSubagents = false) {
|
|
109
|
+
const files = [];
|
|
110
|
+
let dirents;
|
|
111
|
+
try {
|
|
112
|
+
dirents = await readdir(dirPath, { withFileTypes: true });
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return files;
|
|
116
|
+
}
|
|
117
|
+
for (const dirent of dirents) {
|
|
118
|
+
const entryPath = join(dirPath, dirent.name);
|
|
119
|
+
if (dirent.isDirectory()) {
|
|
120
|
+
if (dirent.name === "subagents") {
|
|
121
|
+
if (indexSubagents) {
|
|
122
|
+
const subFiles = await this.findSubagentFiles(entryPath, since, basename(dirname(dirname(entryPath))));
|
|
123
|
+
files.push(...subFiles);
|
|
124
|
+
}
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const subFiles = await this.findSessionFiles(entryPath, since, indexSubagents);
|
|
128
|
+
files.push(...subFiles);
|
|
129
|
+
}
|
|
130
|
+
else if (dirent.name.endsWith(".jsonl")) {
|
|
131
|
+
const sessionId = basename(dirent.name, ".jsonl");
|
|
132
|
+
if (!UUID_PATTERN.test(sessionId))
|
|
133
|
+
continue;
|
|
134
|
+
let entryStat;
|
|
135
|
+
try {
|
|
136
|
+
entryStat = await stat(entryPath);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const lastModified = entryStat.mtime;
|
|
142
|
+
if (since && lastModified <= since)
|
|
143
|
+
continue;
|
|
144
|
+
const projectDir = basename(dirPath);
|
|
145
|
+
const project = extractProjectFromDir(projectDir);
|
|
146
|
+
files.push({
|
|
147
|
+
filePath: entryPath,
|
|
148
|
+
sessionId,
|
|
149
|
+
project,
|
|
150
|
+
lastModified,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return files;
|
|
155
|
+
}
|
|
156
|
+
async findSubagentFiles(subagentsDir, since, projectDir) {
|
|
157
|
+
const files = [];
|
|
158
|
+
let entries;
|
|
159
|
+
try {
|
|
160
|
+
entries = await readdir(subagentsDir);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return files;
|
|
164
|
+
}
|
|
165
|
+
for (const entry of entries) {
|
|
166
|
+
if (!entry.endsWith(".jsonl"))
|
|
167
|
+
continue;
|
|
168
|
+
const entryPath = join(subagentsDir, entry);
|
|
169
|
+
let entryStat;
|
|
170
|
+
try {
|
|
171
|
+
entryStat = await stat(entryPath);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const lastModified = entryStat.mtime;
|
|
177
|
+
if (since && lastModified <= since)
|
|
178
|
+
continue;
|
|
179
|
+
const sessionId = basename(entry, ".jsonl");
|
|
180
|
+
const project = extractProjectFromDir(projectDir);
|
|
181
|
+
files.push({
|
|
182
|
+
filePath: entryPath,
|
|
183
|
+
sessionId,
|
|
184
|
+
project,
|
|
185
|
+
lastModified,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return files;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=claude-code.parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code.parser.js","sourceRoot":"","sources":["../../../../src/services/parsers/claude-code.parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI/C,+BAA+B;AAC/B,MAAM,YAAY,GAChB,iEAAiE,CAAC;AAEpE,qEAAqE;AACrE,SAAS,oBAAoB,CAC3B,OAA+C;IAE/C,OAAO,OAAO;SACX,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC;SACtD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAK,CAAC;SAC3B,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,qBAAqB,CAAC,OAAe;IAC5C,OAAO,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QAC5B,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;QACrC,CAAC,CAAC,OAAO,CAAC;AACd,CAAC;AAED,MAAM,OAAO,uBAAuB;IAClC,KAAK,CAAC,KAAK,CACT,QAAgB,EAChB,iBAA0B,KAAK;QAE/B,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAEpE,MAAM,QAAQ,GAAoB,EAAE,CAAC;QACrC,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,+CAA+C;QAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC9C,gDAAgD;QAChD,MAAM,cAAc,GAAG,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAExD,uFAAuF;QACvF,+CAA+C;QAC/C,MAAM,UAAU,GAAG,cAAc;YAC/B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC/C,CAAC,CAAC,SAAS,CAAC;QAEd,MAAM,OAAO,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;QAElD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,KAA8B,CAAC;YACnC,IAAI,CAAC;gBACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;gBACvB,SAAS;YACX,CAAC;YAED,MAAM,IAAI,GAAG,KAAK,CAAC,IAAc,CAAC;YAElC,2BAA2B;YAC3B,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,uBAAuB,EAAE,CAAC;gBAC5D,SAAS;YACX,CAAC;YAED,2DAA2D;YAC3D,IAAI,CAAC,cAAc,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,IAAI,IAAI,cAAc,CAAC,EAAE,CAAC;gBACtE,SAAS;YACX,CAAC;YAED,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC5C,SAAS;YACX,CAAC;YAED,MAAM,OAAO,GAAG,KAAK,CAAC,OAA8C,CAAC;YACrE,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAc,CAAC;YACpC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW;gBAAE,SAAS;YAEtD,IAAI,OAAO,GAAkB,IAAI,CAAC;YAElC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;gBACpB,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;gBACnC,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;oBACnC,OAAO,GAAG,UAAU,CAAC;gBACvB,CAAC;qBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;oBACrC,6DAA6D;oBAC7D,SAAS;gBACX,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;gBAChC,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;gBACnC,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC9B,OAAO,GAAG,oBAAoB,CAC5B,UAAoD,CACrD,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,qBAAqB;YACrB,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5C,SAAS;YACX,CAAC;YAED,MAAM,SAAS,GACZ,KAAK,CAAC,SAAoB,IAAI,QAAQ,CAAC;YAE1C,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAG,KAAK,CAAC,IAAe,IAAI,GAAG,SAAS,IAAI,YAAY,EAAE;gBAC9D,IAAI,EAAE,IAA4B;gBAClC,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;gBACvB,SAAS,EAAE,KAAK,CAAC,SAAS;oBACxB,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,SAAmB,CAAC;oBACrC,CAAC,CAAC,IAAI,IAAI,EAAE;gBACd,YAAY;gBACZ,SAAS;gBACT,OAAO;gBACP,SAAS,EAAE,KAAK,CAAC,SAA+B;gBAChD,UAAU,EAAG,KAAK,CAAC,WAAuB,IAAI,cAAc;gBAC5D,OAAO,EAAE,KAAK,CAAC,OAA6B;aAC7C,CAAC,CAAC;YAEH,YAAY,EAAE,CAAC;QACjB,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,gBAAgB,CACpB,OAAe,EACf,KAAY,EACZ,iBAA0B,KAAK;QAE/B,MAAM,KAAK,GAAsB,EAAE,CAAC;QAEpC,IAAI,OAA8B,CAAC;QACnC,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YAE7C,IAAI,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;gBACzB,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBAChC,IAAI,cAAc,EAAE,CAAC;wBACnB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAC3C,SAAS,EACT,KAAK,EACL,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CACtC,CAAC;wBACF,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;oBAC1B,CAAC;oBACD,SAAS;gBACX,CAAC;gBAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAC1C,SAAS,EACT,KAAK,EACL,cAAc,CACf,CAAC;gBACF,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;YAC1B,CAAC;iBAAM,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1C,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;gBAClD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;oBAAE,SAAS;gBAE5C,IAAI,SAAS,CAAC;gBACd,IAAI,CAAC;oBACH,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;gBACpC,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;gBAED,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC;gBACrC,IAAI,KAAK,IAAI,YAAY,IAAI,KAAK;oBAAE,SAAS;gBAE7C,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;gBACrC,MAAM,OAAO,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;gBAElD,KAAK,CAAC,IAAI,CAAC;oBACT,QAAQ,EAAE,SAAS;oBACnB,SAAS;oBACT,OAAO;oBACP,YAAY;iBACb,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAC7B,YAAoB,EACpB,KAAuB,EACvB,UAAkB;QAElB,MAAM,KAAK,GAAsB,EAAE,CAAC;QACpC,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAExC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YAC5C,IAAI,SAAS,CAAC;YACd,IAAI,CAAC;gBACH,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC;YACrC,IAAI,KAAK,IAAI,YAAY,IAAI,KAAK;gBAAE,SAAS;YAE7C,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC5C,MAAM,OAAO,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAElD,KAAK,CAAC,IAAI,CAAC;gBACT,QAAQ,EAAE,SAAS;gBACnB,SAAS;gBACT,OAAO;gBACP,YAAY;aACb,CAAC,CAAC;QACL,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedMessage, SessionFileInfo } from "../../types/conversation.js";
|
|
2
|
+
/** Interface for parsing session log files into structured messages */
|
|
3
|
+
export interface SessionLogParser {
|
|
4
|
+
/** Parse a session log file into ordered messages */
|
|
5
|
+
parse(filePath: string, indexSubagents?: boolean): Promise<ParsedMessage[]>;
|
|
6
|
+
/** Discover session log files in a directory */
|
|
7
|
+
findSessionFiles(dirPath: string, since?: Date, indexSubagents?: boolean): Promise<SessionFileInfo[]>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/services/parsers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAElF,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAE5E,gDAAgD;IAChD,gBAAgB,CACd,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,IAAI,EACZ,cAAc,CAAC,EAAE,OAAO,GACvB,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CAC/B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/services/parsers/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/** A single parsed message from a session log */
|
|
2
|
+
export interface ParsedMessage {
|
|
3
|
+
uuid: string;
|
|
4
|
+
role: "user" | "assistant";
|
|
5
|
+
content: string;
|
|
6
|
+
timestamp: Date;
|
|
7
|
+
messageIndex: number;
|
|
8
|
+
sessionId: string;
|
|
9
|
+
project: string;
|
|
10
|
+
gitBranch?: string;
|
|
11
|
+
isSubagent: boolean;
|
|
12
|
+
agentId?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Metadata stored per conversation chunk in the database */
|
|
15
|
+
export interface ConversationChunkMetadata {
|
|
16
|
+
session_id: string;
|
|
17
|
+
timestamp: string;
|
|
18
|
+
role: string;
|
|
19
|
+
message_index_start: number;
|
|
20
|
+
message_index_end: number;
|
|
21
|
+
project: string;
|
|
22
|
+
git_branch?: string;
|
|
23
|
+
is_subagent: boolean;
|
|
24
|
+
agent_id?: string;
|
|
25
|
+
}
|
|
26
|
+
/** A chunk of conversation ready for indexing */
|
|
27
|
+
export interface ConversationChunk {
|
|
28
|
+
id: string;
|
|
29
|
+
content: string;
|
|
30
|
+
sessionId: string;
|
|
31
|
+
timestamp: Date;
|
|
32
|
+
endTimestamp: Date;
|
|
33
|
+
role: string;
|
|
34
|
+
messageIndexStart: number;
|
|
35
|
+
messageIndexEnd: number;
|
|
36
|
+
project: string;
|
|
37
|
+
metadata: ConversationChunkMetadata;
|
|
38
|
+
}
|
|
39
|
+
/** Tracking record for an indexed session */
|
|
40
|
+
export interface IndexedSession {
|
|
41
|
+
sessionId: string;
|
|
42
|
+
filePath: string;
|
|
43
|
+
project: string;
|
|
44
|
+
lastModified: number;
|
|
45
|
+
chunkCount: number;
|
|
46
|
+
messageCount: number;
|
|
47
|
+
indexedAt: Date;
|
|
48
|
+
firstMessageAt: Date;
|
|
49
|
+
lastMessageAt: Date;
|
|
50
|
+
}
|
|
51
|
+
/** Raw row from conversation_history table with RRF score */
|
|
52
|
+
export interface ConversationHybridRow {
|
|
53
|
+
id: string;
|
|
54
|
+
content: string;
|
|
55
|
+
metadata: Record<string, unknown>;
|
|
56
|
+
createdAt: Date;
|
|
57
|
+
rrfScore: number;
|
|
58
|
+
}
|
|
59
|
+
/** Unified search result with source provenance */
|
|
60
|
+
export interface SearchResult {
|
|
61
|
+
id: string;
|
|
62
|
+
content: string;
|
|
63
|
+
metadata: Record<string, unknown>;
|
|
64
|
+
createdAt: Date;
|
|
65
|
+
updatedAt: Date;
|
|
66
|
+
source: "memory" | "conversation_history";
|
|
67
|
+
score: number;
|
|
68
|
+
supersededBy?: string | null;
|
|
69
|
+
usefulness?: number;
|
|
70
|
+
accessCount?: number;
|
|
71
|
+
lastAccessed?: Date | null;
|
|
72
|
+
sessionId?: string;
|
|
73
|
+
role?: string;
|
|
74
|
+
messageIndexStart?: number;
|
|
75
|
+
messageIndexEnd?: number;
|
|
76
|
+
}
|
|
77
|
+
/** Session file info returned by the parser's file discovery */
|
|
78
|
+
export interface SessionFileInfo {
|
|
79
|
+
filePath: string;
|
|
80
|
+
sessionId: string;
|
|
81
|
+
project: string;
|
|
82
|
+
lastModified: Date;
|
|
83
|
+
}
|
|
84
|
+
/** Search filter options for conversation history */
|
|
85
|
+
export interface HistoryFilters {
|
|
86
|
+
sessionId?: string;
|
|
87
|
+
role?: string;
|
|
88
|
+
project?: string;
|
|
89
|
+
after?: Date;
|
|
90
|
+
before?: Date;
|
|
91
|
+
}
|
|
92
|
+
/** Options for the integrated search across both sources */
|
|
93
|
+
export interface SearchOptions {
|
|
94
|
+
includeHistory?: boolean;
|
|
95
|
+
historyOnly?: boolean;
|
|
96
|
+
historyWeight?: number;
|
|
97
|
+
historyFilters?: HistoryFilters;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=conversation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/types/conversation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/types/conversation.ts"],"names":[],"mappings":""}
|
package/hooks/session-start.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* SessionStart hook for Claude Code
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* 1. Triggers incremental conversation history indexing (if enabled)
|
|
6
|
+
* 2. Loads and outputs the latest checkpoint with referenced memories
|
|
7
7
|
*
|
|
8
|
-
* Requires the server to be running with HTTP enabled.
|
|
8
|
+
* Requires the vector-memory-mcp server to be running with HTTP enabled.
|
|
9
9
|
*
|
|
10
10
|
* Usage in ~/.claude/settings.json:
|
|
11
11
|
* {
|
|
@@ -20,13 +20,8 @@
|
|
|
20
20
|
* }
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
import { MemoryRepository } from "../src/db/memory.repository.js";
|
|
26
|
-
import { EmbeddingsService } from "../src/services/embeddings.service.js";
|
|
27
|
-
import { MemoryService } from "../src/services/memory.service.js";
|
|
28
|
-
|
|
29
|
-
const VECTOR_MEMORY_URL = process.env.VECTOR_MEMORY_URL ?? "http://127.0.0.1:3271";
|
|
23
|
+
const VECTOR_MEMORY_URL =
|
|
24
|
+
process.env.VECTOR_MEMORY_URL ?? "http://127.0.0.1:3271";
|
|
30
25
|
|
|
31
26
|
interface HealthResponse {
|
|
32
27
|
status: string;
|
|
@@ -34,11 +29,19 @@ interface HealthResponse {
|
|
|
34
29
|
dbPath: string;
|
|
35
30
|
embeddingModel: string;
|
|
36
31
|
embeddingDimension: number;
|
|
32
|
+
historyEnabled: boolean;
|
|
37
33
|
};
|
|
38
34
|
}
|
|
39
35
|
|
|
36
|
+
interface CheckpointResponse {
|
|
37
|
+
content: string;
|
|
38
|
+
metadata: Record<string, unknown>;
|
|
39
|
+
referencedMemories: Array<{ id: string; content: string }>;
|
|
40
|
+
updatedAt: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
40
43
|
async function main() {
|
|
41
|
-
//
|
|
44
|
+
// Step 1: Check server is running and get config
|
|
42
45
|
let health: HealthResponse;
|
|
43
46
|
try {
|
|
44
47
|
const response = await fetch(`${VECTOR_MEMORY_URL}/health`);
|
|
@@ -54,47 +57,62 @@ async function main() {
|
|
|
54
57
|
throw error;
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
// Step 2: Trigger conversation history indexing (if enabled)
|
|
61
|
+
if (health.config.historyEnabled) {
|
|
62
|
+
try {
|
|
63
|
+
const indexResponse = await fetch(
|
|
64
|
+
`${VECTOR_MEMORY_URL}/index-conversations`,
|
|
65
|
+
{ method: "POST", headers: { "Content-Type": "application/json" }, body: "{}" }
|
|
66
|
+
);
|
|
67
|
+
if (indexResponse.ok) {
|
|
68
|
+
const result = await indexResponse.json();
|
|
69
|
+
if (result.indexed > 0 || result.errors?.length > 0) {
|
|
70
|
+
console.error(
|
|
71
|
+
`[vector-memory] Indexed ${result.indexed} sessions, skipped ${result.skipped}` +
|
|
72
|
+
(result.errors?.length > 0
|
|
73
|
+
? `, ${result.errors.length} errors`
|
|
74
|
+
: "")
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
// Non-fatal — indexing failure shouldn't block session start
|
|
80
|
+
console.error("[vector-memory] Conversation indexing failed, continuing.");
|
|
81
|
+
}
|
|
63
82
|
}
|
|
64
83
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
// Step 3: Load and output checkpoint
|
|
85
|
+
let checkpoint: CheckpointResponse;
|
|
86
|
+
try {
|
|
87
|
+
const response = await fetch(`${VECTOR_MEMORY_URL}/checkpoint`);
|
|
88
|
+
if (response.status === 404) {
|
|
89
|
+
console.log("No checkpoint found. Starting fresh session.");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new Error(`Checkpoint endpoint returned ${response.status}`);
|
|
94
|
+
}
|
|
95
|
+
checkpoint = await response.json();
|
|
96
|
+
} catch (error) {
|
|
97
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
98
|
+
console.error(`[vector-memory] Failed to load checkpoint: ${msg}`);
|
|
74
99
|
return;
|
|
75
100
|
}
|
|
76
101
|
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
let memoriesSection = "";
|
|
102
|
+
// Format output: checkpoint content + referenced memories
|
|
103
|
+
let output = checkpoint.content;
|
|
80
104
|
|
|
81
|
-
if (
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
memories.push(`### Memory: ${id}\n${memory.content}`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
if (memories.length > 0) {
|
|
90
|
-
memoriesSection = `\n\n## Referenced Memories\n\n${memories.join("\n\n")}`;
|
|
91
|
-
}
|
|
105
|
+
if (checkpoint.referencedMemories.length > 0) {
|
|
106
|
+
const memoriesSection = checkpoint.referencedMemories
|
|
107
|
+
.map((m) => `### Memory: ${m.id}\n${m.content}`)
|
|
108
|
+
.join("\n\n");
|
|
109
|
+
output += `\n\n## Referenced Memories\n\n${memoriesSection}`;
|
|
92
110
|
}
|
|
93
111
|
|
|
94
|
-
console.log(
|
|
112
|
+
console.log(output);
|
|
95
113
|
}
|
|
96
114
|
|
|
97
115
|
main().catch((err) => {
|
|
98
|
-
console.error("Error
|
|
116
|
+
console.error("Error in session-start hook:", err.message);
|
|
99
117
|
process.exit(1);
|
|
100
118
|
});
|
package/package.json
CHANGED
package/src/config/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import arg from "arg";
|
|
2
|
+
import { homedir } from "os";
|
|
2
3
|
import { isAbsolute, join } from "path";
|
|
3
4
|
import packageJson from "../../package.json" with { type: "json" };
|
|
4
5
|
|
|
@@ -6,6 +7,15 @@ export const VERSION = packageJson.version;
|
|
|
6
7
|
|
|
7
8
|
export type TransportMode = "stdio" | "http" | "both";
|
|
8
9
|
|
|
10
|
+
export interface ConversationHistoryConfig {
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
sessionLogPath: string | null;
|
|
13
|
+
historyWeight: number;
|
|
14
|
+
chunkOverlap: number;
|
|
15
|
+
maxChunkMessages: number;
|
|
16
|
+
indexSubagents: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
9
19
|
export interface Config {
|
|
10
20
|
dbPath: string;
|
|
11
21
|
embeddingModel: string;
|
|
@@ -14,11 +24,7 @@ export interface Config {
|
|
|
14
24
|
httpHost: string;
|
|
15
25
|
enableHttp: boolean;
|
|
16
26
|
transportMode: TransportMode;
|
|
17
|
-
conversationHistory:
|
|
18
|
-
enabled: boolean;
|
|
19
|
-
sessionPath: string | null; // null = auto-detect Claude Code session dir
|
|
20
|
-
historyWeight: number; // 0.0-1.0, applied to history scores when merging with memories
|
|
21
|
-
};
|
|
27
|
+
conversationHistory: ConversationHistoryConfig;
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
export interface ConfigOverrides {
|
|
@@ -26,11 +32,9 @@ export interface ConfigOverrides {
|
|
|
26
32
|
httpPort?: number;
|
|
27
33
|
enableHttp?: boolean;
|
|
28
34
|
transportMode?: TransportMode;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
historyWeight?: number;
|
|
33
|
-
};
|
|
35
|
+
enableHistory?: boolean;
|
|
36
|
+
historyPath?: string;
|
|
37
|
+
historyWeight?: number;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
// Defaults - always use repo-local .vector-memory folder
|
|
@@ -58,9 +62,12 @@ export function loadConfig(overrides: ConfigOverrides = {}): Config {
|
|
|
58
62
|
enableHttp,
|
|
59
63
|
transportMode,
|
|
60
64
|
conversationHistory: {
|
|
61
|
-
enabled: overrides.
|
|
62
|
-
|
|
63
|
-
historyWeight: overrides.
|
|
65
|
+
enabled: overrides.enableHistory ?? false,
|
|
66
|
+
sessionLogPath: overrides.historyPath ?? null,
|
|
67
|
+
historyWeight: overrides.historyWeight ?? 0.75,
|
|
68
|
+
chunkOverlap: 1,
|
|
69
|
+
maxChunkMessages: 10,
|
|
70
|
+
indexSubagents: false,
|
|
64
71
|
},
|
|
65
72
|
};
|
|
66
73
|
}
|
|
@@ -74,8 +81,9 @@ export function parseCliArgs(argv: string[]): ConfigOverrides {
|
|
|
74
81
|
"--db-file": String,
|
|
75
82
|
"--port": Number,
|
|
76
83
|
"--no-http": Boolean,
|
|
77
|
-
"--
|
|
78
|
-
"--
|
|
84
|
+
"--enable-history": Boolean,
|
|
85
|
+
"--history-path": String,
|
|
86
|
+
"--history-weight": Number,
|
|
79
87
|
|
|
80
88
|
// Aliases
|
|
81
89
|
"-d": "--db-file",
|
|
@@ -88,14 +96,24 @@ export function parseCliArgs(argv: string[]): ConfigOverrides {
|
|
|
88
96
|
dbPath: args["--db-file"],
|
|
89
97
|
httpPort: args["--port"],
|
|
90
98
|
enableHttp: args["--no-http"] ? false : undefined,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
sessionPath: args["--session-path"],
|
|
95
|
-
}
|
|
96
|
-
: undefined,
|
|
99
|
+
enableHistory: args["--enable-history"] ?? undefined,
|
|
100
|
+
historyPath: args["--history-path"],
|
|
101
|
+
historyWeight: args["--history-weight"],
|
|
97
102
|
};
|
|
98
103
|
}
|
|
99
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Resolve the session log path for conversation history indexing.
|
|
107
|
+
* Returns the configured path, or auto-detects Claude Code's session directory.
|
|
108
|
+
*/
|
|
109
|
+
export function resolveSessionLogPath(config: ConversationHistoryConfig): string {
|
|
110
|
+
if (config.sessionLogPath) {
|
|
111
|
+
return resolvePath(config.sessionLogPath);
|
|
112
|
+
}
|
|
113
|
+
// Auto-detect Claude Code session log directory
|
|
114
|
+
const claudeProjectsDir = join(homedir(), ".claude", "projects");
|
|
115
|
+
return claudeProjectsDir;
|
|
116
|
+
}
|
|
117
|
+
|
|
100
118
|
// Default config for imports that don't use CLI args
|
|
101
119
|
export const config = loadConfig();
|