super-memory-pro 0.2.0

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 (107) hide show
  1. package/README.md +247 -0
  2. package/dist/config.d.ts +6 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +25 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/db/connection.d.ts +20 -0
  7. package/dist/db/connection.d.ts.map +1 -0
  8. package/dist/db/connection.js +66 -0
  9. package/dist/db/connection.js.map +1 -0
  10. package/dist/db/migrations/001_initial.sql +102 -0
  11. package/dist/db/migrations.d.ts +14 -0
  12. package/dist/db/migrations.d.ts.map +1 -0
  13. package/dist/db/migrations.js +86 -0
  14. package/dist/db/migrations.js.map +1 -0
  15. package/dist/db/queries.d.ts +24 -0
  16. package/dist/db/queries.d.ts.map +1 -0
  17. package/dist/db/queries.js +179 -0
  18. package/dist/db/queries.js.map +1 -0
  19. package/dist/hooks/event-handler.d.ts +13 -0
  20. package/dist/hooks/event-handler.d.ts.map +1 -0
  21. package/dist/hooks/event-handler.js +80 -0
  22. package/dist/hooks/event-handler.js.map +1 -0
  23. package/dist/hooks/index.d.ts +4 -0
  24. package/dist/hooks/index.d.ts.map +1 -0
  25. package/dist/hooks/index.js +7 -0
  26. package/dist/hooks/index.js.map +1 -0
  27. package/dist/hooks/message-handler.d.ts +13 -0
  28. package/dist/hooks/message-handler.d.ts.map +1 -0
  29. package/dist/hooks/message-handler.js +47 -0
  30. package/dist/hooks/message-handler.js.map +1 -0
  31. package/dist/hooks/session-compactor.d.ts +15 -0
  32. package/dist/hooks/session-compactor.d.ts.map +1 -0
  33. package/dist/hooks/session-compactor.js +40 -0
  34. package/dist/hooks/session-compactor.js.map +1 -0
  35. package/dist/hooks/system-transform.d.ts +27 -0
  36. package/dist/hooks/system-transform.d.ts.map +1 -0
  37. package/dist/hooks/system-transform.js +76 -0
  38. package/dist/hooks/system-transform.js.map +1 -0
  39. package/dist/hooks/tool-handler.d.ts +14 -0
  40. package/dist/hooks/tool-handler.d.ts.map +1 -0
  41. package/dist/hooks/tool-handler.js +94 -0
  42. package/dist/hooks/tool-handler.js.map +1 -0
  43. package/dist/index.d.ts +4 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +152 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/installer/index.d.ts +19 -0
  48. package/dist/installer/index.d.ts.map +1 -0
  49. package/dist/installer/index.js +553 -0
  50. package/dist/installer/index.js.map +1 -0
  51. package/dist/memory/extractor.d.ts +29 -0
  52. package/dist/memory/extractor.d.ts.map +1 -0
  53. package/dist/memory/extractor.js +426 -0
  54. package/dist/memory/extractor.js.map +1 -0
  55. package/dist/memory/index.d.ts +7 -0
  56. package/dist/memory/index.d.ts.map +1 -0
  57. package/dist/memory/index.js +7 -0
  58. package/dist/memory/index.js.map +1 -0
  59. package/dist/memory/processor.d.ts +50 -0
  60. package/dist/memory/processor.d.ts.map +1 -0
  61. package/dist/memory/processor.js +199 -0
  62. package/dist/memory/processor.js.map +1 -0
  63. package/dist/memory/search.d.ts +35 -0
  64. package/dist/memory/search.d.ts.map +1 -0
  65. package/dist/memory/search.js +170 -0
  66. package/dist/memory/search.js.map +1 -0
  67. package/dist/memory/store.d.ts +32 -0
  68. package/dist/memory/store.d.ts.map +1 -0
  69. package/dist/memory/store.js +112 -0
  70. package/dist/memory/store.js.map +1 -0
  71. package/dist/server/index.d.ts +16 -0
  72. package/dist/server/index.d.ts.map +1 -0
  73. package/dist/server/index.js +49 -0
  74. package/dist/server/index.js.map +1 -0
  75. package/dist/server/middleware/async-handler.d.ts +11 -0
  76. package/dist/server/middleware/async-handler.d.ts.map +1 -0
  77. package/dist/server/middleware/async-handler.js +14 -0
  78. package/dist/server/middleware/async-handler.js.map +1 -0
  79. package/dist/server/middleware/error-handler.d.ts +11 -0
  80. package/dist/server/middleware/error-handler.d.ts.map +1 -0
  81. package/dist/server/middleware/error-handler.js +18 -0
  82. package/dist/server/middleware/error-handler.js.map +1 -0
  83. package/dist/server/routes/health.d.ts +2 -0
  84. package/dist/server/routes/health.d.ts.map +1 -0
  85. package/dist/server/routes/health.js +25 -0
  86. package/dist/server/routes/health.js.map +1 -0
  87. package/dist/server/routes/memory.d.ts +2 -0
  88. package/dist/server/routes/memory.d.ts.map +1 -0
  89. package/dist/server/routes/memory.js +139 -0
  90. package/dist/server/routes/memory.js.map +1 -0
  91. package/dist/server/schemas.d.ts +51 -0
  92. package/dist/server/schemas.d.ts.map +1 -0
  93. package/dist/server/schemas.js +23 -0
  94. package/dist/server/schemas.js.map +1 -0
  95. package/dist/tools/definitions.d.ts +130 -0
  96. package/dist/tools/definitions.d.ts.map +1 -0
  97. package/dist/tools/definitions.js +78 -0
  98. package/dist/tools/definitions.js.map +1 -0
  99. package/dist/tools/index.d.ts +32 -0
  100. package/dist/tools/index.d.ts.map +1 -0
  101. package/dist/tools/index.js +148 -0
  102. package/dist/tools/index.js.map +1 -0
  103. package/dist/types.d.ts +108 -0
  104. package/dist/types.d.ts.map +1 -0
  105. package/dist/types.js +12 -0
  106. package/dist/types.js.map +1 -0
  107. package/package.json +70 -0
@@ -0,0 +1,199 @@
1
+ // ─── Memory Processor ──────────────────────────────────────────────────────
2
+ // Orchestrator that combines extraction, storage, and search.
3
+ // This is the primary entry point for the memory system.
4
+ import { extractTechStack, extractDecisions, extractUserPreferences, extractPatterns, classifyContent, } from './extractor.js';
5
+ import { storeMemories } from './store.js';
6
+ import { searchRelevantMemories, formatMemoriesForPrompt } from './search.js';
7
+ // ─── Constants ─────────────────────────────────────────────────────────────
8
+ const DEFAULT_MAX_INJECTIONS = 5;
9
+ /**
10
+ * Process a message: extract patterns → classify → store memories.
11
+ *
12
+ * This is the main pipeline for ingesting a message into the memory system.
13
+ * It runs all extractors in parallel, classifies the content, and persists
14
+ * everything atomically (each memory independently — partial failures are
15
+ * tolerated).
16
+ *
17
+ * Extraction steps:
18
+ * 1. Tech stack mentions → tech_stack memories
19
+ * 2. Decisions → decision memories
20
+ * 3. User preferences → user_profile memories
21
+ * 4. Workflow patterns → pattern memories
22
+ * 5. Content classification → appropriate type memory
23
+ *
24
+ * @param content - The message text to process
25
+ * @param metadata - Session / project / source context
26
+ * @returns - All memories created or updated
27
+ */
28
+ export async function processMessage(content, metadata) {
29
+ if (!content || content.trim().length === 0) {
30
+ return [];
31
+ }
32
+ const { sessionId, projectId, source } = metadata;
33
+ try {
34
+ // Step 1: Run all extractors
35
+ const [techStack, decisions, preferences, patterns] = await Promise.all([
36
+ safeExtract(() => extractTechStack(content)),
37
+ safeExtract(() => extractDecisions(content)),
38
+ safeExtract(() => extractUserPreferences(content)),
39
+ safeExtract(() => extractPatterns(content)),
40
+ ]);
41
+ // Step 2: Classify content
42
+ const memoryType = classifyContent(content);
43
+ // Step 3: Build memory payloads
44
+ const memoryPayloads = [];
45
+ // 3a. Tech stack
46
+ if (techStack.length > 0) {
47
+ for (const tech of techStack) {
48
+ memoryPayloads.push({
49
+ memory_type: 'tech_stack',
50
+ project_id: projectId ?? null,
51
+ session_id: sessionId ?? null,
52
+ key: `tech:${tech.toLowerCase().replace(/[^a-z0-9.#]/g, '_')}`,
53
+ content: `Project uses ${tech}`,
54
+ importance: 4,
55
+ source: source ?? 'processor',
56
+ metadata: { technology: tech, extracted: true },
57
+ });
58
+ }
59
+ }
60
+ // 3b. Decisions
61
+ for (const d of decisions) {
62
+ memoryPayloads.push({
63
+ memory_type: 'decision',
64
+ project_id: projectId ?? null,
65
+ session_id: sessionId ?? null,
66
+ key: `decision:${normalizeKeyFragment(d.decision)}`,
67
+ content: d.decision,
68
+ importance: 4,
69
+ source: source ?? 'processor',
70
+ metadata: { context: d.context, extracted: true },
71
+ });
72
+ }
73
+ // 3c. Preferences
74
+ for (const pref of preferences) {
75
+ memoryPayloads.push({
76
+ memory_type: 'user_profile',
77
+ project_id: projectId ?? null,
78
+ session_id: sessionId ?? null,
79
+ key: `preference:${normalizeKeyFragment(pref)}`,
80
+ content: pref,
81
+ importance: 3,
82
+ source: source ?? 'processor',
83
+ metadata: { extracted: true },
84
+ });
85
+ }
86
+ // 3d. Patterns
87
+ for (const pat of patterns) {
88
+ memoryPayloads.push({
89
+ memory_type: 'pattern',
90
+ project_id: projectId ?? null,
91
+ session_id: sessionId ?? null,
92
+ key: `pattern:${normalizeKeyFragment(pat)}`,
93
+ content: pat,
94
+ importance: 2,
95
+ source: source ?? 'processor',
96
+ metadata: { extracted: true },
97
+ });
98
+ }
99
+ // 3e. Classified content — store the whole message
100
+ if (content.trim().length > 10) {
101
+ memoryPayloads.push({
102
+ memory_type: memoryType,
103
+ project_id: projectId ?? null,
104
+ session_id: sessionId ?? null,
105
+ key: `msg:${memoryType}:${createContentHash(content)}`,
106
+ content: content.trim(),
107
+ importance: 3,
108
+ source: source ?? 'processor',
109
+ metadata: {
110
+ classified_as: memoryType,
111
+ tech_stack: techStack,
112
+ decisions_count: decisions.length,
113
+ preferences_count: preferences.length,
114
+ patterns_count: patterns.length,
115
+ },
116
+ });
117
+ }
118
+ // Step 4: Store all memories (parallel upsert)
119
+ if (memoryPayloads.length === 0)
120
+ return [];
121
+ return storeMemories(memoryPayloads);
122
+ }
123
+ catch (err) {
124
+ console.error('[UltraMemory] processMessage: unexpected error', err);
125
+ return [];
126
+ }
127
+ }
128
+ /**
129
+ * Get relevant context for a query as formatted prompt text.
130
+ *
131
+ * Searches the memory store for relevant records, formats them as
132
+ * structured markdown, and returns a string suitable for injection
133
+ * into an LLM system prompt.
134
+ *
135
+ * @param query - The query to find context for
136
+ * @param options - Optional filters and limits
137
+ * @returns - Formatted context string (empty if nothing relevant)
138
+ */
139
+ export async function getContextForQuery(query, options) {
140
+ if (!query || query.trim().length === 0) {
141
+ return '';
142
+ }
143
+ const maxInjections = options?.maxInjections ?? DEFAULT_MAX_INJECTIONS;
144
+ try {
145
+ const results = await searchRelevantMemories(query, {
146
+ types: options?.types,
147
+ projectId: options?.projectId,
148
+ limit: maxInjections,
149
+ minImportance: options?.minImportance,
150
+ });
151
+ if (results.length === 0)
152
+ return '';
153
+ return formatMemoriesForPrompt(results);
154
+ }
155
+ catch (err) {
156
+ console.error('[UltraMemory] getContextForQuery: search failed', err);
157
+ return '';
158
+ }
159
+ }
160
+ // ─── Internal Helpers ──────────────────────────────────────────────────────
161
+ /**
162
+ * Safely run an extractor; returns empty result on failure.
163
+ */
164
+ function safeExtract(fn) {
165
+ try {
166
+ return fn();
167
+ }
168
+ catch (err) {
169
+ console.error('[UltraMemory] extractor failed:', err);
170
+ return [];
171
+ }
172
+ }
173
+ /**
174
+ * Create a stable content hash for deduplication keys.
175
+ * Uses a simple djb2 hash — not cryptographic, just good enough
176
+ * for stable key generation.
177
+ */
178
+ function createContentHash(content) {
179
+ let hash = 5381;
180
+ const normalized = content.toLowerCase().trim();
181
+ for (let i = 0; i < normalized.length; i++) {
182
+ hash = ((hash << 5) + hash + normalized.charCodeAt(i)) & 0xffffffff;
183
+ }
184
+ return Math.abs(hash).toString(36);
185
+ }
186
+ /**
187
+ * Normalize a text fragment into a stable key suffix.
188
+ * Lowercases, collapses whitespace, strips special characters,
189
+ * and truncates to 60 chars.
190
+ */
191
+ function normalizeKeyFragment(text) {
192
+ return text
193
+ .toLowerCase()
194
+ .replace(/[^a-z0-9\s]/g, ' ')
195
+ .replace(/\s+/g, '_')
196
+ .replace(/^_+|_+$/g, '')
197
+ .slice(0, 60);
198
+ }
199
+ //# sourceMappingURL=processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processor.js","sourceRoot":"","sources":["../../src/memory/processor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { MemorySearchResult, MemoryType } from '../types.js';
2
+ export interface SearchOptions {
3
+ /** Filter by specific memory types */
4
+ types?: MemoryType[];
5
+ /** Scope to a specific project */
6
+ projectId?: string;
7
+ /** Maximum results to return (default: 10) */
8
+ limit?: number;
9
+ /** Minimum importance threshold (1-5, default: 1) */
10
+ minImportance?: number;
11
+ /** Minimum relevance score threshold (0.0-1.0, default: 0) */
12
+ minRelevance?: number;
13
+ }
14
+ /**
15
+ * Search for memories relevant to the given query.
16
+ *
17
+ * Delegates to the DB full-text search engine and layers on client-side
18
+ * importance/relevance filtering. Tracks access for LRU eviction.
19
+ *
20
+ * @param query - Natural-language search text
21
+ * @param options - Optional filters and limits
22
+ * @returns - Ranked memory search results
23
+ */
24
+ export declare function searchRelevantMemories(query: string, options?: SearchOptions): Promise<MemorySearchResult[]>;
25
+ /**
26
+ * Format memories as structured text for system prompt injection.
27
+ *
28
+ * Produces clean, hierarchical markdown grouped by memory type.
29
+ * Each entry includes its importance level and key content.
30
+ *
31
+ * @param memories - Search results to format
32
+ * @returns - Formatted markdown string (empty string if no memories)
33
+ */
34
+ export declare function formatMemoriesForPrompt(memories: MemorySearchResult[]): string;
35
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/memory/search.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKlE,MAAM,WAAW,aAAa;IAC5B,sCAAsC;IACtC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAiC/B;AA0DD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAqD9E"}
@@ -0,0 +1,170 @@
1
+ // ─── Memory Search & Prompt Formatting ─────────────────────────────────────
2
+ // Retrieves relevant memories and formats them for LLM prompt injection.
3
+ import { searchMemories, recordMemoryAccess } from '../db/queries.js';
4
+ /**
5
+ * Search for memories relevant to the given query.
6
+ *
7
+ * Delegates to the DB full-text search engine and layers on client-side
8
+ * importance/relevance filtering. Tracks access for LRU eviction.
9
+ *
10
+ * @param query - Natural-language search text
11
+ * @param options - Optional filters and limits
12
+ * @returns - Ranked memory search results
13
+ */
14
+ export async function searchRelevantMemories(query, options) {
15
+ if (!query || query.trim().length === 0) {
16
+ return [];
17
+ }
18
+ const results = await searchMemories({
19
+ query: query.trim(),
20
+ types: options?.types,
21
+ project_id: options?.projectId,
22
+ limit: (options?.limit ?? 10) * 2, // Fetch extra for post-filtering
23
+ offset: 0,
24
+ });
25
+ // Apply client-side filters
26
+ let filtered = results;
27
+ if (options?.minImportance !== undefined && options.minImportance > 1) {
28
+ filtered = filtered.filter((r) => r.memory.importance >= options.minImportance);
29
+ }
30
+ if (options?.minRelevance !== undefined && options.minRelevance > 0) {
31
+ filtered = filtered.filter((r) => r.relevance >= options.minRelevance);
32
+ }
33
+ // Respect limit exactly
34
+ const limited = filtered.slice(0, options?.limit ?? 10);
35
+ // Track access for LRU without blocking the response
36
+ if (limited.length > 0) {
37
+ trackMemoryAccess(limited).catch(() => { });
38
+ }
39
+ return limited;
40
+ }
41
+ function groupByType(memories) {
42
+ const grouped = {
43
+ tech_stack: [],
44
+ decision: [],
45
+ user_profile: [],
46
+ pattern: [],
47
+ project_context: [],
48
+ explicit: [],
49
+ session: [],
50
+ other: [],
51
+ };
52
+ for (const m of memories) {
53
+ switch (m.memory.memory_type) {
54
+ case 'tech_stack':
55
+ grouped.tech_stack.push(m);
56
+ break;
57
+ case 'decision':
58
+ grouped.decision.push(m);
59
+ break;
60
+ case 'user_profile':
61
+ grouped.user_profile.push(m);
62
+ break;
63
+ case 'pattern':
64
+ grouped.pattern.push(m);
65
+ break;
66
+ case 'project_context':
67
+ grouped.project_context.push(m);
68
+ break;
69
+ case 'explicit':
70
+ grouped.explicit.push(m);
71
+ break;
72
+ case 'session':
73
+ grouped.session.push(m);
74
+ break;
75
+ default:
76
+ grouped.other.push(m);
77
+ break;
78
+ }
79
+ }
80
+ return grouped;
81
+ }
82
+ /** Type label for display in prompt injection text. */
83
+ const TYPE_LABELS = {
84
+ tech_stack: 'Tech Stack',
85
+ decision: 'Decisions',
86
+ user_profile: 'User Preferences',
87
+ pattern: 'Workflow Patterns',
88
+ project_context: 'Project Context',
89
+ explicit: 'Saved Notes',
90
+ session: 'Session History',
91
+ other: 'Other Context',
92
+ };
93
+ /**
94
+ * Format memories as structured text for system prompt injection.
95
+ *
96
+ * Produces clean, hierarchical markdown grouped by memory type.
97
+ * Each entry includes its importance level and key content.
98
+ *
99
+ * @param memories - Search results to format
100
+ * @returns - Formatted markdown string (empty string if no memories)
101
+ */
102
+ export function formatMemoriesForPrompt(memories) {
103
+ if (memories.length === 0)
104
+ return '';
105
+ const grouped = groupByType(memories);
106
+ const sections = ['## Relevant Context'];
107
+ // Ordered groups by relevance/importance
108
+ const groupOrder = [
109
+ 'explicit',
110
+ 'tech_stack',
111
+ 'decision',
112
+ 'user_profile',
113
+ 'project_context',
114
+ 'pattern',
115
+ 'session',
116
+ 'other',
117
+ ];
118
+ for (const key of groupOrder) {
119
+ const items = grouped[key];
120
+ if (items.length === 0)
121
+ continue;
122
+ const label = TYPE_LABELS[key] ?? key;
123
+ sections.push('');
124
+ sections.push(`### ${label}`);
125
+ if (key === 'tech_stack') {
126
+ // Compact inline format for tech
127
+ const techList = items
128
+ .map((r) => r.memory.content || r.memory.key.replace(/^tech:/, ''))
129
+ .filter(Boolean);
130
+ sections.push(techList.map((t) => `- ${t}`).join('\n'));
131
+ }
132
+ else if (key === 'decision') {
133
+ for (const item of items) {
134
+ const mem = item.memory;
135
+ const imp = importanceBadge(mem.importance);
136
+ const val = mem.value;
137
+ const ctx = val?.context;
138
+ sections.push(`- ${mem.content}${imp}`);
139
+ if (ctx) {
140
+ sections.push(` - Context: ${ctx}`);
141
+ }
142
+ }
143
+ }
144
+ else {
145
+ for (const item of items) {
146
+ const mem = item.memory;
147
+ const imp = importanceBadge(mem.importance);
148
+ sections.push(`- ${mem.content}${imp}`);
149
+ }
150
+ }
151
+ }
152
+ return sections.join('\n');
153
+ }
154
+ // ─── Internal Helpers ──────────────────────────────────────────────────────
155
+ /** Format importance as a human-readable badge. */
156
+ function importanceBadge(level) {
157
+ if (level >= 5)
158
+ return ' *(high importance)*';
159
+ if (level >= 4)
160
+ return '';
161
+ if (level <= 2)
162
+ return ' *(minor)*';
163
+ return '';
164
+ }
165
+ /** Non-blocking access tracking for LRU. */
166
+ async function trackMemoryAccess(results) {
167
+ const ids = results.map((r) => r.memory.id);
168
+ await Promise.allSettled(ids.map((id) => recordMemoryAccess(id)));
169
+ }
170
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/memory/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type pg from 'pg';
2
+ import type { MemoryCreate, MemoryRecord } from '../types.js';
3
+ /**
4
+ * Store a memory record with automatic deduplication.
5
+ *
6
+ * Uses `createMemory` from queries.ts which performs an upsert on
7
+ * `(memory_type, project_id, key)`. When no explicit `key` is given,
8
+ * one is generated from the content to enable stable deduplication.
9
+ *
10
+ * @param data - Memory data to persist
11
+ * @param pool - Optional pg.Pool for transaction support
12
+ * @returns - The stored/updated MemoryRecord
13
+ */
14
+ export declare function storeMemory(data: MemoryCreate, pool?: pg.Pool): Promise<MemoryRecord>;
15
+ /**
16
+ * Store multiple memory records in parallel.
17
+ * Each entry is independently upserted — a failure in one does not
18
+ * affect the others.
19
+ *
20
+ * @param data - Array of memory data to persist
21
+ * @returns - Array of stored MemoryRecords
22
+ */
23
+ export declare function storeMemories(data: MemoryCreate[]): Promise<MemoryRecord[]>;
24
+ /**
25
+ * Convenience: store tech-stack entries with the correct type and key prefix.
26
+ */
27
+ export declare function storeTechStack(technologies: string[], metadata: {
28
+ projectId?: string;
29
+ sessionId?: string;
30
+ source?: string;
31
+ }): Promise<MemoryRecord[]>;
32
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAgC1E;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,YAAY,EAClB,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,GACb,OAAO,CAAC,YAAY,CAAC,CAsCvB;AAID;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAejF;AAID;;GAEG;AACH,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,EAAE,EACtB,QAAQ,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE,OAAO,CAAC,YAAY,EAAE,CAAC,CAezB"}
@@ -0,0 +1,112 @@
1
+ // ─── Memory Storage ────────────────────────────────────────────────────────
2
+ // Stores extracted memories with deduplication via upsert.
3
+ import { createMemory } from '../db/queries.js';
4
+ // ─── Key Generation ────────────────────────────────────────────────────────
5
+ /**
6
+ * Generate a stable deduplication key from content.
7
+ * Keys are normalised so identical or semantically similar content
8
+ * produces the same key, enabling upsert deduplication.
9
+ */
10
+ function generateKey(content, type) {
11
+ const prefix = type ? `${type}:` : '';
12
+ // Lowercase, collapse whitespace, strip special chars
13
+ const normalized = content
14
+ .toLowerCase()
15
+ .replace(/[^a-z0-9\s]/g, ' ')
16
+ .replace(/\s+/g, '_')
17
+ .replace(/^_+|_+$/g, '')
18
+ .slice(0, 80);
19
+ if (!normalized) {
20
+ // Fallback: use a short timestamp-based key
21
+ return `${prefix}entry_${Date.now()}`;
22
+ }
23
+ return `${prefix}${normalized}`;
24
+ }
25
+ // ─── Single Store ──────────────────────────────────────────────────────────
26
+ /**
27
+ * Store a memory record with automatic deduplication.
28
+ *
29
+ * Uses `createMemory` from queries.ts which performs an upsert on
30
+ * `(memory_type, project_id, key)`. When no explicit `key` is given,
31
+ * one is generated from the content to enable stable deduplication.
32
+ *
33
+ * @param data - Memory data to persist
34
+ * @param pool - Optional pg.Pool for transaction support
35
+ * @returns - The stored/updated MemoryRecord
36
+ */
37
+ export async function storeMemory(data, pool) {
38
+ // Ensure required fields
39
+ const memoryType = data.memory_type;
40
+ const key = data.key?.trim() || generateKey(data.content, memoryType);
41
+ // If a pool was provided, use it directly; otherwise queries.ts manages
42
+ // its own pool via getPool().
43
+ if (pool) {
44
+ const result = await pool.query(`INSERT INTO memories (memory_type, project_id, session_id, key, value, content, importance, source, metadata)
45
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
46
+ ON CONFLICT (memory_type, project_id, key)
47
+ DO UPDATE SET
48
+ content = EXCLUDED.content,
49
+ importance = GREATEST(memories.importance, EXCLUDED.importance),
50
+ value = memories.value || EXCLUDED.value,
51
+ updated_at = NOW()
52
+ RETURNING *`, [
53
+ memoryType,
54
+ data.project_id ?? null,
55
+ data.session_id ?? null,
56
+ key,
57
+ JSON.stringify(data.value ?? {}),
58
+ data.content,
59
+ data.importance ?? 3,
60
+ data.source ?? 'auto',
61
+ JSON.stringify(data.metadata ?? {}),
62
+ ]);
63
+ return result.rows[0];
64
+ }
65
+ // No pool provided — delegate to queries.ts
66
+ return createMemory({
67
+ ...data,
68
+ key,
69
+ });
70
+ }
71
+ // ─── Batch Store ───────────────────────────────────────────────────────────
72
+ /**
73
+ * Store multiple memory records in parallel.
74
+ * Each entry is independently upserted — a failure in one does not
75
+ * affect the others.
76
+ *
77
+ * @param data - Array of memory data to persist
78
+ * @returns - Array of stored MemoryRecords
79
+ */
80
+ export async function storeMemories(data) {
81
+ if (data.length === 0)
82
+ return [];
83
+ const results = await Promise.allSettled(data.map((d) => storeMemory(d)));
84
+ return results.reduce((acc, r) => {
85
+ if (r.status === 'fulfilled') {
86
+ acc.push(r.value);
87
+ }
88
+ else {
89
+ console.error('[UltraMemory] storeMemories: failed to store memory', r.reason);
90
+ }
91
+ return acc;
92
+ }, []);
93
+ }
94
+ // ─── Tech-Stack Specific Store ─────────────────────────────────────────────
95
+ /**
96
+ * Convenience: store tech-stack entries with the correct type and key prefix.
97
+ */
98
+ export async function storeTechStack(technologies, metadata) {
99
+ if (technologies.length === 0)
100
+ return [];
101
+ return storeMemories(technologies.map((tech) => ({
102
+ memory_type: 'tech_stack',
103
+ project_id: metadata.projectId ?? null,
104
+ session_id: metadata.sessionId ?? null,
105
+ key: `tech:${tech.toLowerCase().replace(/[^a-z0-9.#]/g, '_')}`,
106
+ content: `Project uses ${tech}`,
107
+ importance: 4,
108
+ source: metadata.source ?? 'extractor',
109
+ metadata: { technology: tech, extracted: true },
110
+ })));
111
+ }
112
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { type Express } from 'express';
2
+ import type { PluginConfig } from '../types.js';
3
+ /**
4
+ * Create and start the Ultra Memory HTTP API server.
5
+ *
6
+ * @param config - Plugin configuration (DB, server host/port, etc.)
7
+ * @returns `{ app, url, close }` — the Express app, its listening URL,
8
+ * and an async `close()` function for graceful shutdown.
9
+ */
10
+ export declare function createServer(config: PluginConfig): Promise<{
11
+ app: Express;
12
+ url: string;
13
+ close: () => Promise<void>;
14
+ }>;
15
+ export type { CreateMemoryInput, SearchQueryInput, UpdateMemoryInput } from './schemas.js';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAEhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CA4CpE;AAGD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,49 @@
1
+ import express from 'express';
2
+ import { getPool, closePool } from '../db/connection.js';
3
+ import { healthRouter } from './routes/health.js';
4
+ import { memoryRouter } from './routes/memory.js';
5
+ import { errorHandler } from './middleware/error-handler.js';
6
+ /**
7
+ * Create and start the Ultra Memory HTTP API server.
8
+ *
9
+ * @param config - Plugin configuration (DB, server host/port, etc.)
10
+ * @returns `{ app, url, close }` — the Express app, its listening URL,
11
+ * and an async `close()` function for graceful shutdown.
12
+ */
13
+ export async function createServer(config) {
14
+ // Initialise the database connection pool before accepting requests
15
+ getPool(config);
16
+ const app = express();
17
+ // ── Global middleware ────────────────────────────────────────────────
18
+ app.use(express.json());
19
+ // ── Routes ──────────────────────────────────────────────────────────
20
+ app.use('/', healthRouter);
21
+ app.use('/api', memoryRouter);
22
+ // ── Error handler (must be last) ────────────────────────────────────
23
+ app.use(errorHandler);
24
+ // ── Start listening ─────────────────────────────────────────────────
25
+ const host = config.server.host;
26
+ const port = config.server.port;
27
+ let server;
28
+ const url = await new Promise((resolve, reject) => {
29
+ server = app.listen(port, host, () => {
30
+ const addr = server.address();
31
+ const actualPort = addr && typeof addr === 'object' ? addr.port : port;
32
+ const serverUrl = `http://${host}:${actualPort}`;
33
+ console.log(`[UltraMemory] Memory server listening on ${serverUrl}`);
34
+ resolve(serverUrl);
35
+ });
36
+ server.on('error', (err) => {
37
+ reject(err);
38
+ });
39
+ });
40
+ return {
41
+ app,
42
+ url,
43
+ close: async () => {
44
+ server.close();
45
+ await closePool();
46
+ },
47
+ };
48
+ }
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAyB,MAAM,SAAS,CAAC;AAGhD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAoB;IAEpB,oEAAoE;IACpE,OAAO,CAAC,MAAM,CAAC,CAAC;IAEhB,MAAM,GAAG,GAAY,OAAO,EAAE,CAAC;IAE/B,wEAAwE;IACxE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAExB,uEAAuE;IACvE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC3B,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAE9B,uEAAuE;IACvE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAEtB,uEAAuE;IACvE,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;IAChC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;IAEhC,IAAI,MAAc,CAAC;IAEnB,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxD,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE;YACnC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,MAAM,UAAU,GACd,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YACtD,MAAM,SAAS,GAAG,UAAU,IAAI,IAAI,UAAU,EAAE,CAAC;YACjD,OAAO,CAAC,GAAG,CAAC,4CAA4C,SAAS,EAAE,CAAC,CAAC;YACrE,OAAO,CAAC,SAAS,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;YAChC,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,GAAG;QACH,GAAG;QACH,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,SAAS,EAAE,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC"}