@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.
Files changed (92) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/config/index.d.ts +17 -10
  3. package/dist/src/config/index.d.ts.map +1 -1
  4. package/dist/src/config/index.js +25 -11
  5. package/dist/src/config/index.js.map +1 -1
  6. package/dist/src/db/conversation.repository.d.ts +26 -0
  7. package/dist/src/db/conversation.repository.d.ts.map +1 -0
  8. package/dist/src/db/conversation.repository.js +72 -0
  9. package/dist/src/db/conversation.repository.js.map +1 -0
  10. package/dist/src/db/conversation.schema.d.ts +4 -0
  11. package/dist/src/db/conversation.schema.d.ts.map +1 -0
  12. package/dist/src/db/conversation.schema.js +15 -0
  13. package/dist/src/db/conversation.schema.js.map +1 -0
  14. package/dist/src/db/lancedb-utils.d.ts +13 -3
  15. package/dist/src/db/lancedb-utils.d.ts.map +1 -1
  16. package/dist/src/db/lancedb-utils.js +36 -7
  17. package/dist/src/db/lancedb-utils.js.map +1 -1
  18. package/dist/src/db/memory.repository.js +7 -7
  19. package/dist/src/db/memory.repository.js.map +1 -1
  20. package/dist/src/http/server.d.ts.map +1 -1
  21. package/dist/src/http/server.js +26 -7
  22. package/dist/src/http/server.js.map +1 -1
  23. package/dist/src/index.js +7 -6
  24. package/dist/src/index.js.map +1 -1
  25. package/dist/src/mcp/handlers.d.ts +1 -1
  26. package/dist/src/mcp/handlers.d.ts.map +1 -1
  27. package/dist/src/mcp/handlers.js +106 -117
  28. package/dist/src/mcp/handlers.js.map +1 -1
  29. package/dist/src/mcp/tools.d.ts.map +1 -1
  30. package/dist/src/mcp/tools.js +43 -14
  31. package/dist/src/mcp/tools.js.map +1 -1
  32. package/dist/src/services/conversation.service.d.ts +38 -0
  33. package/dist/src/services/conversation.service.d.ts.map +1 -0
  34. package/dist/src/services/conversation.service.js +252 -0
  35. package/dist/src/services/conversation.service.js.map +1 -0
  36. package/dist/src/services/memory.service.d.ts +7 -25
  37. package/dist/src/services/memory.service.d.ts.map +1 -1
  38. package/dist/src/services/memory.service.js +66 -80
  39. package/dist/src/services/memory.service.js.map +1 -1
  40. package/dist/src/services/parsers/claude-code.parser.d.ts +8 -0
  41. package/dist/src/services/parsers/claude-code.parser.d.ts.map +1 -0
  42. package/dist/src/services/parsers/claude-code.parser.js +191 -0
  43. package/dist/src/services/parsers/claude-code.parser.js.map +1 -0
  44. package/dist/src/services/parsers/types.d.ts +9 -0
  45. package/dist/src/services/parsers/types.d.ts.map +1 -0
  46. package/dist/src/services/parsers/types.js +2 -0
  47. package/dist/src/services/parsers/types.js.map +1 -0
  48. package/dist/src/types/conversation.d.ts +99 -0
  49. package/dist/src/types/conversation.d.ts.map +1 -0
  50. package/dist/src/types/conversation.js +2 -0
  51. package/dist/src/types/conversation.js.map +1 -0
  52. package/hooks/session-start.ts +60 -42
  53. package/package.json +1 -1
  54. package/src/config/index.ts +39 -21
  55. package/src/db/conversation.repository.ts +120 -0
  56. package/src/db/conversation.schema.ts +33 -0
  57. package/src/db/lancedb-utils.ts +35 -7
  58. package/src/db/memory.repository.ts +7 -7
  59. package/src/http/server.ts +31 -7
  60. package/src/index.ts +10 -11
  61. package/src/mcp/handlers.ts +121 -123
  62. package/src/mcp/tools.ts +44 -15
  63. package/src/services/conversation.service.ts +354 -0
  64. package/src/services/memory.service.ts +101 -105
  65. package/src/services/parsers/claude-code.parser.ts +242 -0
  66. package/src/services/parsers/types.ts +14 -0
  67. package/src/types/conversation.ts +108 -0
  68. package/dist/src/db/conversation-history.repository.d.ts +0 -24
  69. package/dist/src/db/conversation-history.repository.d.ts.map +0 -1
  70. package/dist/src/db/conversation-history.repository.js +0 -184
  71. package/dist/src/db/conversation-history.repository.js.map +0 -1
  72. package/dist/src/db/conversation-history.schema.d.ts +0 -10
  73. package/dist/src/db/conversation-history.schema.d.ts.map +0 -1
  74. package/dist/src/db/conversation-history.schema.js +0 -31
  75. package/dist/src/db/conversation-history.schema.js.map +0 -1
  76. package/dist/src/services/conversation-history.service.d.ts +0 -64
  77. package/dist/src/services/conversation-history.service.d.ts.map +0 -1
  78. package/dist/src/services/conversation-history.service.js +0 -244
  79. package/dist/src/services/conversation-history.service.js.map +0 -1
  80. package/dist/src/services/session-parser.d.ts +0 -59
  81. package/dist/src/services/session-parser.d.ts.map +0 -1
  82. package/dist/src/services/session-parser.js +0 -147
  83. package/dist/src/services/session-parser.js.map +0 -1
  84. package/dist/src/types/conversation-history.d.ts +0 -74
  85. package/dist/src/types/conversation-history.d.ts.map +0 -1
  86. package/dist/src/types/conversation-history.js +0 -2
  87. package/dist/src/types/conversation-history.js.map +0 -1
  88. package/src/db/conversation-history.repository.ts +0 -255
  89. package/src/db/conversation-history.schema.ts +0 -40
  90. package/src/services/conversation-history.service.ts +0 -320
  91. package/src/services/session-parser.ts +0 -232
  92. package/src/types/conversation-history.ts +0 -82
@@ -0,0 +1,242 @@
1
+ import { readFile, readdir, stat } from "fs/promises";
2
+ import { basename, dirname, join } from "path";
3
+ import type { ParsedMessage, SessionFileInfo } from "../../types/conversation.js";
4
+ import type { SessionLogParser } from "./types.js";
5
+
6
+ // UUID pattern for session IDs
7
+ const UUID_PATTERN =
8
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9
+
10
+ /** Extract text content from an assistant message's content array */
11
+ function extractAssistantText(
12
+ content: Array<{ type: string; text?: string }>
13
+ ): string {
14
+ return content
15
+ .filter((block) => block.type === "text" && block.text)
16
+ .map((block) => block.text!)
17
+ .join("\n");
18
+ }
19
+
20
+ /**
21
+ * Extract project name from path-encoded directory name.
22
+ * Claude Code encodes paths by replacing `/` with `-`, e.g. `/home/user/project` → `-home-user-project`.
23
+ * This is a lossy encoding: directory names containing literal dashes (e.g. `my-project`)
24
+ * cannot be distinguished from path separators, so `my-project` decodes as `my/project`.
25
+ * This is a known limitation of Claude Code's encoding scheme.
26
+ */
27
+ function extractProjectFromDir(dirName: string): string {
28
+ return dirName.startsWith("-")
29
+ ? dirName.slice(1).replace(/-/g, "/")
30
+ : dirName;
31
+ }
32
+
33
+ export class ClaudeCodeSessionParser implements SessionLogParser {
34
+ async parse(
35
+ filePath: string,
36
+ indexSubagents: boolean = false
37
+ ): Promise<ParsedMessage[]> {
38
+ const fileContent = await readFile(filePath, "utf-8");
39
+ const lines = fileContent.split("\n").filter((line) => line.trim());
40
+
41
+ const messages: ParsedMessage[] = [];
42
+ let messageIndex = 0;
43
+
44
+ // Derive session ID and project from file path
45
+ const fileName = basename(filePath, ".jsonl");
46
+ const parentDir = basename(dirname(filePath));
47
+ // Check if this is inside a subagents directory
48
+ const isSubagentFile = filePath.includes("/subagents/");
49
+
50
+ // For subagent files, project dir is 3 levels up: <project>/<session>/subagents/<file>
51
+ // For main files, project dir is direct parent
52
+ const projectDir = isSubagentFile
53
+ ? basename(dirname(dirname(dirname(filePath))))
54
+ : parentDir;
55
+
56
+ const project = extractProjectFromDir(projectDir);
57
+
58
+ for (const line of lines) {
59
+ let entry: Record<string, unknown>;
60
+ try {
61
+ entry = JSON.parse(line);
62
+ } catch {
63
+ // Skip malformed lines
64
+ continue;
65
+ }
66
+
67
+ const type = entry.type as string;
68
+
69
+ // Skip non-message entries
70
+ if (type === "progress" || type === "file-history-snapshot") {
71
+ continue;
72
+ }
73
+
74
+ // Skip subagent messages unless configured to include them
75
+ if (!indexSubagents && (entry.isSidechain === true || isSubagentFile)) {
76
+ continue;
77
+ }
78
+
79
+ if (type !== "user" && type !== "assistant") {
80
+ continue;
81
+ }
82
+
83
+ const message = entry.message as Record<string, unknown> | undefined;
84
+ if (!message) continue;
85
+
86
+ const role = message.role as string;
87
+ if (role !== "user" && role !== "assistant") continue;
88
+
89
+ let content: string | null = null;
90
+
91
+ if (role === "user") {
92
+ const msgContent = message.content;
93
+ if (typeof msgContent === "string") {
94
+ content = msgContent;
95
+ } else if (Array.isArray(msgContent)) {
96
+ // Array content in user messages = tool_result entries, skip
97
+ continue;
98
+ }
99
+ } else if (role === "assistant") {
100
+ const msgContent = message.content;
101
+ if (Array.isArray(msgContent)) {
102
+ content = extractAssistantText(
103
+ msgContent as Array<{ type: string; text?: string }>
104
+ );
105
+ }
106
+ }
107
+
108
+ // Skip empty content
109
+ if (!content || content.trim().length === 0) {
110
+ continue;
111
+ }
112
+
113
+ const sessionId =
114
+ (entry.sessionId as string) ?? fileName;
115
+
116
+ messages.push({
117
+ uuid: (entry.uuid as string) ?? `${sessionId}-${messageIndex}`,
118
+ role: role as "user" | "assistant",
119
+ content: content.trim(),
120
+ timestamp: entry.timestamp
121
+ ? new Date(entry.timestamp as string)
122
+ : new Date(),
123
+ messageIndex,
124
+ sessionId,
125
+ project,
126
+ gitBranch: entry.gitBranch as string | undefined,
127
+ isSubagent: (entry.isSidechain as boolean) ?? isSubagentFile,
128
+ agentId: entry.agentId as string | undefined,
129
+ });
130
+
131
+ messageIndex++;
132
+ }
133
+
134
+ return messages;
135
+ }
136
+
137
+ async findSessionFiles(
138
+ dirPath: string,
139
+ since?: Date,
140
+ indexSubagents: boolean = false
141
+ ): Promise<SessionFileInfo[]> {
142
+ const files: SessionFileInfo[] = [];
143
+
144
+ let dirents: import("fs").Dirent[];
145
+ try {
146
+ dirents = await readdir(dirPath, { withFileTypes: true });
147
+ } catch {
148
+ return files;
149
+ }
150
+
151
+ for (const dirent of dirents) {
152
+ const entryPath = join(dirPath, dirent.name);
153
+
154
+ if (dirent.isDirectory()) {
155
+ if (dirent.name === "subagents") {
156
+ if (indexSubagents) {
157
+ const subFiles = await this.findSubagentFiles(
158
+ entryPath,
159
+ since,
160
+ basename(dirname(dirname(entryPath)))
161
+ );
162
+ files.push(...subFiles);
163
+ }
164
+ continue;
165
+ }
166
+
167
+ const subFiles = await this.findSessionFiles(
168
+ entryPath,
169
+ since,
170
+ indexSubagents
171
+ );
172
+ files.push(...subFiles);
173
+ } else if (dirent.name.endsWith(".jsonl")) {
174
+ const sessionId = basename(dirent.name, ".jsonl");
175
+ if (!UUID_PATTERN.test(sessionId)) continue;
176
+
177
+ let entryStat;
178
+ try {
179
+ entryStat = await stat(entryPath);
180
+ } catch {
181
+ continue;
182
+ }
183
+
184
+ const lastModified = entryStat.mtime;
185
+ if (since && lastModified <= since) continue;
186
+
187
+ const projectDir = basename(dirPath);
188
+ const project = extractProjectFromDir(projectDir);
189
+
190
+ files.push({
191
+ filePath: entryPath,
192
+ sessionId,
193
+ project,
194
+ lastModified,
195
+ });
196
+ }
197
+ }
198
+
199
+ return files;
200
+ }
201
+
202
+ private async findSubagentFiles(
203
+ subagentsDir: string,
204
+ since: Date | undefined,
205
+ projectDir: string
206
+ ): Promise<SessionFileInfo[]> {
207
+ const files: SessionFileInfo[] = [];
208
+ let entries: string[];
209
+ try {
210
+ entries = await readdir(subagentsDir);
211
+ } catch {
212
+ return files;
213
+ }
214
+
215
+ for (const entry of entries) {
216
+ if (!entry.endsWith(".jsonl")) continue;
217
+
218
+ const entryPath = join(subagentsDir, entry);
219
+ let entryStat;
220
+ try {
221
+ entryStat = await stat(entryPath);
222
+ } catch {
223
+ continue;
224
+ }
225
+
226
+ const lastModified = entryStat.mtime;
227
+ if (since && lastModified <= since) continue;
228
+
229
+ const sessionId = basename(entry, ".jsonl");
230
+ const project = extractProjectFromDir(projectDir);
231
+
232
+ files.push({
233
+ filePath: entryPath,
234
+ sessionId,
235
+ project,
236
+ lastModified,
237
+ });
238
+ }
239
+
240
+ return files;
241
+ }
242
+ }
@@ -0,0 +1,14 @@
1
+ import type { ParsedMessage, SessionFileInfo } from "../../types/conversation.js";
2
+
3
+ /** Interface for parsing session log files into structured messages */
4
+ export interface SessionLogParser {
5
+ /** Parse a session log file into ordered messages */
6
+ parse(filePath: string, indexSubagents?: boolean): Promise<ParsedMessage[]>;
7
+
8
+ /** Discover session log files in a directory */
9
+ findSessionFiles(
10
+ dirPath: string,
11
+ since?: Date,
12
+ indexSubagents?: boolean
13
+ ): Promise<SessionFileInfo[]>;
14
+ }
@@ -0,0 +1,108 @@
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
+
15
+ /** Metadata stored per conversation chunk in the database */
16
+ export interface ConversationChunkMetadata {
17
+ session_id: string;
18
+ timestamp: string;
19
+ role: string;
20
+ message_index_start: number;
21
+ message_index_end: number;
22
+ project: string;
23
+ git_branch?: string;
24
+ is_subagent: boolean;
25
+ agent_id?: string;
26
+ }
27
+
28
+ /** A chunk of conversation ready for indexing */
29
+ export interface ConversationChunk {
30
+ id: string;
31
+ content: string;
32
+ sessionId: string;
33
+ timestamp: Date;
34
+ endTimestamp: Date;
35
+ role: string;
36
+ messageIndexStart: number;
37
+ messageIndexEnd: number;
38
+ project: string;
39
+ metadata: ConversationChunkMetadata;
40
+ }
41
+
42
+ /** Tracking record for an indexed session */
43
+ export interface IndexedSession {
44
+ sessionId: string;
45
+ filePath: string;
46
+ project: string;
47
+ lastModified: number;
48
+ chunkCount: number;
49
+ messageCount: number;
50
+ indexedAt: Date;
51
+ firstMessageAt: Date;
52
+ lastMessageAt: Date;
53
+ }
54
+
55
+ /** Raw row from conversation_history table with RRF score */
56
+ export interface ConversationHybridRow {
57
+ id: string;
58
+ content: string;
59
+ metadata: Record<string, unknown>;
60
+ createdAt: Date;
61
+ rrfScore: number;
62
+ }
63
+
64
+ /** Unified search result with source provenance */
65
+ export interface SearchResult {
66
+ id: string;
67
+ content: string;
68
+ metadata: Record<string, unknown>;
69
+ createdAt: Date;
70
+ updatedAt: Date;
71
+ source: "memory" | "conversation_history";
72
+ score: number;
73
+ // Memory-specific fields
74
+ supersededBy?: string | null;
75
+ usefulness?: number;
76
+ accessCount?: number;
77
+ lastAccessed?: Date | null;
78
+ // History-specific fields
79
+ sessionId?: string;
80
+ role?: string;
81
+ messageIndexStart?: number;
82
+ messageIndexEnd?: number;
83
+ }
84
+
85
+ /** Session file info returned by the parser's file discovery */
86
+ export interface SessionFileInfo {
87
+ filePath: string;
88
+ sessionId: string;
89
+ project: string;
90
+ lastModified: Date;
91
+ }
92
+
93
+ /** Search filter options for conversation history */
94
+ export interface HistoryFilters {
95
+ sessionId?: string;
96
+ role?: string;
97
+ project?: string;
98
+ after?: Date;
99
+ before?: Date;
100
+ }
101
+
102
+ /** Options for the integrated search across both sources */
103
+ export interface SearchOptions {
104
+ includeHistory?: boolean;
105
+ historyOnly?: boolean;
106
+ historyWeight?: number;
107
+ historyFilters?: HistoryFilters;
108
+ }
@@ -1,24 +0,0 @@
1
- import * as lancedb from "@lancedb/lancedb";
2
- import type { ConversationHistoryEntry, ConversationHistoryHybridRow, IndexedSession, IndexedSessionSummary } from "../types/conversation-history.js";
3
- export declare class ConversationHistoryRepository {
4
- private db;
5
- private tablePromise;
6
- private sessionsTablePromise;
7
- private ensureFtsIndex;
8
- private getReranker;
9
- constructor(db: lancedb.Connection);
10
- private getTable;
11
- private getSessionsTable;
12
- private rowToEntry;
13
- private rowToSessionSummary;
14
- private rowToSession;
15
- insert(entries: ConversationHistoryEntry[]): Promise<void>;
16
- findHybrid(embedding: number[], query: string, limit: number): Promise<ConversationHistoryHybridRow[]>;
17
- findBySessionId(sessionId: string): Promise<ConversationHistoryEntry[]>;
18
- deleteBySessionId(sessionId: string): Promise<number>;
19
- getIndexedSession(sessionId: string): Promise<IndexedSession | null>;
20
- upsertIndexedSession(session: IndexedSession): Promise<void>;
21
- listIndexedSessions(): Promise<IndexedSessionSummary[]>;
22
- deleteIndexedSession(sessionId: string): Promise<boolean>;
23
- }
24
- //# sourceMappingURL=conversation-history.repository.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"conversation-history.repository.d.ts","sourceRoot":"","sources":["../../../src/db/conversation-history.repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAC;AAe5C,OAAO,KAAK,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,cAAc,EACd,qBAAqB,EAEtB,MAAM,kCAAkC,CAAC;AAE1C,qBAAa,6BAA6B;IAW5B,OAAO,CAAC,EAAE;IATtB,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,oBAAoB,CAA+B;IAG3D,OAAO,CAAC,cAAc,CAAsB;IAG5C,OAAO,CAAC,WAAW,CAAyB;gBAExB,EAAE,EAAE,OAAO,CAAC,UAAU;IAI1C,OAAO,CAAC,QAAQ;IAchB,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,mBAAmB;IAe3B,OAAO,CAAC,YAAY;IAUd,MAAM,CAAC,OAAO,EAAE,wBAAwB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB1D,UAAU,CACd,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,4BAA4B,EAAE,CAAC;IAuBpC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAYvE,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBrD,iBAAiB,CACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAe3B,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B5D,mBAAmB,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;IASvD,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAehE"}
@@ -1,184 +0,0 @@
1
- import { CONVERSATION_HISTORY_TABLE, INDEXED_SESSIONS_TABLE, conversationHistorySchema, indexedSessionsSchema, } from "./conversation-history.schema.js";
2
- import { arrowVectorToArray, getOrCreateTable, createFtsMutex, createRerankerMutex, escapeLanceDbString, } from "./lancedb-utils.js";
3
- export class ConversationHistoryRepository {
4
- db;
5
- // Cached table handles — initialized once, retained for instance lifetime
6
- tablePromise = null;
7
- sessionsTablePromise = null;
8
- // FTS index mutex — once created, the promise is never cleared (index persists in LanceDB)
9
- ensureFtsIndex;
10
- // Cached reranker — k=60 is constant, no need to recreate per search
11
- getReranker = createRerankerMutex();
12
- constructor(db) {
13
- this.db = db;
14
- this.ensureFtsIndex = createFtsMutex(() => this.getTable());
15
- }
16
- getTable() {
17
- if (!this.tablePromise) {
18
- this.tablePromise = getOrCreateTable(this.db, CONVERSATION_HISTORY_TABLE, conversationHistorySchema).catch((e) => {
19
- this.tablePromise = null;
20
- throw e;
21
- });
22
- }
23
- return this.tablePromise;
24
- }
25
- getSessionsTable() {
26
- if (!this.sessionsTablePromise) {
27
- this.sessionsTablePromise = getOrCreateTable(this.db, INDEXED_SESSIONS_TABLE, indexedSessionsSchema).catch((e) => {
28
- this.sessionsTablePromise = null;
29
- throw e;
30
- });
31
- }
32
- return this.sessionsTablePromise;
33
- }
34
- rowToEntry(row) {
35
- return {
36
- id: row.id,
37
- content: row.content,
38
- embedding: arrowVectorToArray(row.vector),
39
- sessionId: row.session_id,
40
- role: row.role,
41
- messageIndex: row.message_index,
42
- timestamp: new Date(row.timestamp),
43
- metadata: JSON.parse(row.metadata),
44
- createdAt: new Date(row.created_at),
45
- };
46
- }
47
- rowToSessionSummary(row) {
48
- return {
49
- sessionId: row.session_id,
50
- messageCount: row.message_count,
51
- firstMessageAt: new Date(row.first_message_at),
52
- lastMessageAt: new Date(row.last_message_at),
53
- indexedAt: new Date(row.indexed_at),
54
- // Use null check (not truthiness) — empty string is a valid value distinct from null
55
- ...(row.project != null ? { project: row.project } : {}),
56
- ...(row.git_branch != null ? { gitBranch: row.git_branch } : {}),
57
- };
58
- }
59
- rowToSession(row) {
60
- return {
61
- ...this.rowToSessionSummary(row),
62
- filePath: row.file_path,
63
- fileSize: row.file_size,
64
- };
65
- }
66
- // --- Conversation History Operations ---
67
- async insert(entries) {
68
- if (entries.length === 0)
69
- return;
70
- const table = await this.getTable();
71
- await table.add(entries.map((entry) => ({
72
- id: entry.id,
73
- vector: entry.embedding,
74
- content: entry.content,
75
- session_id: entry.sessionId,
76
- role: entry.role,
77
- message_index: entry.messageIndex,
78
- timestamp: entry.timestamp.getTime(),
79
- metadata: JSON.stringify(entry.metadata),
80
- created_at: entry.createdAt.getTime(),
81
- })));
82
- }
83
- async findHybrid(embedding, query, limit) {
84
- await this.ensureFtsIndex();
85
- const table = await this.getTable();
86
- const reranker = await this.getReranker();
87
- const results = await table
88
- .query()
89
- .nearestTo(embedding)
90
- .fullTextSearch(query)
91
- .rerank(reranker)
92
- .limit(limit)
93
- .toArray();
94
- return results.map((row) => {
95
- const entry = this.rowToEntry(row);
96
- return {
97
- ...entry,
98
- rrfScore: row._relevance_score ?? 0,
99
- };
100
- });
101
- }
102
- async findBySessionId(sessionId) {
103
- const table = await this.getTable();
104
- const results = await table
105
- .query()
106
- .where(`session_id = '${escapeLanceDbString(sessionId)}'`)
107
- .toArray();
108
- return results.map((row) => this.rowToEntry(row));
109
- }
110
- async deleteBySessionId(sessionId) {
111
- const table = await this.getTable();
112
- // Select only id — avoids deserializing embedding vectors just for a count
113
- const existing = await table
114
- .query()
115
- .where(`session_id = '${escapeLanceDbString(sessionId)}'`)
116
- .select(["id"])
117
- .toArray();
118
- const count = existing.length;
119
- if (count > 0) {
120
- await table.delete(`session_id = '${escapeLanceDbString(sessionId)}'`);
121
- }
122
- return count;
123
- }
124
- // --- Indexed Sessions Tracking ---
125
- async getIndexedSession(sessionId) {
126
- const table = await this.getSessionsTable();
127
- const results = await table
128
- .query()
129
- .where(`session_id = '${escapeLanceDbString(sessionId)}'`)
130
- .limit(1)
131
- .toArray();
132
- if (results.length === 0) {
133
- return null;
134
- }
135
- return this.rowToSession(results[0]);
136
- }
137
- async upsertIndexedSession(session) {
138
- const table = await this.getSessionsTable();
139
- const existing = await table
140
- .query()
141
- .where(`session_id = '${escapeLanceDbString(session.sessionId)}'`)
142
- .limit(1)
143
- .toArray();
144
- const row = {
145
- session_id: session.sessionId,
146
- file_path: session.filePath,
147
- file_size: session.fileSize,
148
- message_count: session.messageCount,
149
- first_message_at: session.firstMessageAt.getTime(),
150
- last_message_at: session.lastMessageAt.getTime(),
151
- indexed_at: session.indexedAt.getTime(),
152
- project: session.project ?? null,
153
- git_branch: session.gitBranch ?? null,
154
- };
155
- if (existing.length === 0) {
156
- await table.add([row]);
157
- }
158
- else {
159
- await table.update({
160
- where: `session_id = '${escapeLanceDbString(session.sessionId)}'`,
161
- values: row,
162
- });
163
- }
164
- }
165
- async listIndexedSessions() {
166
- const table = await this.getSessionsTable();
167
- const results = await table.query().toArray();
168
- return results.map((row) => this.rowToSessionSummary(row));
169
- }
170
- async deleteIndexedSession(sessionId) {
171
- const table = await this.getSessionsTable();
172
- const existing = await table
173
- .query()
174
- .where(`session_id = '${escapeLanceDbString(sessionId)}'`)
175
- .limit(1)
176
- .toArray();
177
- if (existing.length === 0) {
178
- return false;
179
- }
180
- await table.delete(`session_id = '${escapeLanceDbString(sessionId)}'`);
181
- return true;
182
- }
183
- }
184
- //# sourceMappingURL=conversation-history.repository.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"conversation-history.repository.js","sourceRoot":"","sources":["../../../src/db/conversation-history.repository.ts"],"names":[],"mappings":"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"}
@@ -1,10 +0,0 @@
1
- import { Schema } from "apache-arrow";
2
- export declare const CONVERSATION_HISTORY_TABLE = "conversation_history";
3
- /**
4
- * Tracks which sessions have been indexed and their file sizes,
5
- * enabling idempotent incremental indexing.
6
- */
7
- export declare const INDEXED_SESSIONS_TABLE = "indexed_sessions";
8
- export declare const conversationHistorySchema: Schema<any>;
9
- export declare const indexedSessionsSchema: Schema<any>;
10
- //# sourceMappingURL=conversation-history.schema.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"conversation-history.schema.d.ts","sourceRoot":"","sources":["../../../src/db/conversation-history.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EAKP,MAAM,cAAc,CAAC;AAGtB,eAAO,MAAM,0BAA0B,yBAAyB,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAEzD,eAAO,MAAM,yBAAyB,aAUpC,CAAC;AAEH,eAAO,MAAM,qBAAqB,aAUhC,CAAC"}
@@ -1,31 +0,0 @@
1
- import { Schema, Field, Utf8, Int32, Float64, } from "apache-arrow";
2
- import { vectorField, timestampField } from "./schema.js";
3
- export const CONVERSATION_HISTORY_TABLE = "conversation_history";
4
- /**
5
- * Tracks which sessions have been indexed and their file sizes,
6
- * enabling idempotent incremental indexing.
7
- */
8
- export const INDEXED_SESSIONS_TABLE = "indexed_sessions";
9
- export const conversationHistorySchema = new Schema([
10
- new Field("id", new Utf8(), false),
11
- vectorField(),
12
- new Field("content", new Utf8(), false),
13
- new Field("session_id", new Utf8(), false),
14
- new Field("role", new Utf8(), false), // "user" | "assistant"
15
- new Field("message_index", new Int32(), false),
16
- timestampField("timestamp"),
17
- new Field("metadata", new Utf8(), false), // JSON string
18
- timestampField("created_at"),
19
- ]);
20
- export const indexedSessionsSchema = new Schema([
21
- new Field("session_id", new Utf8(), false),
22
- new Field("file_path", new Utf8(), false),
23
- new Field("file_size", new Float64(), false), // Float64 avoids Int32 overflow and BigInt handling
24
- new Field("message_count", new Int32(), false),
25
- timestampField("first_message_at"),
26
- timestampField("last_message_at"),
27
- timestampField("indexed_at"),
28
- new Field("project", new Utf8(), true), // Nullable
29
- new Field("git_branch", new Utf8(), true), // Nullable
30
- ]);
31
- //# sourceMappingURL=conversation-history.schema.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"conversation-history.schema.js","sourceRoot":"","sources":["../../../src/db/conversation-history.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,KAAK,EACL,IAAI,EACJ,KAAK,EACL,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,CAAC,MAAM,0BAA0B,GAAG,sBAAsB,CAAC;AAEjE;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,kBAAkB,CAAC;AAEzD,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,MAAM,CAAC;IAClD,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC;IAClC,WAAW,EAAE;IACb,IAAI,KAAK,CAAC,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC;IACvC,IAAI,KAAK,CAAC,YAAY,EAAE,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC;IAC1C,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC,EAAE,uBAAuB;IAC7D,IAAI,KAAK,CAAC,eAAe,EAAE,IAAI,KAAK,EAAE,EAAE,KAAK,CAAC;IAC9C,cAAc,CAAC,WAAW,CAAC;IAC3B,IAAI,KAAK,CAAC,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC,EAAE,cAAc;IACxD,cAAc,CAAC,YAAY,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,MAAM,CAAC;IAC9C,IAAI,KAAK,CAAC,YAAY,EAAE,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC;IAC1C,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC;IACzC,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,OAAO,EAAE,EAAE,KAAK,CAAC,EAAE,oDAAoD;IAClG,IAAI,KAAK,CAAC,eAAe,EAAE,IAAI,KAAK,EAAE,EAAE,KAAK,CAAC;IAC9C,cAAc,CAAC,kBAAkB,CAAC;IAClC,cAAc,CAAC,iBAAiB,CAAC;IACjC,cAAc,CAAC,YAAY,CAAC;IAC5B,IAAI,KAAK,CAAC,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC,EAAE,WAAW;IACnD,IAAI,KAAK,CAAC,YAAY,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC,EAAE,WAAW;CACvD,CAAC,CAAC"}