@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,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":"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"}
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -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":"AAAA,iDAAiD;AACjD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,6DAA6D;AAC7D,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,iDAAiD;AACjD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,YAAY,EAAE,IAAI,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,yBAAyB,CAAC;CACrC;AAED,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;IAChB,cAAc,EAAE,IAAI,CAAC;IACrB,aAAa,EAAE,IAAI,CAAC;CACrB;AAED,6DAA6D;AAC7D,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,QAAQ,GAAG,sBAAsB,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IAEd,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAE3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,IAAI,CAAC;CACpB;AAED,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,MAAM,CAAC,EAAE,IAAI,CAAC;CACf;AAED,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/types/conversation.ts"],"names":[],"mappings":""}
@@ -2,10 +2,10 @@
2
2
  /**
3
3
  * SessionStart hook for Claude Code
4
4
  *
5
- * Fetches config from the running vector-memory server's /health endpoint,
6
- * then retrieves and outputs the latest checkpoint.
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
- import { existsSync } from "fs";
24
- import { connectToDatabase } from "../src/db/connection.js";
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
- // Get config from running server
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
- const { dbPath, embeddingModel, embeddingDimension } = health.config;
58
-
59
- // Check if DB exists
60
- if (!existsSync(dbPath)) {
61
- console.log("Vector memory database not found. Starting fresh session.");
62
- return;
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
- const db = await connectToDatabase(dbPath);
66
- const repository = new MemoryRepository(db);
67
- const embeddings = new EmbeddingsService(embeddingModel, embeddingDimension);
68
- const service = new MemoryService(repository, embeddings);
69
-
70
- const checkpoint = await service.getLatestCheckpoint();
71
-
72
- if (!checkpoint) {
73
- console.log("No checkpoint found. Starting fresh session.");
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
- // Fetch referenced memories if any
78
- const memoryIds = (checkpoint.metadata.memory_ids as string[] | undefined) ?? [];
79
- let memoriesSection = "";
102
+ // Format output: checkpoint content + referenced memories
103
+ let output = checkpoint.content;
80
104
 
81
- if (memoryIds.length > 0) {
82
- const memories: string[] = [];
83
- for (const id of memoryIds) {
84
- const memory = await service.get(id);
85
- if (memory) {
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(checkpoint.content + memoriesSection);
112
+ console.log(output);
95
113
  }
96
114
 
97
115
  main().catch((err) => {
98
- console.error("Error loading checkpoint:", err.message);
116
+ console.error("Error in session-start hook:", err.message);
99
117
  process.exit(1);
100
118
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeriondyseti/vector-memory-mcp",
3
- "version": "1.1.0-dev.2",
3
+ "version": "1.1.0-dev.3",
4
4
  "description": "A zero-configuration RAG memory server for MCP clients",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -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
- conversationHistory?: {
30
- enabled?: boolean;
31
- sessionPath?: string;
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.conversationHistory?.enabled ?? false,
62
- sessionPath: overrides.conversationHistory?.sessionPath ?? null,
63
- historyWeight: overrides.conversationHistory?.historyWeight ?? 0.5,
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
- "--conversation-history": Boolean,
78
- "--session-path": String,
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
- conversationHistory: args["--conversation-history"] || args["--session-path"]
92
- ? {
93
- enabled: args["--conversation-history"],
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();