@memtensor/memos-local-openclaw-plugin 1.0.4 → 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 (61) 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/telemetry.d.ts +4 -1
  29. package/dist/telemetry.d.ts.map +1 -1
  30. package/dist/telemetry.js +26 -18
  31. package/dist/telemetry.js.map +1 -1
  32. package/dist/tools/memory-get.d.ts.map +1 -1
  33. package/dist/tools/memory-get.js +4 -1
  34. package/dist/tools/memory-get.js.map +1 -1
  35. package/dist/types.d.ts +1 -1
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/types.js.map +1 -1
  38. package/dist/viewer/server.d.ts +24 -0
  39. package/dist/viewer/server.d.ts.map +1 -1
  40. package/dist/viewer/server.js +332 -130
  41. package/dist/viewer/server.js.map +1 -1
  42. package/index.ts +66 -30
  43. package/package.json +1 -1
  44. package/scripts/postinstall.cjs +21 -5
  45. package/src/capture/index.ts +36 -0
  46. package/src/client/connector.ts +22 -1
  47. package/src/client/hub.ts +4 -0
  48. package/src/hub/server.ts +42 -26
  49. package/src/ingest/providers/index.ts +30 -93
  50. package/src/ingest/providers/openai.ts +32 -15
  51. package/src/recall/engine.ts +28 -19
  52. package/src/storage/sqlite.ts +156 -65
  53. package/src/telemetry.ts +25 -18
  54. package/src/tools/memory-get.ts +4 -1
  55. package/src/types.ts +2 -0
  56. package/src/viewer/server.ts +313 -125
  57. package/prebuilds/darwin-arm64/better_sqlite3.node +0 -0
  58. package/prebuilds/darwin-x64/better_sqlite3.node +0 -0
  59. package/prebuilds/linux-x64/better_sqlite3.node +0 -0
  60. package/prebuilds/win32-x64/better_sqlite3.node +0 -0
  61. package/telemetry.credentials.json +0 -5
@@ -116,6 +116,7 @@ export class SqliteStore {
116
116
  this.migrateLocalSharedTasksOwner();
117
117
  this.migrateHubUserIdentityFields();
118
118
  this.migrateClientHubConnectionIdentityFields();
119
+ this.migrateTeamSharingInstanceId();
119
120
  this.log.debug("Database schema initialized");
120
121
  }
121
122
 
@@ -176,6 +177,40 @@ export class SqliteStore {
176
177
  } catch { /* table may not exist yet */ }
177
178
  }
178
179
 
180
+ private migrateTeamSharingInstanceId(): void {
181
+ try {
182
+ const tscCols = this.db.prepare("PRAGMA table_info(team_shared_chunks)").all() as Array<{ name: string }>;
183
+ if (tscCols.length > 0 && !tscCols.some(c => c.name === "hub_instance_id")) {
184
+ this.db.exec("ALTER TABLE team_shared_chunks ADD COLUMN hub_instance_id TEXT NOT NULL DEFAULT ''");
185
+ this.log.info("Migrated: added hub_instance_id to team_shared_chunks");
186
+ }
187
+ } catch { /* table may not exist yet */ }
188
+ try {
189
+ const lstCols = this.db.prepare("PRAGMA table_info(local_shared_tasks)").all() as Array<{ name: string }>;
190
+ if (lstCols.length > 0 && !lstCols.some(c => c.name === "hub_instance_id")) {
191
+ this.db.exec("ALTER TABLE local_shared_tasks ADD COLUMN hub_instance_id TEXT NOT NULL DEFAULT ''");
192
+ this.log.info("Migrated: added hub_instance_id to local_shared_tasks");
193
+ }
194
+ } catch { /* table may not exist yet */ }
195
+ try {
196
+ const connCols = this.db.prepare("PRAGMA table_info(client_hub_connection)").all() as Array<{ name: string }>;
197
+ if (connCols.length > 0 && !connCols.some(c => c.name === "hub_instance_id")) {
198
+ this.db.exec("ALTER TABLE client_hub_connection ADD COLUMN hub_instance_id TEXT NOT NULL DEFAULT ''");
199
+ this.log.info("Migrated: added hub_instance_id to client_hub_connection");
200
+ }
201
+ } catch { /* table may not exist yet */ }
202
+ this.db.exec(`
203
+ CREATE TABLE IF NOT EXISTS team_shared_skills (
204
+ skill_id TEXT PRIMARY KEY,
205
+ hub_skill_id TEXT NOT NULL DEFAULT '',
206
+ visibility TEXT NOT NULL DEFAULT 'public',
207
+ group_id TEXT,
208
+ hub_instance_id TEXT NOT NULL DEFAULT '',
209
+ shared_at INTEGER NOT NULL
210
+ )
211
+ `);
212
+ }
213
+
179
214
  private migrateOwnerFields(): void {
180
215
  const chunkCols = this.db.prepare("PRAGMA table_info(chunks)").all() as Array<{ name: string }>;
181
216
  if (!chunkCols.some((c) => c.name === "owner")) {
@@ -778,12 +813,13 @@ export class SqliteStore {
778
813
  );
779
814
 
780
815
  CREATE TABLE IF NOT EXISTS local_shared_tasks (
781
- task_id TEXT PRIMARY KEY,
782
- hub_task_id TEXT NOT NULL,
783
- visibility TEXT NOT NULL DEFAULT 'public',
784
- group_id TEXT,
785
- synced_chunks INTEGER NOT NULL DEFAULT 0,
786
- shared_at INTEGER NOT NULL
816
+ task_id TEXT PRIMARY KEY,
817
+ hub_task_id TEXT NOT NULL,
818
+ visibility TEXT NOT NULL DEFAULT 'public',
819
+ group_id TEXT,
820
+ synced_chunks INTEGER NOT NULL DEFAULT 0,
821
+ hub_instance_id TEXT NOT NULL DEFAULT '',
822
+ shared_at INTEGER NOT NULL
787
823
  );
788
824
 
789
825
  CREATE TABLE IF NOT EXISTS local_shared_memories (
@@ -794,11 +830,21 @@ export class SqliteStore {
794
830
 
795
831
  -- Client: team share UI metadata only (no hub_memories row — avoids local FTS/embed recall duplication)
796
832
  CREATE TABLE IF NOT EXISTS team_shared_chunks (
797
- chunk_id TEXT PRIMARY KEY REFERENCES chunks(id) ON DELETE CASCADE,
798
- hub_memory_id TEXT NOT NULL DEFAULT '',
799
- visibility TEXT NOT NULL DEFAULT 'public',
800
- group_id TEXT,
801
- shared_at INTEGER NOT NULL
833
+ chunk_id TEXT PRIMARY KEY REFERENCES chunks(id) ON DELETE CASCADE,
834
+ hub_memory_id TEXT NOT NULL DEFAULT '',
835
+ visibility TEXT NOT NULL DEFAULT 'public',
836
+ group_id TEXT,
837
+ hub_instance_id TEXT NOT NULL DEFAULT '',
838
+ shared_at INTEGER NOT NULL
839
+ );
840
+
841
+ CREATE TABLE IF NOT EXISTS team_shared_skills (
842
+ skill_id TEXT PRIMARY KEY,
843
+ hub_skill_id TEXT NOT NULL DEFAULT '',
844
+ visibility TEXT NOT NULL DEFAULT 'public',
845
+ group_id TEXT,
846
+ hub_instance_id TEXT NOT NULL DEFAULT '',
847
+ shared_at INTEGER NOT NULL
802
848
  );
803
849
 
804
850
  CREATE TABLE IF NOT EXISTS hub_users (
@@ -959,12 +1005,7 @@ export class SqliteStore {
959
1005
  CREATE INDEX IF NOT EXISTS idx_hub_memories_visibility ON hub_memories(visibility);
960
1006
  CREATE INDEX IF NOT EXISTS idx_hub_memories_group ON hub_memories(group_id);
961
1007
 
962
- CREATE TABLE IF NOT EXISTS hub_memory_embeddings (
963
- memory_id TEXT PRIMARY KEY REFERENCES hub_memories(id) ON DELETE CASCADE,
964
- vector BLOB NOT NULL,
965
- dimensions INTEGER NOT NULL,
966
- updated_at INTEGER NOT NULL
967
- );
1008
+ -- hub_memory_embeddings removed: vectors are now computed on-the-fly at search time
968
1009
 
969
1010
  CREATE VIRTUAL TABLE IF NOT EXISTS hub_memories_fts USING fts5(
970
1011
  summary,
@@ -1379,6 +1420,7 @@ export class SqliteStore {
1379
1420
  "skills",
1380
1421
  "local_shared_memories",
1381
1422
  "team_shared_chunks",
1423
+ "team_shared_skills",
1382
1424
  "local_shared_tasks",
1383
1425
  "embeddings",
1384
1426
  "chunks",
@@ -1803,8 +1845,8 @@ export class SqliteStore {
1803
1845
 
1804
1846
  setClientHubConnection(conn: ClientHubConnection): void {
1805
1847
  this.db.prepare(`
1806
- INSERT INTO client_hub_connection (id, hub_url, user_id, username, user_token, role, connected_at, identity_key, last_known_status)
1807
- VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?)
1848
+ INSERT INTO client_hub_connection (id, hub_url, user_id, username, user_token, role, connected_at, identity_key, last_known_status, hub_instance_id)
1849
+ VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1808
1850
  ON CONFLICT(id) DO UPDATE SET
1809
1851
  hub_url = excluded.hub_url,
1810
1852
  user_id = excluded.user_id,
@@ -1813,8 +1855,9 @@ export class SqliteStore {
1813
1855
  role = excluded.role,
1814
1856
  connected_at = excluded.connected_at,
1815
1857
  identity_key = excluded.identity_key,
1816
- last_known_status = excluded.last_known_status
1817
- `).run(conn.hubUrl, conn.userId, conn.username, conn.userToken, conn.role, conn.connectedAt, conn.identityKey ?? "", conn.lastKnownStatus ?? "");
1858
+ last_known_status = excluded.last_known_status,
1859
+ hub_instance_id = excluded.hub_instance_id
1860
+ `).run(conn.hubUrl, conn.userId, conn.username, conn.userToken, conn.role, conn.connectedAt, conn.identityKey ?? "", conn.lastKnownStatus ?? "", conn.hubInstanceId ?? "");
1818
1861
  }
1819
1862
 
1820
1863
  getClientHubConnection(): ClientHubConnection | null {
@@ -1828,32 +1871,33 @@ export class SqliteStore {
1828
1871
 
1829
1872
  // ─── Local Shared Tasks (client-side tracking) ───
1830
1873
 
1831
- markTaskShared(taskId: string, hubTaskId: string, syncedChunks: number, visibility: string, groupId?: string | null): void {
1874
+ markTaskShared(taskId: string, hubTaskId: string, syncedChunks: number, visibility: string, groupId?: string | null, hubInstanceId?: string): void {
1832
1875
  this.db.prepare(`
1833
- INSERT INTO local_shared_tasks (task_id, hub_task_id, visibility, group_id, synced_chunks, shared_at)
1834
- VALUES (?, ?, ?, ?, ?, ?)
1876
+ INSERT INTO local_shared_tasks (task_id, hub_task_id, visibility, group_id, synced_chunks, hub_instance_id, shared_at)
1877
+ VALUES (?, ?, ?, ?, ?, ?, ?)
1835
1878
  ON CONFLICT(task_id) DO UPDATE SET
1836
1879
  hub_task_id = excluded.hub_task_id,
1837
1880
  visibility = excluded.visibility,
1838
1881
  group_id = excluded.group_id,
1839
1882
  synced_chunks = excluded.synced_chunks,
1883
+ hub_instance_id = excluded.hub_instance_id,
1840
1884
  shared_at = excluded.shared_at
1841
- `).run(taskId, hubTaskId, visibility, groupId ?? null, syncedChunks, Date.now());
1885
+ `).run(taskId, hubTaskId, visibility, groupId ?? null, syncedChunks, hubInstanceId ?? "", Date.now());
1842
1886
  }
1843
1887
 
1844
1888
  unmarkTaskShared(taskId: string): void {
1845
1889
  this.db.prepare('DELETE FROM local_shared_tasks WHERE task_id = ?').run(taskId);
1846
1890
  }
1847
1891
 
1848
- getLocalSharedTask(taskId: string): { taskId: string; hubTaskId: string; visibility: string; groupId: string | null; syncedChunks: number; sharedAt: number } | null {
1892
+ getLocalSharedTask(taskId: string): { taskId: string; hubTaskId: string; visibility: string; groupId: string | null; syncedChunks: number; sharedAt: number; hubInstanceId: string } | null {
1849
1893
  const row = this.db.prepare('SELECT * FROM local_shared_tasks WHERE task_id = ?').get(taskId) as any;
1850
1894
  if (!row) return null;
1851
- 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 };
1895
+ 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 || "" };
1852
1896
  }
1853
1897
 
1854
- listLocalSharedTasks(): Array<{ taskId: string; hubTaskId: string; visibility: string; groupId: string | null; syncedChunks: number }> {
1855
- const rows = this.db.prepare('SELECT task_id, hub_task_id, visibility, group_id, synced_chunks FROM local_shared_tasks').all() as any[];
1856
- return rows.map(r => ({ taskId: r.task_id, hubTaskId: r.hub_task_id, visibility: r.visibility, groupId: r.group_id, syncedChunks: r.synced_chunks }));
1898
+ listLocalSharedTasks(): Array<{ taskId: string; hubTaskId: string; visibility: string; groupId: string | null; syncedChunks: number; hubInstanceId: string }> {
1899
+ const rows = this.db.prepare('SELECT task_id, hub_task_id, visibility, group_id, synced_chunks, hub_instance_id FROM local_shared_tasks').all() as any[];
1900
+ 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 || "" }));
1857
1901
  }
1858
1902
 
1859
1903
  // ─── Local Shared Memories (client-side tracking) ───
@@ -1958,11 +2002,23 @@ export class SqliteStore {
1958
2002
  });
1959
2003
  }
1960
2004
 
2005
+ deleteHubMemoriesByUser(userId: string): void {
2006
+ this.db.prepare('DELETE FROM hub_memories WHERE source_user_id = ?').run(userId);
2007
+ }
2008
+
2009
+ deleteHubTasksByUser(userId: string): void {
2010
+ this.db.prepare('DELETE FROM hub_tasks WHERE source_user_id = ?').run(userId);
2011
+ }
2012
+
2013
+ deleteHubSkillsByUser(userId: string): void {
2014
+ this.db.prepare('DELETE FROM hub_skills WHERE source_user_id = ?').run(userId);
2015
+ }
2016
+
1961
2017
  deleteHubUser(userId: string, cleanResources = false): boolean {
1962
2018
  if (cleanResources) {
1963
- this.db.prepare('DELETE FROM hub_tasks WHERE source_user_id = ?').run(userId);
1964
- this.db.prepare('DELETE FROM hub_skills WHERE source_user_id = ?').run(userId);
1965
- this.db.prepare('DELETE FROM hub_memories WHERE source_user_id = ?').run(userId);
2019
+ this.deleteHubTasksByUser(userId);
2020
+ this.deleteHubSkillsByUser(userId);
2021
+ this.deleteHubMemoriesByUser(userId);
1966
2022
  const result = this.db.prepare('DELETE FROM hub_users WHERE id = ?').run(userId);
1967
2023
  return result.changes > 0;
1968
2024
  }
@@ -2369,25 +2425,26 @@ export class SqliteStore {
2369
2425
 
2370
2426
  upsertTeamSharedChunk(
2371
2427
  chunkId: string,
2372
- row: { hubMemoryId?: string; visibility?: string; groupId?: string | null },
2428
+ row: { hubMemoryId?: string; visibility?: string; groupId?: string | null; hubInstanceId?: string },
2373
2429
  ): void {
2374
2430
  const now = Date.now();
2375
2431
  const vis = row.visibility === "group" ? "group" : "public";
2376
2432
  const gid = vis === "group" ? (row.groupId ?? null) : null;
2377
2433
  this.db.prepare(`
2378
- INSERT INTO team_shared_chunks (chunk_id, hub_memory_id, visibility, group_id, shared_at)
2379
- VALUES (?, ?, ?, ?, ?)
2434
+ INSERT INTO team_shared_chunks (chunk_id, hub_memory_id, visibility, group_id, hub_instance_id, shared_at)
2435
+ VALUES (?, ?, ?, ?, ?, ?)
2380
2436
  ON CONFLICT(chunk_id) DO UPDATE SET
2381
2437
  hub_memory_id = excluded.hub_memory_id,
2382
2438
  visibility = excluded.visibility,
2383
2439
  group_id = excluded.group_id,
2440
+ hub_instance_id = excluded.hub_instance_id,
2384
2441
  shared_at = excluded.shared_at
2385
- `).run(chunkId, row.hubMemoryId ?? "", vis, gid, now);
2442
+ `).run(chunkId, row.hubMemoryId ?? "", vis, gid, row.hubInstanceId ?? "", now);
2386
2443
  }
2387
2444
 
2388
- getTeamSharedChunk(chunkId: string): { chunkId: string; hubMemoryId: string; visibility: string; groupId: string | null; sharedAt: number } | null {
2389
- 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) as {
2390
- chunk_id: string; hub_memory_id: string; visibility: string; group_id: string | null; shared_at: number;
2445
+ getTeamSharedChunk(chunkId: string): { chunkId: string; hubMemoryId: string; visibility: string; groupId: string | null; hubInstanceId: string; sharedAt: number } | null {
2446
+ 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) as {
2447
+ chunk_id: string; hub_memory_id: string; visibility: string; group_id: string | null; hub_instance_id: string; shared_at: number;
2391
2448
  } | undefined;
2392
2449
  if (!r) return null;
2393
2450
  return {
@@ -2395,6 +2452,7 @@ export class SqliteStore {
2395
2452
  hubMemoryId: r.hub_memory_id,
2396
2453
  visibility: r.visibility,
2397
2454
  groupId: r.group_id,
2455
+ hubInstanceId: r.hub_instance_id || "",
2398
2456
  sharedAt: r.shared_at,
2399
2457
  };
2400
2458
  }
@@ -2404,6 +2462,58 @@ export class SqliteStore {
2404
2462
  return info.changes > 0;
2405
2463
  }
2406
2464
 
2465
+ // ─── Team Shared Skills (Client role — UI metadata only) ───
2466
+
2467
+ upsertTeamSharedSkill(skillId: string, row: { hubSkillId?: string; visibility?: string; groupId?: string | null; hubInstanceId?: string }): void {
2468
+ const now = Date.now();
2469
+ const vis = row.visibility === "group" ? "group" : "public";
2470
+ const gid = vis === "group" ? (row.groupId ?? null) : null;
2471
+ this.db.prepare(`
2472
+ INSERT INTO team_shared_skills (skill_id, hub_skill_id, visibility, group_id, hub_instance_id, shared_at)
2473
+ VALUES (?, ?, ?, ?, ?, ?)
2474
+ ON CONFLICT(skill_id) DO UPDATE SET
2475
+ hub_skill_id = excluded.hub_skill_id,
2476
+ visibility = excluded.visibility,
2477
+ group_id = excluded.group_id,
2478
+ hub_instance_id = excluded.hub_instance_id,
2479
+ shared_at = excluded.shared_at
2480
+ `).run(skillId, row.hubSkillId ?? "", vis, gid, row.hubInstanceId ?? "", now);
2481
+ }
2482
+
2483
+ getTeamSharedSkill(skillId: string): { skillId: string; hubSkillId: string; visibility: string; groupId: string | null; hubInstanceId: string; sharedAt: number } | null {
2484
+ const r = this.db.prepare("SELECT * FROM team_shared_skills WHERE skill_id = ?").get(skillId) as any;
2485
+ if (!r) return null;
2486
+ 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 };
2487
+ }
2488
+
2489
+ deleteTeamSharedSkill(skillId: string): boolean {
2490
+ return this.db.prepare("DELETE FROM team_shared_skills WHERE skill_id = ?").run(skillId).changes > 0;
2491
+ }
2492
+
2493
+ // ─── Team sharing cleanup (role switch / leave) ───
2494
+
2495
+ clearTeamSharedChunks(): void {
2496
+ this.db.prepare("DELETE FROM team_shared_chunks").run();
2497
+ }
2498
+
2499
+ clearTeamSharedSkills(): void {
2500
+ this.db.prepare("DELETE FROM team_shared_skills").run();
2501
+ }
2502
+
2503
+ downgradeTeamSharedTasksToLocal(): void {
2504
+ this.db.prepare("UPDATE local_shared_tasks SET hub_task_id = '', hub_instance_id = '', visibility = 'public', group_id = NULL, synced_chunks = 0").run();
2505
+ }
2506
+
2507
+ downgradeTeamSharedTaskToLocal(taskId: string): void {
2508
+ 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);
2509
+ }
2510
+
2511
+ clearAllTeamSharingState(): void {
2512
+ this.clearTeamSharedChunks();
2513
+ this.clearTeamSharedSkills();
2514
+ this.downgradeTeamSharedTasksToLocal();
2515
+ }
2516
+
2407
2517
  // ─── Hub Notifications ───
2408
2518
 
2409
2519
  insertHubNotification(n: { id: string; userId: string; type: string; resource: string; title: string; message?: string }): void {
@@ -2445,20 +2555,8 @@ export class SqliteStore {
2445
2555
  this.db.prepare('DELETE FROM hub_notifications WHERE user_id = ?').run(userId);
2446
2556
  }
2447
2557
 
2448
- upsertHubMemoryEmbedding(memoryId: string, vector: Float32Array): void {
2449
- const buf = Buffer.from(vector.buffer, vector.byteOffset, vector.byteLength);
2450
- this.db.prepare(`
2451
- INSERT INTO hub_memory_embeddings (memory_id, vector, dimensions, updated_at)
2452
- VALUES (?, ?, ?, ?)
2453
- ON CONFLICT(memory_id) DO UPDATE SET vector = excluded.vector, dimensions = excluded.dimensions, updated_at = excluded.updated_at
2454
- `).run(memoryId, buf, vector.length, Date.now());
2455
- }
2456
-
2457
- getHubMemoryEmbedding(memoryId: string): Float32Array | null {
2458
- const row = this.db.prepare('SELECT vector, dimensions FROM hub_memory_embeddings WHERE memory_id = ?').get(memoryId) as { vector: Buffer; dimensions: number } | undefined;
2459
- if (!row) return null;
2460
- return new Float32Array(row.vector.buffer, row.vector.byteOffset, row.dimensions);
2461
- }
2558
+ // upsertHubMemoryEmbedding / getHubMemoryEmbedding removed:
2559
+ // hub memory vectors are now computed on-the-fly at search time.
2462
2560
 
2463
2561
  searchHubMemories(query: string, options?: { userId?: string; maxResults?: number }): Array<{ hit: HubMemorySearchRow; rank: number }> {
2464
2562
  const limit = options?.maxResults ?? 10;
@@ -2478,17 +2576,7 @@ export class SqliteStore {
2478
2576
  return rows.map((row, idx) => ({ hit: row, rank: idx + 1 }));
2479
2577
  }
2480
2578
 
2481
- getVisibleHubMemoryEmbeddings(userId: string): Array<{ memoryId: string; vector: Float32Array }> {
2482
- const rows = this.db.prepare(`
2483
- SELECT hme.memory_id, hme.vector, hme.dimensions
2484
- FROM hub_memory_embeddings hme
2485
- JOIN hub_memories hm ON hm.id = hme.memory_id
2486
- `).all() as Array<{ memory_id: string; vector: Buffer; dimensions: number }>;
2487
- return rows.map(r => ({
2488
- memoryId: r.memory_id,
2489
- vector: new Float32Array(r.vector.buffer, r.vector.byteOffset, r.dimensions),
2490
- }));
2491
- }
2579
+ // getVisibleHubMemoryEmbeddings removed: vectors computed on-the-fly at search time.
2492
2580
 
2493
2581
  getVisibleHubSearchHitByMemoryId(memoryId: string, userId: string): HubMemorySearchRow | null {
2494
2582
  const row = this.db.prepare(`
@@ -2740,6 +2828,7 @@ interface ClientHubConnection {
2740
2828
  connectedAt: number;
2741
2829
  identityKey?: string;
2742
2830
  lastKnownStatus?: string;
2831
+ hubInstanceId?: string;
2743
2832
  }
2744
2833
 
2745
2834
  interface ClientHubConnectionRow {
@@ -2751,6 +2840,7 @@ interface ClientHubConnectionRow {
2751
2840
  connected_at: number;
2752
2841
  identity_key?: string;
2753
2842
  last_known_status?: string;
2843
+ hub_instance_id?: string;
2754
2844
  }
2755
2845
 
2756
2846
  function rowToClientHubConnection(row: ClientHubConnectionRow): ClientHubConnection {
@@ -2763,6 +2853,7 @@ function rowToClientHubConnection(row: ClientHubConnectionRow): ClientHubConnect
2763
2853
  connectedAt: row.connected_at,
2764
2854
  identityKey: row.identity_key || "",
2765
2855
  lastKnownStatus: row.last_known_status || "",
2856
+ hubInstanceId: row.hub_instance_id || "",
2766
2857
  };
2767
2858
  }
2768
2859
 
package/src/telemetry.ts CHANGED
@@ -18,7 +18,7 @@ export interface TelemetryConfig {
18
18
  enabled?: boolean;
19
19
  }
20
20
 
21
- function loadTelemetryCredentials(): { endpoint: string; pid: string; env: string } {
21
+ function loadTelemetryCredentials(pluginDir?: string): { endpoint: string; pid: string; env: string } {
22
22
  if (process.env.MEMOS_ARMS_ENDPOINT) {
23
23
  return {
24
24
  endpoint: process.env.MEMOS_ARMS_ENDPOINT,
@@ -26,20 +26,19 @@ function loadTelemetryCredentials(): { endpoint: string; pid: string; env: strin
26
26
  env: process.env.MEMOS_ARMS_ENV ?? "prod",
27
27
  };
28
28
  }
29
- try {
30
- const credPath = path.resolve(__dirname, "..", "telemetry.credentials.json");
31
- const raw = fs.readFileSync(credPath, "utf-8");
32
- const creds = JSON.parse(raw);
33
- if (creds.endpoint) return { endpoint: creds.endpoint, pid: creds.pid ?? "", env: creds.env ?? "prod" };
34
- } catch {}
29
+ const bases = pluginDir ? [pluginDir, path.join(pluginDir, "src")] : [];
30
+ if (typeof __dirname === "string") bases.push(path.resolve(__dirname, ".."), __dirname);
31
+ const candidates = bases.map(b => path.join(b, "telemetry.credentials.json"));
32
+ for (const credPath of candidates) {
33
+ try {
34
+ const raw = fs.readFileSync(credPath, "utf-8");
35
+ const creds = JSON.parse(raw);
36
+ if (creds.endpoint) return { endpoint: creds.endpoint, pid: creds.pid ?? "", env: creds.env ?? "prod" };
37
+ } catch {}
38
+ }
35
39
  return { endpoint: "", pid: "", env: "prod" };
36
40
  }
37
41
 
38
- const _creds = loadTelemetryCredentials();
39
- const ARMS_ENDPOINT = _creds.endpoint;
40
- const ARMS_PID = _creds.pid;
41
- const ARMS_ENV = _creds.env;
42
-
43
42
  const FLUSH_AT = 10;
44
43
  const FLUSH_INTERVAL_MS = 30_000;
45
44
  const SEND_TIMEOUT_MS = 30_000;
@@ -67,8 +66,11 @@ export class Telemetry {
67
66
  private flushTimer: ReturnType<typeof setInterval> | null = null;
68
67
  private sessionId: string;
69
68
  private firstSeenDate: string;
69
+ private armsEndpoint: string;
70
+ private armsPid: string;
71
+ private armsEnv: string;
70
72
 
71
- constructor(config: TelemetryConfig, stateDir: string, pluginVersion: string, log: Logger) {
73
+ constructor(config: TelemetryConfig, stateDir: string, pluginVersion: string, log: Logger, pluginDir?: string) {
72
74
  this.log = log;
73
75
  this.pluginVersion = pluginVersion;
74
76
  this.enabled = config.enabled !== false;
@@ -76,10 +78,15 @@ export class Telemetry {
76
78
  this.firstSeenDate = this.loadOrCreateFirstSeen(stateDir);
77
79
  this.sessionId = this.loadOrCreateSessionId(stateDir);
78
80
 
79
- if (!this.enabled || !ARMS_ENDPOINT) {
81
+ const creds = loadTelemetryCredentials(pluginDir);
82
+ this.armsEndpoint = creds.endpoint;
83
+ this.armsPid = creds.pid;
84
+ this.armsEnv = creds.env;
85
+
86
+ if (!this.enabled || !this.armsEndpoint) {
80
87
  this.enabled = false;
81
88
  this.log.debug(
82
- !ARMS_ENDPOINT
89
+ !this.armsEndpoint
83
90
  ? "Telemetry disabled (no credentials configured)"
84
91
  : "Telemetry disabled (opt-out)",
85
92
  );
@@ -192,8 +199,8 @@ export class Telemetry {
192
199
  private buildPayload(events: ArmsEvent[]): Record<string, unknown> {
193
200
  return {
194
201
  app: {
195
- id: ARMS_PID,
196
- env: ARMS_ENV,
202
+ id: this.armsPid,
203
+ env: this.armsEnv,
197
204
  version: this.pluginVersion,
198
205
  type: "node",
199
206
  },
@@ -212,7 +219,7 @@ export class Telemetry {
212
219
  const payload = this.buildPayload(batch);
213
220
 
214
221
  try {
215
- const resp = await fetch(ARMS_ENDPOINT, {
222
+ const resp = await fetch(this.armsEndpoint, {
216
223
  method: "POST",
217
224
  headers: { "Content-Type": "text/plain" },
218
225
  body: JSON.stringify(payload),
@@ -47,7 +47,10 @@ export function createMemoryGetTool(store: SqliteStore): ToolDefinition {
47
47
  return { error: `Chunk not found: ${ref.chunkId}` };
48
48
  }
49
49
 
50
- const content = chunk.content;
50
+ let content = chunk.content;
51
+ if (content.length > maxChars) {
52
+ content = content.slice(0, maxChars) + "…";
53
+ }
51
54
 
52
55
  const result: GetResult = {
53
56
  content,
package/src/types.ts CHANGED
@@ -150,6 +150,8 @@ export type SummaryProvider =
150
150
  | "bedrock"
151
151
  | "zhipu"
152
152
  | "siliconflow"
153
+ | "deepseek"
154
+ | "moonshot"
153
155
  | "bailian"
154
156
  | "cohere"
155
157
  | "mistral"