@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
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import { createReadStream } from "fs";
|
|
2
|
-
import { readdir, stat } from "fs/promises";
|
|
3
|
-
import { createInterface } from "readline";
|
|
4
|
-
import { basename, join } from "path";
|
|
5
|
-
import { randomUUID } from "crypto";
|
|
6
|
-
import type { MessageRole } from "../types/conversation-history.js";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* A parsed message extracted from a Claude Code JSONL session file.
|
|
10
|
-
* Does not include embedding — that's added by the service layer.
|
|
11
|
-
*/
|
|
12
|
-
export interface ParsedMessage {
|
|
13
|
-
id: string;
|
|
14
|
-
sessionId: string;
|
|
15
|
-
role: MessageRole;
|
|
16
|
-
messageIndex: number;
|
|
17
|
-
content: string;
|
|
18
|
-
timestamp: Date;
|
|
19
|
-
metadata: Record<string, unknown>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Info about a discovered session file (before parsing).
|
|
24
|
-
*/
|
|
25
|
-
export interface SessionFileInfo {
|
|
26
|
-
sessionId: string;
|
|
27
|
-
filePath: string;
|
|
28
|
-
fileSize: number;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Result of parsing a single session file.
|
|
33
|
-
* Structurally mirrors IndexedSession but with nullable timestamps/metadata
|
|
34
|
-
* (a file with 0 messages has no timestamps). The service layer maps this to
|
|
35
|
-
* IndexedSession at write time, supplying messageCount and indexedAt.
|
|
36
|
-
*/
|
|
37
|
-
export interface ParseResult {
|
|
38
|
-
sessionId: string;
|
|
39
|
-
filePath: string;
|
|
40
|
-
fileSize: number;
|
|
41
|
-
messages: ParsedMessage[];
|
|
42
|
-
firstMessageAt: Date | null;
|
|
43
|
-
lastMessageAt: Date | null;
|
|
44
|
-
gitBranch: string | null;
|
|
45
|
-
project: string | null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// -- JSONL line shapes (only the fields we need) --
|
|
49
|
-
|
|
50
|
-
interface JournalLine {
|
|
51
|
-
type: string;
|
|
52
|
-
sessionId?: string;
|
|
53
|
-
timestamp?: string;
|
|
54
|
-
gitBranch?: string;
|
|
55
|
-
cwd?: string;
|
|
56
|
-
message?: {
|
|
57
|
-
role?: string;
|
|
58
|
-
content?: string | ContentBlock[];
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface ContentBlock {
|
|
63
|
-
type: string;
|
|
64
|
-
text?: string;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Extract the text content from a JSONL message line.
|
|
69
|
-
* - User messages: content is string OR array (skip tool_result blocks)
|
|
70
|
-
* - Assistant messages: content is array of blocks (keep only type=text)
|
|
71
|
-
* Returns null if no usable text content.
|
|
72
|
-
*/
|
|
73
|
-
function extractTextContent(line: JournalLine): string | null {
|
|
74
|
-
const content = line.message?.content;
|
|
75
|
-
if (content == null) return null;
|
|
76
|
-
|
|
77
|
-
// User messages can be a plain string
|
|
78
|
-
if (typeof content === "string") {
|
|
79
|
-
return content.trim() || null;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Array of content blocks — extract text blocks only
|
|
83
|
-
const textParts: string[] = [];
|
|
84
|
-
for (const block of content) {
|
|
85
|
-
if (block.type === "text" && block.text) {
|
|
86
|
-
textParts.push(block.text);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const joined = textParts.join("\n").trim();
|
|
91
|
-
return joined || null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Parse a single Claude Code JSONL session file.
|
|
96
|
-
*
|
|
97
|
-
* @param filePath - Absolute path to the .jsonl file
|
|
98
|
-
* @param fromByte - Byte offset to start reading from (for incremental parsing).
|
|
99
|
-
* When non-zero, messageIndex starts from startIndex.
|
|
100
|
-
* @param startIndex - Starting message index (for incremental parsing).
|
|
101
|
-
* @param knownFileSize - If already known (e.g. from discoverSessionFiles), avoids a redundant stat().
|
|
102
|
-
*/
|
|
103
|
-
export async function parseSessionFile(
|
|
104
|
-
filePath: string,
|
|
105
|
-
fromByte: number = 0,
|
|
106
|
-
startIndex: number = 0,
|
|
107
|
-
knownFileSize?: number,
|
|
108
|
-
): Promise<ParseResult> {
|
|
109
|
-
const fileSize = knownFileSize ?? (await stat(filePath)).size;
|
|
110
|
-
|
|
111
|
-
// Extract session ID from filename (e.g. "abc-123.jsonl" → "abc-123")
|
|
112
|
-
const sessionId = basename(filePath, ".jsonl");
|
|
113
|
-
|
|
114
|
-
const messages: ParsedMessage[] = [];
|
|
115
|
-
let messageIndex = startIndex;
|
|
116
|
-
let firstMessageAt: Date | null = null;
|
|
117
|
-
let lastMessageAt: Date | null = null;
|
|
118
|
-
let gitBranch: string | null = null;
|
|
119
|
-
let project: string | null = null;
|
|
120
|
-
|
|
121
|
-
const stream = createReadStream(filePath, {
|
|
122
|
-
encoding: "utf-8",
|
|
123
|
-
start: fromByte,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
const rl = createInterface({ input: stream, crlfDelay: Infinity });
|
|
127
|
-
|
|
128
|
-
for await (const rawLine of rl) {
|
|
129
|
-
if (!rawLine.trim()) continue;
|
|
130
|
-
|
|
131
|
-
let line: JournalLine;
|
|
132
|
-
try {
|
|
133
|
-
line = JSON.parse(rawLine);
|
|
134
|
-
} catch {
|
|
135
|
-
// Skip malformed lines
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Only process user and assistant messages
|
|
140
|
-
if (line.type !== "user" && line.type !== "assistant") continue;
|
|
141
|
-
|
|
142
|
-
// Capture metadata from first line that has it
|
|
143
|
-
if (gitBranch == null && line.gitBranch) gitBranch = line.gitBranch;
|
|
144
|
-
if (project == null && line.cwd) project = line.cwd;
|
|
145
|
-
|
|
146
|
-
const role: MessageRole = line.type === "user" ? "user" : "assistant";
|
|
147
|
-
const text = extractTextContent(line);
|
|
148
|
-
if (!text) continue;
|
|
149
|
-
|
|
150
|
-
const timestamp = line.timestamp ? new Date(line.timestamp) : new Date();
|
|
151
|
-
|
|
152
|
-
if (firstMessageAt == null) firstMessageAt = timestamp;
|
|
153
|
-
lastMessageAt = timestamp;
|
|
154
|
-
|
|
155
|
-
messages.push({
|
|
156
|
-
id: randomUUID(),
|
|
157
|
-
sessionId,
|
|
158
|
-
role,
|
|
159
|
-
messageIndex,
|
|
160
|
-
content: text,
|
|
161
|
-
timestamp,
|
|
162
|
-
metadata: {
|
|
163
|
-
...(line.gitBranch ? { gitBranch: line.gitBranch } : {}),
|
|
164
|
-
...(line.cwd ? { cwd: line.cwd } : {}),
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
messageIndex++;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
sessionId,
|
|
173
|
-
filePath,
|
|
174
|
-
fileSize,
|
|
175
|
-
messages,
|
|
176
|
-
firstMessageAt,
|
|
177
|
-
lastMessageAt,
|
|
178
|
-
gitBranch,
|
|
179
|
-
project,
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Discover all .jsonl session files in a directory.
|
|
185
|
-
* Stat calls are parallelized for efficiency.
|
|
186
|
-
*/
|
|
187
|
-
export async function discoverSessionFiles(
|
|
188
|
-
sessionDir: string,
|
|
189
|
-
): Promise<SessionFileInfo[]> {
|
|
190
|
-
let entries: string[];
|
|
191
|
-
try {
|
|
192
|
-
entries = await readdir(sessionDir);
|
|
193
|
-
} catch {
|
|
194
|
-
return [];
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const jsonlEntries = entries.filter((e) => e.endsWith(".jsonl"));
|
|
198
|
-
|
|
199
|
-
const settled = await Promise.allSettled(
|
|
200
|
-
jsonlEntries.map(async (entry) => {
|
|
201
|
-
const filePath = join(sessionDir, entry);
|
|
202
|
-
const fileStats = await stat(filePath);
|
|
203
|
-
if (!fileStats.isFile()) return null;
|
|
204
|
-
return {
|
|
205
|
-
sessionId: entry.replace(/\.jsonl$/, ""),
|
|
206
|
-
filePath,
|
|
207
|
-
fileSize: fileStats.size,
|
|
208
|
-
} satisfies SessionFileInfo;
|
|
209
|
-
}),
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
return settled
|
|
213
|
-
.filter(
|
|
214
|
-
(r): r is PromiseFulfilledResult<SessionFileInfo | null> =>
|
|
215
|
-
r.status === "fulfilled",
|
|
216
|
-
)
|
|
217
|
-
.map((r) => r.value)
|
|
218
|
-
.filter((v): v is SessionFileInfo => v != null);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Auto-detect the Claude Code sessions directory.
|
|
223
|
-
* Returns null if not found.
|
|
224
|
-
*/
|
|
225
|
-
export function detectSessionPath(): string | null {
|
|
226
|
-
const home = process.env.HOME ?? process.env.USERPROFILE;
|
|
227
|
-
if (!home) return null;
|
|
228
|
-
|
|
229
|
-
// Claude Code stores sessions at ~/.claude/projects/<project-slug>/<session-id>.jsonl
|
|
230
|
-
// We return the projects dir — the caller iterates project subdirs
|
|
231
|
-
return join(home, ".claude", "projects");
|
|
232
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import type { WithRrfScore } from "./memory.js";
|
|
2
|
-
|
|
3
|
-
export type MessageRole = "user" | "assistant";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* A single indexed message from a conversation session log.
|
|
7
|
-
* One entry per user/assistant text message — tool calls and results are excluded.
|
|
8
|
-
*/
|
|
9
|
-
export interface ConversationHistoryEntry {
|
|
10
|
-
id: string;
|
|
11
|
-
content: string;
|
|
12
|
-
embedding: number[];
|
|
13
|
-
sessionId: string;
|
|
14
|
-
role: MessageRole;
|
|
15
|
-
messageIndex: number;
|
|
16
|
-
timestamp: Date;
|
|
17
|
-
metadata: Record<string, unknown>;
|
|
18
|
-
createdAt: Date;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type ConversationHistoryHybridRow = WithRrfScore<ConversationHistoryEntry>;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Summary of an indexed session for list_indexed_sessions.
|
|
25
|
-
*/
|
|
26
|
-
export interface IndexedSessionSummary {
|
|
27
|
-
sessionId: string;
|
|
28
|
-
messageCount: number;
|
|
29
|
-
firstMessageAt: Date;
|
|
30
|
-
lastMessageAt: Date;
|
|
31
|
-
indexedAt: Date;
|
|
32
|
-
project?: string;
|
|
33
|
-
gitBranch?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Full indexed session record including storage-level fields (file path, size).
|
|
38
|
-
* Used by the repository for upsert operations and by the parser for tracking.
|
|
39
|
-
*/
|
|
40
|
-
export interface IndexedSession extends IndexedSessionSummary {
|
|
41
|
-
filePath: string;
|
|
42
|
-
fileSize: number;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Discriminated union for merged search results.
|
|
47
|
-
* Narrow on `source` to access type-specific fields.
|
|
48
|
-
*/
|
|
49
|
-
export interface MemorySearchResult {
|
|
50
|
-
source: "memory";
|
|
51
|
-
id: string;
|
|
52
|
-
content: string;
|
|
53
|
-
metadata: Record<string, unknown>;
|
|
54
|
-
score: number;
|
|
55
|
-
createdAt: Date;
|
|
56
|
-
updatedAt: Date;
|
|
57
|
-
supersededBy: string | null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface HistorySearchResult {
|
|
61
|
-
source: "conversation_history";
|
|
62
|
-
id: string;
|
|
63
|
-
content: string;
|
|
64
|
-
metadata: Record<string, unknown>;
|
|
65
|
-
score: number;
|
|
66
|
-
sessionId: string;
|
|
67
|
-
role: MessageRole;
|
|
68
|
-
messageIndex: number;
|
|
69
|
-
timestamp: Date;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export type SearchResult = MemorySearchResult | HistorySearchResult;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Summary returned by indexConversations() and reindexSession().
|
|
76
|
-
*/
|
|
77
|
-
export interface IndexingSummary {
|
|
78
|
-
sessionsDiscovered: number;
|
|
79
|
-
sessionsIndexed: number;
|
|
80
|
-
sessionsSkipped: number;
|
|
81
|
-
messagesIndexed: number;
|
|
82
|
-
}
|