sensorium-mcp 2.16.28 → 2.16.30

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 (177) hide show
  1. package/dist/config.d.ts +1 -11
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +3 -49
  4. package/dist/config.js.map +1 -1
  5. package/dist/dashboard/presets.d.ts +18 -0
  6. package/dist/dashboard/presets.d.ts.map +1 -0
  7. package/dist/dashboard/presets.js +78 -0
  8. package/dist/dashboard/presets.js.map +1 -0
  9. package/dist/dashboard/routes.d.ts +33 -0
  10. package/dist/dashboard/routes.d.ts.map +1 -0
  11. package/dist/dashboard/routes.js +283 -0
  12. package/dist/dashboard/routes.js.map +1 -0
  13. package/dist/dashboard.d.ts +6 -29
  14. package/dist/dashboard.d.ts.map +1 -1
  15. package/dist/dashboard.js +6 -1158
  16. package/dist/dashboard.js.map +1 -1
  17. package/dist/data/file-storage.d.ts +19 -0
  18. package/dist/data/file-storage.d.ts.map +1 -0
  19. package/dist/data/file-storage.js +58 -0
  20. package/dist/data/file-storage.js.map +1 -0
  21. package/dist/data/memory/bootstrap.d.ts +40 -0
  22. package/dist/data/memory/bootstrap.d.ts.map +1 -0
  23. package/dist/data/memory/bootstrap.js +240 -0
  24. package/dist/data/memory/bootstrap.js.map +1 -0
  25. package/dist/data/memory/consolidation.d.ts +12 -0
  26. package/dist/data/memory/consolidation.d.ts.map +1 -0
  27. package/dist/data/memory/consolidation.js +248 -0
  28. package/dist/data/memory/consolidation.js.map +1 -0
  29. package/dist/data/memory/episodes.d.ts +34 -0
  30. package/dist/data/memory/episodes.d.ts.map +1 -0
  31. package/dist/data/memory/episodes.js +89 -0
  32. package/dist/data/memory/episodes.js.map +1 -0
  33. package/dist/data/memory/index.d.ts +14 -0
  34. package/dist/data/memory/index.d.ts.map +1 -0
  35. package/dist/data/memory/index.js +14 -0
  36. package/dist/data/memory/index.js.map +1 -0
  37. package/dist/data/memory/procedures.d.ts +42 -0
  38. package/dist/data/memory/procedures.d.ts.map +1 -0
  39. package/dist/data/memory/procedures.js +122 -0
  40. package/dist/data/memory/procedures.js.map +1 -0
  41. package/dist/data/memory/schema.d.ts +11 -0
  42. package/dist/data/memory/schema.d.ts.map +1 -0
  43. package/dist/data/memory/schema.js +327 -0
  44. package/dist/data/memory/schema.js.map +1 -0
  45. package/dist/data/memory/semantic.d.ts +94 -0
  46. package/dist/data/memory/semantic.d.ts.map +1 -0
  47. package/dist/data/memory/semantic.js +385 -0
  48. package/dist/data/memory/semantic.js.map +1 -0
  49. package/dist/data/memory/voice-sig.d.ts +33 -0
  50. package/dist/data/memory/voice-sig.d.ts.map +1 -0
  51. package/dist/data/memory/voice-sig.js +48 -0
  52. package/dist/data/memory/voice-sig.js.map +1 -0
  53. package/dist/data/templates.d.ts +19 -0
  54. package/dist/data/templates.d.ts.map +1 -0
  55. package/dist/data/templates.js +46 -0
  56. package/dist/data/templates.js.map +1 -0
  57. package/dist/dispatcher.d.ts +5 -97
  58. package/dist/dispatcher.d.ts.map +1 -1
  59. package/dist/dispatcher.js +5 -525
  60. package/dist/dispatcher.js.map +1 -1
  61. package/dist/drive.d.ts.map +1 -1
  62. package/dist/drive.js +3 -1
  63. package/dist/drive.js.map +1 -1
  64. package/dist/index.d.ts +4 -23
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +11 -289
  67. package/dist/index.js.map +1 -1
  68. package/dist/integrations/openai/chat.d.ts +29 -0
  69. package/dist/integrations/openai/chat.d.ts.map +1 -0
  70. package/dist/integrations/openai/chat.js +84 -0
  71. package/dist/integrations/openai/chat.js.map +1 -0
  72. package/dist/integrations/openai/index.d.ts +6 -0
  73. package/dist/integrations/openai/index.d.ts.map +1 -0
  74. package/dist/integrations/openai/index.js +6 -0
  75. package/dist/integrations/openai/index.js.map +1 -0
  76. package/dist/integrations/openai/speech.d.ts +21 -0
  77. package/dist/integrations/openai/speech.d.ts.map +1 -0
  78. package/dist/integrations/openai/speech.js +75 -0
  79. package/dist/integrations/openai/speech.js.map +1 -0
  80. package/dist/integrations/openai/video.d.ts +15 -0
  81. package/dist/integrations/openai/video.d.ts.map +1 -0
  82. package/dist/integrations/openai/video.js +131 -0
  83. package/dist/integrations/openai/video.js.map +1 -0
  84. package/dist/integrations/openai/vision.d.ts +23 -0
  85. package/dist/integrations/openai/vision.d.ts.map +1 -0
  86. package/dist/integrations/openai/vision.js +116 -0
  87. package/dist/integrations/openai/vision.js.map +1 -0
  88. package/dist/integrations/openai/voice-emotion.d.ts +41 -0
  89. package/dist/integrations/openai/voice-emotion.d.ts.map +1 -0
  90. package/dist/integrations/openai/voice-emotion.js +50 -0
  91. package/dist/integrations/openai/voice-emotion.js.map +1 -0
  92. package/dist/integrations/telegram/types.d.ts +112 -0
  93. package/dist/integrations/telegram/types.d.ts.map +1 -0
  94. package/dist/integrations/telegram/types.js +6 -0
  95. package/dist/integrations/telegram/types.js.map +1 -0
  96. package/dist/memory.d.ts +6 -205
  97. package/dist/memory.d.ts.map +1 -1
  98. package/dist/memory.js +6 -1357
  99. package/dist/memory.js.map +1 -1
  100. package/dist/openai.d.ts +11 -102
  101. package/dist/openai.d.ts.map +1 -1
  102. package/dist/openai.js +14 -421
  103. package/dist/openai.js.map +1 -1
  104. package/dist/response-builders.d.ts +1 -11
  105. package/dist/response-builders.d.ts.map +1 -1
  106. package/dist/response-builders.js +2 -38
  107. package/dist/response-builders.js.map +1 -1
  108. package/dist/server/factory.d.ts +17 -0
  109. package/dist/server/factory.d.ts.map +1 -0
  110. package/dist/server/factory.js +279 -0
  111. package/dist/server/factory.js.map +1 -0
  112. package/dist/services/dispatcher/broker.d.ts +83 -0
  113. package/dist/services/dispatcher/broker.d.ts.map +1 -0
  114. package/dist/services/dispatcher/broker.js +175 -0
  115. package/dist/services/dispatcher/broker.js.map +1 -0
  116. package/dist/services/dispatcher/index.d.ts +7 -0
  117. package/dist/services/dispatcher/index.d.ts.map +1 -0
  118. package/dist/services/dispatcher/index.js +7 -0
  119. package/dist/services/dispatcher/index.js.map +1 -0
  120. package/dist/services/dispatcher/lock.d.ts +25 -0
  121. package/dist/services/dispatcher/lock.d.ts.map +1 -0
  122. package/dist/services/dispatcher/lock.js +111 -0
  123. package/dist/services/dispatcher/lock.js.map +1 -0
  124. package/dist/services/dispatcher/poller.d.ts +19 -0
  125. package/dist/services/dispatcher/poller.d.ts.map +1 -0
  126. package/dist/services/dispatcher/poller.js +269 -0
  127. package/dist/services/dispatcher/poller.js.map +1 -0
  128. package/dist/telegram.d.ts +2 -88
  129. package/dist/telegram.d.ts.map +1 -1
  130. package/dist/telegram.js +2 -0
  131. package/dist/telegram.js.map +1 -1
  132. package/dist/tool-definitions.d.ts +1 -14
  133. package/dist/tool-definitions.d.ts.map +1 -1
  134. package/dist/tool-definitions.js +1 -403
  135. package/dist/tool-definitions.js.map +1 -1
  136. package/dist/tools/definitions.d.ts +15 -0
  137. package/dist/tools/definitions.d.ts.map +1 -0
  138. package/dist/tools/definitions.js +404 -0
  139. package/dist/tools/definitions.js.map +1 -0
  140. package/dist/tools/start-session-tool.d.ts.map +1 -1
  141. package/dist/tools/start-session-tool.js +2 -0
  142. package/dist/tools/start-session-tool.js.map +1 -1
  143. package/dist/tools/wait/drive-handler.d.ts +61 -0
  144. package/dist/tools/wait/drive-handler.d.ts.map +1 -0
  145. package/dist/tools/wait/drive-handler.js +138 -0
  146. package/dist/tools/wait/drive-handler.js.map +1 -0
  147. package/dist/tools/wait/index.d.ts +8 -0
  148. package/dist/tools/wait/index.d.ts.map +1 -0
  149. package/dist/tools/wait/index.js +8 -0
  150. package/dist/tools/wait/index.js.map +1 -0
  151. package/dist/tools/wait/media-processor.d.ts +52 -0
  152. package/dist/tools/wait/media-processor.d.ts.map +1 -0
  153. package/dist/tools/wait/media-processor.js +261 -0
  154. package/dist/tools/wait/media-processor.js.map +1 -0
  155. package/dist/tools/wait/message-delivery.d.ts +63 -0
  156. package/dist/tools/wait/message-delivery.d.ts.map +1 -0
  157. package/dist/tools/wait/message-delivery.js +281 -0
  158. package/dist/tools/wait/message-delivery.js.map +1 -0
  159. package/dist/tools/wait/poll-loop.d.ts +72 -0
  160. package/dist/tools/wait/poll-loop.d.ts.map +1 -0
  161. package/dist/tools/wait/poll-loop.js +280 -0
  162. package/dist/tools/wait/poll-loop.js.map +1 -0
  163. package/dist/tools/wait/reaction-handler.d.ts +49 -0
  164. package/dist/tools/wait/reaction-handler.d.ts.map +1 -0
  165. package/dist/tools/wait/reaction-handler.js +126 -0
  166. package/dist/tools/wait/reaction-handler.js.map +1 -0
  167. package/dist/tools/wait/task-handler.d.ts +40 -0
  168. package/dist/tools/wait/task-handler.d.ts.map +1 -0
  169. package/dist/tools/wait/task-handler.js +41 -0
  170. package/dist/tools/wait/task-handler.js.map +1 -0
  171. package/dist/tools/wait-tool.d.ts +3 -69
  172. package/dist/tools/wait-tool.d.ts.map +1 -1
  173. package/dist/tools/wait-tool.js +3 -876
  174. package/dist/tools/wait-tool.js.map +1 -1
  175. package/package.json +1 -1
  176. package/templates/daily-review.default.md +26 -0
  177. package/templates/drive-dispatcher.default.md +2 -0
@@ -0,0 +1,385 @@
1
+ /**
2
+ * Semantic note CRUD operations for the memory system.
3
+ *
4
+ * Extracted from memory.ts — semantic memory layer.
5
+ */
6
+ import { randomUUID } from "crypto";
7
+ import { cosineSimilarity } from "../../openai.js";
8
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
9
+ function generateId(prefix) {
10
+ return `${prefix}_${randomUUID().replace(/-/g, "").slice(0, 12)}`;
11
+ }
12
+ function nowISO() {
13
+ return new Date().toISOString();
14
+ }
15
+ function jsonOrNull(val) {
16
+ if (val === undefined || val === null)
17
+ return null;
18
+ return JSON.stringify(val);
19
+ }
20
+ function parseJsonArray(val) {
21
+ if (!val)
22
+ return [];
23
+ try {
24
+ return JSON.parse(val);
25
+ }
26
+ catch {
27
+ return [];
28
+ }
29
+ }
30
+ function parseJsonObject(val) {
31
+ if (!val)
32
+ return {};
33
+ try {
34
+ return JSON.parse(val);
35
+ }
36
+ catch {
37
+ return {};
38
+ }
39
+ }
40
+ // ─── Row → Interface mappers ─────────────────────────────────────────────────
41
+ function rowToSemanticNote(row) {
42
+ return {
43
+ noteId: row.note_id,
44
+ type: row.type,
45
+ content: row.content,
46
+ keywords: parseJsonArray(row.keywords),
47
+ confidence: row.confidence,
48
+ priority: row.priority ?? 0,
49
+ threadId: row.thread_id ?? null,
50
+ sourceEpisodes: parseJsonArray(row.source_episodes),
51
+ linkedNotes: parseJsonArray(row.linked_notes),
52
+ linkReasons: parseJsonObject(row.link_reasons),
53
+ validFrom: row.valid_from,
54
+ validTo: row.valid_to ?? null,
55
+ supersededBy: row.superseded_by ?? null,
56
+ accessCount: row.access_count,
57
+ lastAccessed: row.last_accessed ?? null,
58
+ createdAt: row.created_at,
59
+ updatedAt: row.updated_at,
60
+ };
61
+ }
62
+ // ─── Topic Index ─────────────────────────────────────────────────────────────
63
+ export function updateTopicIndexForKeywords(db, keywords, layer) {
64
+ const now = nowISO();
65
+ const col = layer === "semantic" ? "semantic_count" : "procedural_count";
66
+ const upsertStmt = db.prepare(`INSERT INTO meta_topic_index (topic, ${col}, last_updated)
67
+ VALUES (?, 1, ?)
68
+ ON CONFLICT(topic) DO UPDATE SET
69
+ ${col} = ${col} + 1,
70
+ last_updated = ?,
71
+ total_accesses = total_accesses + 1`);
72
+ const txn = db.transaction(() => {
73
+ for (const kw of keywords) {
74
+ const normalised = kw.toLowerCase().trim();
75
+ if (normalised.length > 1) {
76
+ upsertStmt.run(normalised, now, now);
77
+ }
78
+ }
79
+ });
80
+ txn();
81
+ }
82
+ export function decrementTopicIndexForKeywords(db, keywords, layer) {
83
+ const col = layer === "semantic" ? "semantic_count" : "procedural_count";
84
+ const decrementStmt = db.prepare(`UPDATE meta_topic_index SET ${col} = MAX(${col} - 1, 0) WHERE topic = ?`);
85
+ const deleteStmt = db.prepare(`DELETE FROM meta_topic_index WHERE topic = ? AND semantic_count <= 0 AND procedural_count <= 0`);
86
+ const txn = db.transaction(() => {
87
+ for (const kw of keywords) {
88
+ const normalised = kw.toLowerCase().trim();
89
+ if (normalised.length > 1) {
90
+ decrementStmt.run(normalised);
91
+ deleteStmt.run(normalised);
92
+ }
93
+ }
94
+ });
95
+ txn();
96
+ }
97
+ // ─── Semantic Memory CRUD ────────────────────────────────────────────────────
98
+ export function saveSemanticNote(db, note) {
99
+ const id = generateId("sn");
100
+ const now = nowISO();
101
+ db.prepare(`INSERT INTO semantic_notes
102
+ (note_id, type, content, keywords, confidence, priority, thread_id, source_episodes, linked_notes, link_reasons, valid_from, access_count, created_at, updated_at)
103
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)`).run(id, note.type, note.content, JSON.stringify(note.keywords), Math.max(0, Math.min(1, note.confidence ?? 0.5)), Math.max(0, Math.min(2, note.priority ?? 0)), note.threadId ?? null, jsonOrNull(note.sourceEpisodes), null, null, now, now, now);
104
+ // Update topic index for each keyword
105
+ updateTopicIndexForKeywords(db, note.keywords, "semantic");
106
+ return id;
107
+ }
108
+ export function searchSemanticNotes(db, query, options) {
109
+ const maxResults = options?.maxResults ?? 10;
110
+ const terms = query
111
+ .toLowerCase()
112
+ .split(/\s+/)
113
+ .filter((t) => t.length > 1);
114
+ if (terms.length === 0)
115
+ return [];
116
+ // Build LIKE conditions: each term must match content OR keywords
117
+ // Escape SQL LIKE wildcards in search terms
118
+ const conditions = [];
119
+ const params = [];
120
+ for (const term of terms) {
121
+ const escaped = term.replace(/%/g, "\\%").replace(/_/g, "\\_");
122
+ conditions.push(`(LOWER(content) LIKE ? ESCAPE '\\' OR LOWER(keywords) LIKE ? ESCAPE '\\')`);
123
+ params.push(`%${escaped}%`, `%${escaped}%`);
124
+ }
125
+ let sql = `SELECT * FROM semantic_notes WHERE valid_to IS NULL AND superseded_by IS NULL AND (${conditions.join(" AND ")})`;
126
+ if (options?.types && options.types.length > 0) {
127
+ const placeholders = options.types.map(() => "?").join(",");
128
+ sql += ` AND type IN (${placeholders})`;
129
+ params.push(...options.types);
130
+ }
131
+ sql += ` ORDER BY confidence DESC, access_count DESC LIMIT ?`;
132
+ params.push(maxResults);
133
+ const rows = db.prepare(sql).all(...params);
134
+ // Update access counts
135
+ if (!options?.skipAccessTracking) {
136
+ const now = nowISO();
137
+ const updateStmt = db.prepare(`UPDATE semantic_notes SET access_count = access_count + 1, last_accessed = ? WHERE note_id = ?`);
138
+ const txn = db.transaction(() => {
139
+ for (const row of rows) {
140
+ updateStmt.run(now, row.note_id);
141
+ }
142
+ });
143
+ txn();
144
+ }
145
+ return rows.map(rowToSemanticNote);
146
+ }
147
+ export function searchSemanticNotesRanked(db, query, options) {
148
+ const maxResults = options?.maxResults ?? 10;
149
+ const minMatchRatio = options?.minMatchRatio ?? 0.4; // require at least 40% of terms to match
150
+ const terms = query.toLowerCase().split(/\\s+/).filter(t => t.length > 1);
151
+ if (terms.length === 0)
152
+ return [];
153
+ // Use OR to get broad recall
154
+ const conditions = [];
155
+ const params = [];
156
+ for (const term of terms) {
157
+ const escaped = term.replace(/%/g, "\\\\%").replace(/_/g, "\\\\_");
158
+ conditions.push(`(LOWER(content) LIKE ? ESCAPE '\\\\' OR LOWER(keywords) LIKE ? ESCAPE '\\\\')`);
159
+ params.push(`%${escaped}%`, `%${escaped}%`);
160
+ }
161
+ let sql = `SELECT * FROM semantic_notes WHERE valid_to IS NULL AND superseded_by IS NULL AND (${conditions.join(" OR ")})`;
162
+ // Thread filtering: show notes from this thread + global notes
163
+ if (options?.threadId !== undefined) {
164
+ sql += ` AND (thread_id IS NULL OR thread_id = ?)`;
165
+ params.push(options.threadId);
166
+ }
167
+ if (options?.types && options.types.length > 0) {
168
+ const placeholders = options.types.map(() => "?").join(",");
169
+ sql += ` AND type IN (${placeholders})`;
170
+ params.push(...options.types);
171
+ }
172
+ sql += ` ORDER BY confidence DESC, access_count DESC LIMIT ?`;
173
+ params.push(maxResults * 3); // fetch more to allow scoring/filtering
174
+ const rows = db.prepare(sql).all(...params);
175
+ const allNotes = rows.map(rowToSemanticNote);
176
+ // Score by how many terms match
177
+ const minMatches = Math.max(2, Math.ceil(terms.length * minMatchRatio));
178
+ const scored = allNotes.map(n => {
179
+ const text = (n.content + " " + n.keywords.join(" ")).toLowerCase();
180
+ let matchCount = 0;
181
+ for (const term of terms) {
182
+ if (text.includes(term))
183
+ matchCount++;
184
+ }
185
+ return { ...n, _matchCount: matchCount };
186
+ })
187
+ .filter(n => n._matchCount >= minMatches)
188
+ .sort((a, b) => {
189
+ if (b._matchCount !== a._matchCount)
190
+ return b._matchCount - a._matchCount;
191
+ return b.confidence - a.confidence;
192
+ })
193
+ .slice(0, maxResults);
194
+ const notes = scored;
195
+ // Update access counts
196
+ if (!options?.skipAccessTracking) {
197
+ const now = nowISO();
198
+ const updateStmt = db.prepare(`UPDATE semantic_notes SET access_count = access_count + 1, last_accessed = ? WHERE note_id = ?`);
199
+ db.transaction(() => {
200
+ for (const note of notes)
201
+ updateStmt.run(now, note.noteId);
202
+ })();
203
+ }
204
+ return notes;
205
+ }
206
+ export function getTopSemanticNotes(db, options) {
207
+ const limit = options?.limit ?? 10;
208
+ const sortBy = options?.sortBy ?? "confidence";
209
+ const validSortColumns = {
210
+ confidence: "confidence DESC",
211
+ access_count: "access_count DESC",
212
+ created_at: "created_at DESC",
213
+ };
214
+ const orderClause = validSortColumns[sortBy] ?? "confidence DESC";
215
+ let sql = `SELECT * FROM semantic_notes WHERE valid_to IS NULL AND superseded_by IS NULL`;
216
+ const params = [];
217
+ if (options?.type) {
218
+ sql += ` AND type = ?`;
219
+ params.push(options.type);
220
+ }
221
+ sql += ` ORDER BY ${orderClause} LIMIT ?`;
222
+ params.push(limit);
223
+ const rows = db.prepare(sql).all(...params);
224
+ return rows.map(rowToSemanticNote);
225
+ }
226
+ export function updateSemanticNote(db, noteId, updates) {
227
+ const now = nowISO();
228
+ const setClauses = ["updated_at = ?"];
229
+ const params = [now];
230
+ if (updates.content !== undefined) {
231
+ setClauses.push("content = ?");
232
+ params.push(updates.content);
233
+ }
234
+ if (updates.confidence !== undefined) {
235
+ setClauses.push("confidence = ?");
236
+ params.push(updates.confidence);
237
+ }
238
+ if (updates.priority !== undefined) {
239
+ setClauses.push("priority = ?");
240
+ params.push(Math.max(0, Math.min(2, updates.priority)));
241
+ }
242
+ if (updates.keywords !== undefined) {
243
+ setClauses.push("keywords = ?");
244
+ params.push(JSON.stringify(updates.keywords));
245
+ }
246
+ if (updates.linkedNotes !== undefined) {
247
+ setClauses.push("linked_notes = ?");
248
+ params.push(JSON.stringify(updates.linkedNotes));
249
+ }
250
+ if (updates.linkReasons !== undefined) {
251
+ setClauses.push("link_reasons = ?");
252
+ params.push(JSON.stringify(updates.linkReasons));
253
+ }
254
+ params.push(noteId);
255
+ db.prepare(`UPDATE semantic_notes SET ${setClauses.join(", ")} WHERE note_id = ?`).run(...params);
256
+ }
257
+ export function supersedeNote(db, oldNoteId, newNote) {
258
+ // Inherit thread_id from the old note being superseded
259
+ const oldRow = db.prepare(`SELECT thread_id FROM semantic_notes WHERE note_id = ?`).get(oldNoteId);
260
+ const newId = saveSemanticNote(db, {
261
+ type: newNote.type,
262
+ content: newNote.content,
263
+ keywords: newNote.keywords,
264
+ confidence: newNote.confidence,
265
+ priority: newNote.priority,
266
+ threadId: oldRow?.thread_id ?? null,
267
+ sourceEpisodes: newNote.sourceEpisodes,
268
+ });
269
+ const now = nowISO();
270
+ db.prepare(`UPDATE semantic_notes SET superseded_by = ?, valid_to = ?, updated_at = ? WHERE note_id = ?`).run(newId, now, now, oldNoteId);
271
+ // Create bidirectional link: add old note to new note's linked_notes
272
+ const newRow = db.prepare(`SELECT linked_notes, link_reasons FROM semantic_notes WHERE note_id = ?`).get(newId);
273
+ const currentLinked = parseJsonArray(newRow?.linked_notes);
274
+ const currentReasons = parseJsonObject(newRow?.link_reasons);
275
+ if (!currentLinked.includes(oldNoteId)) {
276
+ currentLinked.push(oldNoteId);
277
+ }
278
+ currentReasons[oldNoteId] = "supersedes";
279
+ updateSemanticNote(db, newId, {
280
+ linkedNotes: currentLinked,
281
+ linkReasons: currentReasons,
282
+ });
283
+ return newId;
284
+ }
285
+ // ─── Embedding-based Semantic Search ─────────────────────────────────────────
286
+ /** Store a pre-computed embedding vector for a semantic note. */
287
+ export function saveNoteEmbedding(db, noteId, embedding) {
288
+ const buf = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
289
+ db.prepare(`INSERT OR REPLACE INTO note_embeddings (note_id, embedding, model, created_at) VALUES (?, ?, ?, ?)`).run(noteId, buf, "text-embedding-3-small", nowISO());
290
+ }
291
+ /** Load all note embeddings into memory for cosine similarity search. */
292
+ function loadAllEmbeddings(db, threadId) {
293
+ // When threadId is provided, return embeddings for notes in that thread OR global notes (thread_id IS NULL)
294
+ let sql = `SELECT ne.note_id, ne.embedding FROM note_embeddings ne
295
+ JOIN semantic_notes sn ON sn.note_id = ne.note_id
296
+ WHERE sn.valid_to IS NULL AND sn.superseded_by IS NULL`;
297
+ const params = [];
298
+ if (threadId !== undefined) {
299
+ sql += ` AND (sn.thread_id IS NULL OR sn.thread_id = ?)`;
300
+ params.push(threadId);
301
+ }
302
+ const rows = db.prepare(sql).all(...params);
303
+ const map = new Map();
304
+ for (const row of rows) {
305
+ map.set(row.note_id, new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.embedding.byteLength / 4));
306
+ }
307
+ return map;
308
+ }
309
+ /**
310
+ * Search semantic notes using embedding cosine similarity.
311
+ * Returns notes sorted by similarity score, filtered by minimum threshold.
312
+ */
313
+ export function searchByEmbedding(db, queryEmbedding, options) {
314
+ const maxResults = options?.maxResults ?? 5;
315
+ const minSimilarity = options?.minSimilarity ?? 0.3;
316
+ // Load embeddings — filtered by thread when provided
317
+ const embeddings = loadAllEmbeddings(db, options?.threadId);
318
+ // Compute similarities
319
+ const scores = [];
320
+ for (const [noteId, emb] of embeddings) {
321
+ const sim = cosineSimilarity(queryEmbedding, emb);
322
+ if (sim >= minSimilarity) {
323
+ scores.push({ noteId, similarity: sim });
324
+ }
325
+ }
326
+ // Sort by similarity descending
327
+ scores.sort((a, b) => b.similarity - a.similarity);
328
+ const topIds = scores.slice(0, maxResults);
329
+ if (topIds.length === 0)
330
+ return [];
331
+ // Fetch full notes
332
+ const placeholders = topIds.map(() => "?").join(",");
333
+ const rows = db.prepare(`SELECT * FROM semantic_notes WHERE note_id IN (${placeholders})`).all(...topIds.map(s => s.noteId));
334
+ const noteMap = new Map();
335
+ for (const row of rows) {
336
+ const note = rowToSemanticNote(row);
337
+ noteMap.set(note.noteId, note);
338
+ }
339
+ // Update access counts
340
+ if (!options?.skipAccessTracking) {
341
+ const now = nowISO();
342
+ const updateStmt = db.prepare(`UPDATE semantic_notes SET access_count = access_count + 1, last_accessed = ? WHERE note_id = ?`);
343
+ db.transaction(() => {
344
+ for (const s of topIds)
345
+ updateStmt.run(now, s.noteId);
346
+ })();
347
+ }
348
+ // Return in similarity order
349
+ return topIds
350
+ .map(s => {
351
+ const note = noteMap.get(s.noteId);
352
+ return note ? { ...note, similarity: s.similarity } : null;
353
+ })
354
+ .filter((n) => n !== null);
355
+ }
356
+ /** Get note IDs that don't have embeddings yet (for backfill). */
357
+ export function getNotesWithoutEmbeddings(db) {
358
+ return db.prepare(`SELECT sn.note_id as noteId, sn.content FROM semantic_notes sn
359
+ LEFT JOIN note_embeddings ne ON ne.note_id = sn.note_id
360
+ WHERE ne.note_id IS NULL AND sn.valid_to IS NULL AND sn.superseded_by IS NULL`).all();
361
+ }
362
+ /**
363
+ * Find semantic notes that potentially conflict with a given note
364
+ * by sharing >= 2 keywords of the same type.
365
+ */
366
+ export function findPotentialConflicts(db, noteId) {
367
+ const row = db.prepare(`SELECT note_id, type, keywords FROM semantic_notes WHERE note_id = ?`).get(noteId);
368
+ if (!row)
369
+ return [];
370
+ const noteKeywords = row.keywords ? JSON.parse(row.keywords) : [];
371
+ if (noteKeywords.length < 2)
372
+ return [];
373
+ // Fetch all active notes of the same type (excluding this note and superseded ones)
374
+ const candidates = db.prepare(`SELECT * FROM semantic_notes
375
+ WHERE type = ? AND note_id != ? AND valid_to IS NULL AND superseded_by IS NULL`).all(row.type, noteId);
376
+ const lowerKeywords = new Set(noteKeywords.map(k => k.toLowerCase()));
377
+ return candidates
378
+ .filter(c => {
379
+ const cKeywords = c.keywords ? JSON.parse(c.keywords) : [];
380
+ const overlap = cKeywords.filter(k => lowerKeywords.has(k.toLowerCase())).length;
381
+ return overlap >= 2;
382
+ })
383
+ .map(rowToSemanticNote);
384
+ }
385
+ //# sourceMappingURL=semantic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic.js","sourceRoot":"","sources":["../../../src/data/memory/semantic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { Database } from "./schema.js";
2
+ export interface VoiceBaseline {
3
+ avgArousal: number | null;
4
+ avgDominance: number | null;
5
+ avgValence: number | null;
6
+ avgSpeechRate: number | null;
7
+ avgMeanPitchHz: number | null;
8
+ avgPitchStdHz: number | null;
9
+ avgJitter: number | null;
10
+ avgShimmer: number | null;
11
+ avgHnrDb: number | null;
12
+ sampleCount: number;
13
+ }
14
+ export declare function saveVoiceSignature(db: Database, sig: {
15
+ episodeId: string;
16
+ emotion?: string;
17
+ arousal?: number;
18
+ dominance?: number;
19
+ valence?: number;
20
+ speechRate?: number;
21
+ meanPitchHz?: number;
22
+ pitchStdHz?: number;
23
+ jitter?: number;
24
+ shimmer?: number;
25
+ hnrDb?: number;
26
+ audioEvents?: Array<{
27
+ label: string;
28
+ confidence: number;
29
+ }>;
30
+ durationSec?: number;
31
+ }): void;
32
+ export declare function getVoiceBaseline(db: Database, dayRange?: number): VoiceBaseline | null;
33
+ //# sourceMappingURL=voice-sig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-sig.d.ts","sourceRoot":"","sources":["../../../src/data/memory/voice-sig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAeD,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACA,IAAI,CAqBN;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,SAAK,GAAG,aAAa,GAAG,IAAI,CAmClF"}
@@ -0,0 +1,48 @@
1
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
2
+ function nowISO() {
3
+ return new Date().toISOString();
4
+ }
5
+ function jsonOrNull(val) {
6
+ if (val === undefined || val === null)
7
+ return null;
8
+ return JSON.stringify(val);
9
+ }
10
+ // ─── Voice Signatures ────────────────────────────────────────────────────────
11
+ export function saveVoiceSignature(db, sig) {
12
+ db.prepare(`INSERT INTO voice_signatures
13
+ (episode_id, emotion, arousal, dominance, valence, speech_rate, mean_pitch_hz, pitch_std_hz, jitter, shimmer, hnr_db, audio_events, duration_sec, created_at)
14
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(sig.episodeId, sig.emotion ?? null, sig.arousal ?? null, sig.dominance ?? null, sig.valence ?? null, sig.speechRate ?? null, sig.meanPitchHz ?? null, sig.pitchStdHz ?? null, sig.jitter ?? null, sig.shimmer ?? null, sig.hnrDb ?? null, jsonOrNull(sig.audioEvents), sig.durationSec ?? null, nowISO());
15
+ }
16
+ export function getVoiceBaseline(db, dayRange = 30) {
17
+ const cutoff = new Date(Date.now() - dayRange * 24 * 60 * 60 * 1000).toISOString();
18
+ const row = db
19
+ .prepare(`SELECT
20
+ AVG(arousal) AS avg_arousal,
21
+ AVG(dominance) AS avg_dominance,
22
+ AVG(valence) AS avg_valence,
23
+ AVG(speech_rate) AS avg_speech_rate,
24
+ AVG(mean_pitch_hz) AS avg_mean_pitch_hz,
25
+ AVG(pitch_std_hz) AS avg_pitch_std_hz,
26
+ AVG(jitter) AS avg_jitter,
27
+ AVG(shimmer) AS avg_shimmer,
28
+ AVG(hnr_db) AS avg_hnr_db,
29
+ COUNT(*) AS sample_count
30
+ FROM voice_signatures
31
+ WHERE created_at >= ?`)
32
+ .get(cutoff);
33
+ if (!row || row.sample_count === 0)
34
+ return null;
35
+ return {
36
+ avgArousal: row.avg_arousal,
37
+ avgDominance: row.avg_dominance,
38
+ avgValence: row.avg_valence,
39
+ avgSpeechRate: row.avg_speech_rate,
40
+ avgMeanPitchHz: row.avg_mean_pitch_hz,
41
+ avgPitchStdHz: row.avg_pitch_std_hz,
42
+ avgJitter: row.avg_jitter,
43
+ avgShimmer: row.avg_shimmer,
44
+ avgHnrDb: row.avg_hnr_db,
45
+ sampleCount: row.sample_count,
46
+ };
47
+ }
48
+ //# sourceMappingURL=voice-sig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-sig.js","sourceRoot":"","sources":["../../../src/data/memory/voice-sig.ts"],"names":[],"mappings":"AAiBA,gFAAgF;AAEhF,SAAS,MAAM;IACb,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,SAAS,UAAU,CAAC,GAAY;IAC9B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,kBAAkB,CAChC,EAAY,EACZ,GAcC;IAED,EAAE,CAAC,OAAO,CACR;;uDAEmD,CACpD,CAAC,GAAG,CACH,GAAG,CAAC,SAAS,EACb,GAAG,CAAC,OAAO,IAAI,IAAI,EACnB,GAAG,CAAC,OAAO,IAAI,IAAI,EACnB,GAAG,CAAC,SAAS,IAAI,IAAI,EACrB,GAAG,CAAC,OAAO,IAAI,IAAI,EACnB,GAAG,CAAC,UAAU,IAAI,IAAI,EACtB,GAAG,CAAC,WAAW,IAAI,IAAI,EACvB,GAAG,CAAC,UAAU,IAAI,IAAI,EACtB,GAAG,CAAC,MAAM,IAAI,IAAI,EAClB,GAAG,CAAC,OAAO,IAAI,IAAI,EACnB,GAAG,CAAC,KAAK,IAAI,IAAI,EACjB,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,EAC3B,GAAG,CAAC,WAAW,IAAI,IAAI,EACvB,MAAM,EAAE,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,EAAY,EAAE,QAAQ,GAAG,EAAE;IAC1D,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAEnF,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CACN;;;;;;;;;;;;6BAYuB,CACxB;SACA,GAAG,CAAC,MAAM,CAAwC,CAAC;IAEtD,IAAI,CAAC,GAAG,IAAK,GAAG,CAAC,YAAuB,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE5D,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,WAA4B;QAC5C,YAAY,EAAE,GAAG,CAAC,aAA8B;QAChD,UAAU,EAAE,GAAG,CAAC,WAA4B;QAC5C,aAAa,EAAE,GAAG,CAAC,eAAgC;QACnD,cAAc,EAAE,GAAG,CAAC,iBAAkC;QACtD,aAAa,EAAE,GAAG,CAAC,gBAAiC;QACpD,SAAS,EAAE,GAAG,CAAC,UAA2B;QAC1C,UAAU,EAAE,GAAG,CAAC,WAA4B;QAC5C,QAAQ,EAAE,GAAG,CAAC,UAA2B;QACzC,WAAW,EAAE,GAAG,CAAC,YAAsB;KACxC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Template loading, caching, and rendering utilities.
3
+ *
4
+ * Templates live in ~/.remote-copilot-mcp/templates/{name}.md and are
5
+ * cached in-memory with a short TTL so edits take effect quickly without
6
+ * needing a server restart.
7
+ */
8
+ /**
9
+ * Load a template file from ~/.remote-copilot-mcp/templates/{name}.md.
10
+ * Returns the raw template string, or null if the file doesn't exist.
11
+ * Results are cached in memory with a 60-second TTL.
12
+ */
13
+ export declare function loadTemplate(name: string): string | null;
14
+ /**
15
+ * Replace all `{{VAR}}` placeholders in a template string with the
16
+ * corresponding values from the provided vars map.
17
+ */
18
+ export declare function renderTemplate(template: string, vars: Record<string, string>): string;
19
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/data/templates.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiBH;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBxD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAIrF"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Template loading, caching, and rendering utilities.
3
+ *
4
+ * Templates live in ~/.remote-copilot-mcp/templates/{name}.md and are
5
+ * cached in-memory with a short TTL so edits take effect quickly without
6
+ * needing a server restart.
7
+ */
8
+ import { readFileSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { TEMPLATES_DIR } from "../config.js";
11
+ // ── Template loading & caching ────────────────────────────────────────────
12
+ const TEMPLATE_TTL_MS = 60_000; // 60-second cache TTL
13
+ const templateCache = new Map();
14
+ /**
15
+ * Load a template file from ~/.remote-copilot-mcp/templates/{name}.md.
16
+ * Returns the raw template string, or null if the file doesn't exist.
17
+ * Results are cached in memory with a 60-second TTL.
18
+ */
19
+ export function loadTemplate(name) {
20
+ const now = Date.now();
21
+ const cached = templateCache.get(name);
22
+ if (cached && now - cached.loadedAt < TEMPLATE_TTL_MS) {
23
+ return cached.content;
24
+ }
25
+ const filePath = join(TEMPLATES_DIR, `${name}.md`);
26
+ let content = null;
27
+ try {
28
+ content = readFileSync(filePath, "utf-8");
29
+ }
30
+ catch {
31
+ // File doesn't exist or is unreadable — fall back to null
32
+ content = null;
33
+ }
34
+ templateCache.set(name, { content, loadedAt: now });
35
+ return content;
36
+ }
37
+ /**
38
+ * Replace all `{{VAR}}` placeholders in a template string with the
39
+ * corresponding values from the provided vars map.
40
+ */
41
+ export function renderTemplate(template, vars) {
42
+ return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
43
+ return Object.prototype.hasOwnProperty.call(vars, key) ? vars[key] : match;
44
+ });
45
+ }
46
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/data/templates.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,6EAA6E;AAE7E,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,sBAAsB;AAOtD,MAAM,aAAa,GAAG,IAAI,GAAG,EAA0B,CAAC;AAExD;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,QAAQ,GAAG,eAAe,EAAE,CAAC;QACtD,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;IACnD,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;QAC1D,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IACpD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,IAA4B;IAC3E,OAAO,QAAQ,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE;QAC/D,OAAO,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC"}