@memtensor/memos-local-openclaw-plugin 1.0.5 → 1.0.6-beta.1

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 (56) hide show
  1. package/dist/capture/index.d.ts.map +1 -1
  2. package/dist/capture/index.js +24 -0
  3. package/dist/capture/index.js.map +1 -1
  4. package/dist/client/connector.d.ts.map +1 -1
  5. package/dist/client/connector.js +23 -1
  6. package/dist/client/connector.js.map +1 -1
  7. package/dist/client/hub.d.ts.map +1 -1
  8. package/dist/client/hub.js +4 -0
  9. package/dist/client/hub.js.map +1 -1
  10. package/dist/hub/server.d.ts +1 -1
  11. package/dist/hub/server.d.ts.map +1 -1
  12. package/dist/hub/server.js +39 -31
  13. package/dist/hub/server.js.map +1 -1
  14. package/dist/ingest/providers/index.d.ts.map +1 -1
  15. package/dist/ingest/providers/index.js +16 -86
  16. package/dist/ingest/providers/index.js.map +1 -1
  17. package/dist/ingest/providers/openai.d.ts +3 -0
  18. package/dist/ingest/providers/openai.d.ts.map +1 -1
  19. package/dist/ingest/providers/openai.js +34 -19
  20. package/dist/ingest/providers/openai.js.map +1 -1
  21. package/dist/recall/engine.d.ts.map +1 -1
  22. package/dist/recall/engine.js +28 -19
  23. package/dist/recall/engine.js.map +1 -1
  24. package/dist/storage/sqlite.d.ts +30 -7
  25. package/dist/storage/sqlite.d.ts.map +1 -1
  26. package/dist/storage/sqlite.js +139 -60
  27. package/dist/storage/sqlite.js.map +1 -1
  28. package/dist/tools/memory-get.d.ts.map +1 -1
  29. package/dist/tools/memory-get.js +4 -1
  30. package/dist/tools/memory-get.js.map +1 -1
  31. package/dist/types.d.ts +1 -1
  32. package/dist/types.d.ts.map +1 -1
  33. package/dist/types.js.map +1 -1
  34. package/dist/viewer/server.d.ts +24 -0
  35. package/dist/viewer/server.d.ts.map +1 -1
  36. package/dist/viewer/server.js +332 -130
  37. package/dist/viewer/server.js.map +1 -1
  38. package/index.ts +65 -29
  39. package/package.json +1 -1
  40. package/scripts/postinstall.cjs +21 -5
  41. package/src/capture/index.ts +36 -0
  42. package/src/client/connector.ts +22 -1
  43. package/src/client/hub.ts +4 -0
  44. package/src/hub/server.ts +42 -26
  45. package/src/ingest/providers/index.ts +30 -93
  46. package/src/ingest/providers/openai.ts +32 -15
  47. package/src/recall/engine.ts +28 -19
  48. package/src/storage/sqlite.ts +156 -65
  49. package/src/tools/memory-get.ts +4 -1
  50. package/src/types.ts +2 -0
  51. package/src/viewer/server.ts +313 -125
  52. package/prebuilds/darwin-arm64/better_sqlite3.node +0 -0
  53. package/prebuilds/darwin-x64/better_sqlite3.node +0 -0
  54. package/prebuilds/linux-x64/better_sqlite3.node +0 -0
  55. package/prebuilds/win32-x64/better_sqlite3.node +0 -0
  56. package/telemetry.credentials.json +0 -5
@@ -150,6 +150,7 @@ class SqliteStore {
150
150
  this.migrateLocalSharedTasksOwner();
151
151
  this.migrateHubUserIdentityFields();
152
152
  this.migrateClientHubConnectionIdentityFields();
153
+ this.migrateTeamSharingInstanceId();
153
154
  this.log.debug("Database schema initialized");
154
155
  }
155
156
  migrateChunksIndexesForRecall() {
@@ -210,6 +211,42 @@ class SqliteStore {
210
211
  }
211
212
  catch { /* table may not exist yet */ }
212
213
  }
214
+ migrateTeamSharingInstanceId() {
215
+ try {
216
+ const tscCols = this.db.prepare("PRAGMA table_info(team_shared_chunks)").all();
217
+ if (tscCols.length > 0 && !tscCols.some(c => c.name === "hub_instance_id")) {
218
+ this.db.exec("ALTER TABLE team_shared_chunks ADD COLUMN hub_instance_id TEXT NOT NULL DEFAULT ''");
219
+ this.log.info("Migrated: added hub_instance_id to team_shared_chunks");
220
+ }
221
+ }
222
+ catch { /* table may not exist yet */ }
223
+ try {
224
+ const lstCols = this.db.prepare("PRAGMA table_info(local_shared_tasks)").all();
225
+ if (lstCols.length > 0 && !lstCols.some(c => c.name === "hub_instance_id")) {
226
+ this.db.exec("ALTER TABLE local_shared_tasks ADD COLUMN hub_instance_id TEXT NOT NULL DEFAULT ''");
227
+ this.log.info("Migrated: added hub_instance_id to local_shared_tasks");
228
+ }
229
+ }
230
+ catch { /* table may not exist yet */ }
231
+ try {
232
+ const connCols = this.db.prepare("PRAGMA table_info(client_hub_connection)").all();
233
+ if (connCols.length > 0 && !connCols.some(c => c.name === "hub_instance_id")) {
234
+ this.db.exec("ALTER TABLE client_hub_connection ADD COLUMN hub_instance_id TEXT NOT NULL DEFAULT ''");
235
+ this.log.info("Migrated: added hub_instance_id to client_hub_connection");
236
+ }
237
+ }
238
+ catch { /* table may not exist yet */ }
239
+ this.db.exec(`
240
+ CREATE TABLE IF NOT EXISTS team_shared_skills (
241
+ skill_id TEXT PRIMARY KEY,
242
+ hub_skill_id TEXT NOT NULL DEFAULT '',
243
+ visibility TEXT NOT NULL DEFAULT 'public',
244
+ group_id TEXT,
245
+ hub_instance_id TEXT NOT NULL DEFAULT '',
246
+ shared_at INTEGER NOT NULL
247
+ )
248
+ `);
249
+ }
213
250
  migrateOwnerFields() {
214
251
  const chunkCols = this.db.prepare("PRAGMA table_info(chunks)").all();
215
252
  if (!chunkCols.some((c) => c.name === "owner")) {
@@ -744,12 +781,13 @@ class SqliteStore {
744
781
  );
745
782
 
746
783
  CREATE TABLE IF NOT EXISTS local_shared_tasks (
747
- task_id TEXT PRIMARY KEY,
748
- hub_task_id TEXT NOT NULL,
749
- visibility TEXT NOT NULL DEFAULT 'public',
750
- group_id TEXT,
751
- synced_chunks INTEGER NOT NULL DEFAULT 0,
752
- shared_at INTEGER NOT NULL
784
+ task_id TEXT PRIMARY KEY,
785
+ hub_task_id TEXT NOT NULL,
786
+ visibility TEXT NOT NULL DEFAULT 'public',
787
+ group_id TEXT,
788
+ synced_chunks INTEGER NOT NULL DEFAULT 0,
789
+ hub_instance_id TEXT NOT NULL DEFAULT '',
790
+ shared_at INTEGER NOT NULL
753
791
  );
754
792
 
755
793
  CREATE TABLE IF NOT EXISTS local_shared_memories (
@@ -760,11 +798,21 @@ class SqliteStore {
760
798
 
761
799
  -- Client: team share UI metadata only (no hub_memories row — avoids local FTS/embed recall duplication)
762
800
  CREATE TABLE IF NOT EXISTS team_shared_chunks (
763
- chunk_id TEXT PRIMARY KEY REFERENCES chunks(id) ON DELETE CASCADE,
764
- hub_memory_id TEXT NOT NULL DEFAULT '',
765
- visibility TEXT NOT NULL DEFAULT 'public',
766
- group_id TEXT,
767
- shared_at INTEGER NOT NULL
801
+ chunk_id TEXT PRIMARY KEY REFERENCES chunks(id) ON DELETE CASCADE,
802
+ hub_memory_id TEXT NOT NULL DEFAULT '',
803
+ visibility TEXT NOT NULL DEFAULT 'public',
804
+ group_id TEXT,
805
+ hub_instance_id TEXT NOT NULL DEFAULT '',
806
+ shared_at INTEGER NOT NULL
807
+ );
808
+
809
+ CREATE TABLE IF NOT EXISTS team_shared_skills (
810
+ skill_id TEXT PRIMARY KEY,
811
+ hub_skill_id TEXT NOT NULL DEFAULT '',
812
+ visibility TEXT NOT NULL DEFAULT 'public',
813
+ group_id TEXT,
814
+ hub_instance_id TEXT NOT NULL DEFAULT '',
815
+ shared_at INTEGER NOT NULL
768
816
  );
769
817
 
770
818
  CREATE TABLE IF NOT EXISTS hub_users (
@@ -925,12 +973,7 @@ class SqliteStore {
925
973
  CREATE INDEX IF NOT EXISTS idx_hub_memories_visibility ON hub_memories(visibility);
926
974
  CREATE INDEX IF NOT EXISTS idx_hub_memories_group ON hub_memories(group_id);
927
975
 
928
- CREATE TABLE IF NOT EXISTS hub_memory_embeddings (
929
- memory_id TEXT PRIMARY KEY REFERENCES hub_memories(id) ON DELETE CASCADE,
930
- vector BLOB NOT NULL,
931
- dimensions INTEGER NOT NULL,
932
- updated_at INTEGER NOT NULL
933
- );
976
+ -- hub_memory_embeddings removed: vectors are now computed on-the-fly at search time
934
977
 
935
978
  CREATE VIRTUAL TABLE IF NOT EXISTS hub_memories_fts USING fts5(
936
979
  summary,
@@ -1272,6 +1315,7 @@ class SqliteStore {
1272
1315
  "skills",
1273
1316
  "local_shared_memories",
1274
1317
  "team_shared_chunks",
1318
+ "team_shared_skills",
1275
1319
  "local_shared_tasks",
1276
1320
  "embeddings",
1277
1321
  "chunks",
@@ -1651,8 +1695,8 @@ class SqliteStore {
1651
1695
  // ─── Hub / Client connection ───
1652
1696
  setClientHubConnection(conn) {
1653
1697
  this.db.prepare(`
1654
- INSERT INTO client_hub_connection (id, hub_url, user_id, username, user_token, role, connected_at, identity_key, last_known_status)
1655
- VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?)
1698
+ INSERT INTO client_hub_connection (id, hub_url, user_id, username, user_token, role, connected_at, identity_key, last_known_status, hub_instance_id)
1699
+ VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1656
1700
  ON CONFLICT(id) DO UPDATE SET
1657
1701
  hub_url = excluded.hub_url,
1658
1702
  user_id = excluded.user_id,
@@ -1661,8 +1705,9 @@ class SqliteStore {
1661
1705
  role = excluded.role,
1662
1706
  connected_at = excluded.connected_at,
1663
1707
  identity_key = excluded.identity_key,
1664
- last_known_status = excluded.last_known_status
1665
- `).run(conn.hubUrl, conn.userId, conn.username, conn.userToken, conn.role, conn.connectedAt, conn.identityKey ?? "", conn.lastKnownStatus ?? "");
1708
+ last_known_status = excluded.last_known_status,
1709
+ hub_instance_id = excluded.hub_instance_id
1710
+ `).run(conn.hubUrl, conn.userId, conn.username, conn.userToken, conn.role, conn.connectedAt, conn.identityKey ?? "", conn.lastKnownStatus ?? "", conn.hubInstanceId ?? "");
1666
1711
  }
1667
1712
  getClientHubConnection() {
1668
1713
  const row = this.db.prepare('SELECT * FROM client_hub_connection WHERE id = 1').get();
@@ -1672,17 +1717,18 @@ class SqliteStore {
1672
1717
  this.db.prepare('DELETE FROM client_hub_connection WHERE id = 1').run();
1673
1718
  }
1674
1719
  // ─── Local Shared Tasks (client-side tracking) ───
1675
- markTaskShared(taskId, hubTaskId, syncedChunks, visibility, groupId) {
1720
+ markTaskShared(taskId, hubTaskId, syncedChunks, visibility, groupId, hubInstanceId) {
1676
1721
  this.db.prepare(`
1677
- INSERT INTO local_shared_tasks (task_id, hub_task_id, visibility, group_id, synced_chunks, shared_at)
1678
- VALUES (?, ?, ?, ?, ?, ?)
1722
+ INSERT INTO local_shared_tasks (task_id, hub_task_id, visibility, group_id, synced_chunks, hub_instance_id, shared_at)
1723
+ VALUES (?, ?, ?, ?, ?, ?, ?)
1679
1724
  ON CONFLICT(task_id) DO UPDATE SET
1680
1725
  hub_task_id = excluded.hub_task_id,
1681
1726
  visibility = excluded.visibility,
1682
1727
  group_id = excluded.group_id,
1683
1728
  synced_chunks = excluded.synced_chunks,
1729
+ hub_instance_id = excluded.hub_instance_id,
1684
1730
  shared_at = excluded.shared_at
1685
- `).run(taskId, hubTaskId, visibility, groupId ?? null, syncedChunks, Date.now());
1731
+ `).run(taskId, hubTaskId, visibility, groupId ?? null, syncedChunks, hubInstanceId ?? "", Date.now());
1686
1732
  }
1687
1733
  unmarkTaskShared(taskId) {
1688
1734
  this.db.prepare('DELETE FROM local_shared_tasks WHERE task_id = ?').run(taskId);
@@ -1691,11 +1737,11 @@ class SqliteStore {
1691
1737
  const row = this.db.prepare('SELECT * FROM local_shared_tasks WHERE task_id = ?').get(taskId);
1692
1738
  if (!row)
1693
1739
  return null;
1694
- return { taskId: row.task_id, hubTaskId: row.hub_task_id, visibility: row.visibility, groupId: row.group_id, syncedChunks: row.synced_chunks, sharedAt: row.shared_at };
1740
+ return { taskId: row.task_id, hubTaskId: row.hub_task_id, visibility: row.visibility, groupId: row.group_id, syncedChunks: row.synced_chunks, sharedAt: row.shared_at, hubInstanceId: row.hub_instance_id || "" };
1695
1741
  }
1696
1742
  listLocalSharedTasks() {
1697
- const rows = this.db.prepare('SELECT task_id, hub_task_id, visibility, group_id, synced_chunks FROM local_shared_tasks').all();
1698
- return rows.map(r => ({ taskId: r.task_id, hubTaskId: r.hub_task_id, visibility: r.visibility, groupId: r.group_id, syncedChunks: r.synced_chunks }));
1743
+ const rows = this.db.prepare('SELECT task_id, hub_task_id, visibility, group_id, synced_chunks, hub_instance_id FROM local_shared_tasks').all();
1744
+ return rows.map(r => ({ taskId: r.task_id, hubTaskId: r.hub_task_id, visibility: r.visibility, groupId: r.group_id, syncedChunks: r.synced_chunks, hubInstanceId: r.hub_instance_id || "" }));
1699
1745
  }
1700
1746
  // ─── Local Shared Memories (client-side tracking) ───
1701
1747
  markMemorySharedLocally(chunkId) {
@@ -1790,11 +1836,20 @@ class SqliteStore {
1790
1836
  return user;
1791
1837
  });
1792
1838
  }
1839
+ deleteHubMemoriesByUser(userId) {
1840
+ this.db.prepare('DELETE FROM hub_memories WHERE source_user_id = ?').run(userId);
1841
+ }
1842
+ deleteHubTasksByUser(userId) {
1843
+ this.db.prepare('DELETE FROM hub_tasks WHERE source_user_id = ?').run(userId);
1844
+ }
1845
+ deleteHubSkillsByUser(userId) {
1846
+ this.db.prepare('DELETE FROM hub_skills WHERE source_user_id = ?').run(userId);
1847
+ }
1793
1848
  deleteHubUser(userId, cleanResources = false) {
1794
1849
  if (cleanResources) {
1795
- this.db.prepare('DELETE FROM hub_tasks WHERE source_user_id = ?').run(userId);
1796
- this.db.prepare('DELETE FROM hub_skills WHERE source_user_id = ?').run(userId);
1797
- this.db.prepare('DELETE FROM hub_memories WHERE source_user_id = ?').run(userId);
1850
+ this.deleteHubTasksByUser(userId);
1851
+ this.deleteHubSkillsByUser(userId);
1852
+ this.deleteHubMemoriesByUser(userId);
1798
1853
  const result = this.db.prepare('DELETE FROM hub_users WHERE id = ?').run(userId);
1799
1854
  return result.changes > 0;
1800
1855
  }
@@ -2179,17 +2234,18 @@ class SqliteStore {
2179
2234
  const vis = row.visibility === "group" ? "group" : "public";
2180
2235
  const gid = vis === "group" ? (row.groupId ?? null) : null;
2181
2236
  this.db.prepare(`
2182
- INSERT INTO team_shared_chunks (chunk_id, hub_memory_id, visibility, group_id, shared_at)
2183
- VALUES (?, ?, ?, ?, ?)
2237
+ INSERT INTO team_shared_chunks (chunk_id, hub_memory_id, visibility, group_id, hub_instance_id, shared_at)
2238
+ VALUES (?, ?, ?, ?, ?, ?)
2184
2239
  ON CONFLICT(chunk_id) DO UPDATE SET
2185
2240
  hub_memory_id = excluded.hub_memory_id,
2186
2241
  visibility = excluded.visibility,
2187
2242
  group_id = excluded.group_id,
2243
+ hub_instance_id = excluded.hub_instance_id,
2188
2244
  shared_at = excluded.shared_at
2189
- `).run(chunkId, row.hubMemoryId ?? "", vis, gid, now);
2245
+ `).run(chunkId, row.hubMemoryId ?? "", vis, gid, row.hubInstanceId ?? "", now);
2190
2246
  }
2191
2247
  getTeamSharedChunk(chunkId) {
2192
- const r = this.db.prepare("SELECT chunk_id, hub_memory_id, visibility, group_id, shared_at FROM team_shared_chunks WHERE chunk_id = ?").get(chunkId);
2248
+ const r = this.db.prepare("SELECT chunk_id, hub_memory_id, visibility, group_id, hub_instance_id, shared_at FROM team_shared_chunks WHERE chunk_id = ?").get(chunkId);
2193
2249
  if (!r)
2194
2250
  return null;
2195
2251
  return {
@@ -2197,6 +2253,7 @@ class SqliteStore {
2197
2253
  hubMemoryId: r.hub_memory_id,
2198
2254
  visibility: r.visibility,
2199
2255
  groupId: r.group_id,
2256
+ hubInstanceId: r.hub_instance_id || "",
2200
2257
  sharedAt: r.shared_at,
2201
2258
  };
2202
2259
  }
@@ -2204,6 +2261,49 @@ class SqliteStore {
2204
2261
  const info = this.db.prepare("DELETE FROM team_shared_chunks WHERE chunk_id = ?").run(chunkId);
2205
2262
  return info.changes > 0;
2206
2263
  }
2264
+ // ─── Team Shared Skills (Client role — UI metadata only) ───
2265
+ upsertTeamSharedSkill(skillId, row) {
2266
+ const now = Date.now();
2267
+ const vis = row.visibility === "group" ? "group" : "public";
2268
+ const gid = vis === "group" ? (row.groupId ?? null) : null;
2269
+ this.db.prepare(`
2270
+ INSERT INTO team_shared_skills (skill_id, hub_skill_id, visibility, group_id, hub_instance_id, shared_at)
2271
+ VALUES (?, ?, ?, ?, ?, ?)
2272
+ ON CONFLICT(skill_id) DO UPDATE SET
2273
+ hub_skill_id = excluded.hub_skill_id,
2274
+ visibility = excluded.visibility,
2275
+ group_id = excluded.group_id,
2276
+ hub_instance_id = excluded.hub_instance_id,
2277
+ shared_at = excluded.shared_at
2278
+ `).run(skillId, row.hubSkillId ?? "", vis, gid, row.hubInstanceId ?? "", now);
2279
+ }
2280
+ getTeamSharedSkill(skillId) {
2281
+ const r = this.db.prepare("SELECT * FROM team_shared_skills WHERE skill_id = ?").get(skillId);
2282
+ if (!r)
2283
+ return null;
2284
+ return { skillId: r.skill_id, hubSkillId: r.hub_skill_id, visibility: r.visibility, groupId: r.group_id, hubInstanceId: r.hub_instance_id || "", sharedAt: r.shared_at };
2285
+ }
2286
+ deleteTeamSharedSkill(skillId) {
2287
+ return this.db.prepare("DELETE FROM team_shared_skills WHERE skill_id = ?").run(skillId).changes > 0;
2288
+ }
2289
+ // ─── Team sharing cleanup (role switch / leave) ───
2290
+ clearTeamSharedChunks() {
2291
+ this.db.prepare("DELETE FROM team_shared_chunks").run();
2292
+ }
2293
+ clearTeamSharedSkills() {
2294
+ this.db.prepare("DELETE FROM team_shared_skills").run();
2295
+ }
2296
+ downgradeTeamSharedTasksToLocal() {
2297
+ this.db.prepare("UPDATE local_shared_tasks SET hub_task_id = '', hub_instance_id = '', visibility = 'public', group_id = NULL, synced_chunks = 0").run();
2298
+ }
2299
+ downgradeTeamSharedTaskToLocal(taskId) {
2300
+ this.db.prepare("UPDATE local_shared_tasks SET hub_task_id = '', hub_instance_id = '', visibility = 'public', group_id = NULL, synced_chunks = 0 WHERE task_id = ?").run(taskId);
2301
+ }
2302
+ clearAllTeamSharingState() {
2303
+ this.clearTeamSharedChunks();
2304
+ this.clearTeamSharedSkills();
2305
+ this.downgradeTeamSharedTasksToLocal();
2306
+ }
2207
2307
  // ─── Hub Notifications ───
2208
2308
  insertHubNotification(n) {
2209
2309
  this.db.prepare('INSERT INTO hub_notifications (id, user_id, type, resource, title, message, read, created_at) VALUES (?, ?, ?, ?, ?, ?, 0, ?)').run(n.id, n.userId, n.type, n.resource, n.title, n.message ?? '', Date.now());
@@ -2235,20 +2335,8 @@ class SqliteStore {
2235
2335
  clearHubNotifications(userId) {
2236
2336
  this.db.prepare('DELETE FROM hub_notifications WHERE user_id = ?').run(userId);
2237
2337
  }
2238
- upsertHubMemoryEmbedding(memoryId, vector) {
2239
- const buf = Buffer.from(vector.buffer, vector.byteOffset, vector.byteLength);
2240
- this.db.prepare(`
2241
- INSERT INTO hub_memory_embeddings (memory_id, vector, dimensions, updated_at)
2242
- VALUES (?, ?, ?, ?)
2243
- ON CONFLICT(memory_id) DO UPDATE SET vector = excluded.vector, dimensions = excluded.dimensions, updated_at = excluded.updated_at
2244
- `).run(memoryId, buf, vector.length, Date.now());
2245
- }
2246
- getHubMemoryEmbedding(memoryId) {
2247
- const row = this.db.prepare('SELECT vector, dimensions FROM hub_memory_embeddings WHERE memory_id = ?').get(memoryId);
2248
- if (!row)
2249
- return null;
2250
- return new Float32Array(row.vector.buffer, row.vector.byteOffset, row.dimensions);
2251
- }
2338
+ // upsertHubMemoryEmbedding / getHubMemoryEmbedding removed:
2339
+ // hub memory vectors are now computed on-the-fly at search time.
2252
2340
  searchHubMemories(query, options) {
2253
2341
  const limit = options?.maxResults ?? 10;
2254
2342
  const userId = options?.userId ?? "";
@@ -2267,17 +2355,7 @@ class SqliteStore {
2267
2355
  `).all(sanitized, limit);
2268
2356
  return rows.map((row, idx) => ({ hit: row, rank: idx + 1 }));
2269
2357
  }
2270
- getVisibleHubMemoryEmbeddings(userId) {
2271
- const rows = this.db.prepare(`
2272
- SELECT hme.memory_id, hme.vector, hme.dimensions
2273
- FROM hub_memory_embeddings hme
2274
- JOIN hub_memories hm ON hm.id = hme.memory_id
2275
- `).all();
2276
- return rows.map(r => ({
2277
- memoryId: r.memory_id,
2278
- vector: new Float32Array(r.vector.buffer, r.vector.byteOffset, r.dimensions),
2279
- }));
2280
- }
2358
+ // getVisibleHubMemoryEmbeddings removed: vectors computed on-the-fly at search time.
2281
2359
  getVisibleHubSearchHitByMemoryId(memoryId, userId) {
2282
2360
  const row = this.db.prepare(`
2283
2361
  SELECT hm.id, hm.content, hm.summary, hm.role, hm.created_at, hm.visibility, '' as group_name, hu.username as owner_name,
@@ -2451,6 +2529,7 @@ function rowToClientHubConnection(row) {
2451
2529
  connectedAt: row.connected_at,
2452
2530
  identityKey: row.identity_key || "",
2453
2531
  lastKnownStatus: row.last_known_status || "",
2532
+ hubInstanceId: row.hub_instance_id || "",
2454
2533
  };
2455
2534
  }
2456
2535
  function rowToHubUser(row) {