@memtensor/memos-local-openclaw-plugin 1.0.4-beta.10 → 1.0.4-beta.12

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 (72) hide show
  1. package/dist/client/connector.d.ts +5 -0
  2. package/dist/client/connector.d.ts.map +1 -1
  3. package/dist/client/connector.js +38 -8
  4. package/dist/client/connector.js.map +1 -1
  5. package/dist/hub/server.d.ts +1 -0
  6. package/dist/hub/server.d.ts.map +1 -1
  7. package/dist/hub/server.js +143 -32
  8. package/dist/hub/server.js.map +1 -1
  9. package/dist/hub/user-manager.d.ts +9 -0
  10. package/dist/hub/user-manager.d.ts.map +1 -1
  11. package/dist/hub/user-manager.js +26 -2
  12. package/dist/hub/user-manager.js.map +1 -1
  13. package/dist/ingest/chunker.d.ts +2 -1
  14. package/dist/ingest/chunker.d.ts.map +1 -1
  15. package/dist/ingest/chunker.js +14 -10
  16. package/dist/ingest/chunker.js.map +1 -1
  17. package/dist/recall/engine.d.ts.map +1 -1
  18. package/dist/recall/engine.js +7 -2
  19. package/dist/recall/engine.js.map +1 -1
  20. package/dist/sharing/types.d.ts +1 -1
  21. package/dist/sharing/types.d.ts.map +1 -1
  22. package/dist/skill/evolver.d.ts +2 -0
  23. package/dist/skill/evolver.d.ts.map +1 -1
  24. package/dist/skill/evolver.js +56 -5
  25. package/dist/skill/evolver.js.map +1 -1
  26. package/dist/skill/generator.d.ts +2 -0
  27. package/dist/skill/generator.d.ts.map +1 -1
  28. package/dist/skill/generator.js +45 -3
  29. package/dist/skill/generator.js.map +1 -1
  30. package/dist/skill/installer.d.ts +26 -0
  31. package/dist/skill/installer.d.ts.map +1 -1
  32. package/dist/skill/installer.js +80 -4
  33. package/dist/skill/installer.js.map +1 -1
  34. package/dist/skill/upgrader.d.ts +2 -0
  35. package/dist/skill/upgrader.d.ts.map +1 -1
  36. package/dist/skill/upgrader.js +139 -1
  37. package/dist/skill/upgrader.js.map +1 -1
  38. package/dist/skill/validator.d.ts +3 -0
  39. package/dist/skill/validator.d.ts.map +1 -1
  40. package/dist/skill/validator.js +75 -0
  41. package/dist/skill/validator.js.map +1 -1
  42. package/dist/storage/sqlite.d.ts +28 -0
  43. package/dist/storage/sqlite.d.ts.map +1 -1
  44. package/dist/storage/sqlite.js +155 -16
  45. package/dist/storage/sqlite.js.map +1 -1
  46. package/dist/types.d.ts +10 -0
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/types.js +4 -0
  49. package/dist/types.js.map +1 -1
  50. package/dist/viewer/html.d.ts.map +1 -1
  51. package/dist/viewer/html.js +64 -24
  52. package/dist/viewer/html.js.map +1 -1
  53. package/dist/viewer/server.d.ts.map +1 -1
  54. package/dist/viewer/server.js +39 -20
  55. package/dist/viewer/server.js.map +1 -1
  56. package/index.ts +338 -33
  57. package/package.json +1 -1
  58. package/src/client/connector.ts +43 -8
  59. package/src/hub/server.ts +142 -31
  60. package/src/hub/user-manager.ts +42 -6
  61. package/src/ingest/chunker.ts +19 -13
  62. package/src/recall/engine.ts +7 -2
  63. package/src/sharing/types.ts +1 -1
  64. package/src/skill/evolver.ts +58 -6
  65. package/src/skill/generator.ts +44 -5
  66. package/src/skill/installer.ts +107 -4
  67. package/src/skill/upgrader.ts +139 -1
  68. package/src/skill/validator.ts +79 -0
  69. package/src/storage/sqlite.ts +174 -16
  70. package/src/types.ts +11 -0
  71. package/src/viewer/html.ts +64 -24
  72. package/src/viewer/server.ts +39 -20
@@ -148,6 +148,8 @@ class SqliteStore {
148
148
  this.migrateHubTables();
149
149
  this.migrateHubFtsToTrigram();
150
150
  this.migrateLocalSharedTasksOwner();
151
+ this.migrateHubUserIdentityFields();
152
+ this.migrateClientHubConnectionIdentityFields();
151
153
  this.log.debug("Database schema initialized");
152
154
  }
153
155
  migrateChunksIndexesForRecall() {
@@ -163,6 +165,51 @@ class SqliteStore {
163
165
  }
164
166
  catch { /* table may not exist yet */ }
165
167
  }
168
+ migrateHubUserIdentityFields() {
169
+ try {
170
+ const cols = this.db.prepare("PRAGMA table_info(hub_users)").all();
171
+ if (cols.length === 0)
172
+ return;
173
+ if (!cols.some(c => c.name === "identity_key")) {
174
+ this.db.exec("ALTER TABLE hub_users ADD COLUMN identity_key TEXT NOT NULL DEFAULT ''");
175
+ this.db.exec("CREATE INDEX IF NOT EXISTS idx_hub_users_identity_key ON hub_users(identity_key)");
176
+ this.log.info("Migrated: added identity_key to hub_users");
177
+ }
178
+ if (!cols.some(c => c.name === "left_at")) {
179
+ this.db.exec("ALTER TABLE hub_users ADD COLUMN left_at INTEGER");
180
+ this.log.info("Migrated: added left_at to hub_users");
181
+ }
182
+ if (!cols.some(c => c.name === "removed_at")) {
183
+ this.db.exec("ALTER TABLE hub_users ADD COLUMN removed_at INTEGER");
184
+ this.log.info("Migrated: added removed_at to hub_users");
185
+ }
186
+ if (!cols.some(c => c.name === "rejected_at")) {
187
+ this.db.exec("ALTER TABLE hub_users ADD COLUMN rejected_at INTEGER");
188
+ this.log.info("Migrated: added rejected_at to hub_users");
189
+ }
190
+ if (!cols.some(c => c.name === "rejoin_requested_at")) {
191
+ this.db.exec("ALTER TABLE hub_users ADD COLUMN rejoin_requested_at INTEGER");
192
+ this.log.info("Migrated: added rejoin_requested_at to hub_users");
193
+ }
194
+ }
195
+ catch { /* table may not exist yet */ }
196
+ }
197
+ migrateClientHubConnectionIdentityFields() {
198
+ try {
199
+ const cols = this.db.prepare("PRAGMA table_info(client_hub_connection)").all();
200
+ if (cols.length === 0)
201
+ return;
202
+ if (!cols.some(c => c.name === "identity_key")) {
203
+ this.db.exec("ALTER TABLE client_hub_connection ADD COLUMN identity_key TEXT NOT NULL DEFAULT ''");
204
+ this.log.info("Migrated: added identity_key to client_hub_connection");
205
+ }
206
+ if (!cols.some(c => c.name === "last_known_status")) {
207
+ this.db.exec("ALTER TABLE client_hub_connection ADD COLUMN last_known_status TEXT NOT NULL DEFAULT ''");
208
+ this.log.info("Migrated: added last_known_status to client_hub_connection");
209
+ }
210
+ }
211
+ catch { /* table may not exist yet */ }
212
+ }
166
213
  migrateOwnerFields() {
167
214
  const chunkCols = this.db.prepare("PRAGMA table_info(chunks)").all();
168
215
  if (!chunkCols.some((c) => c.name === "owner")) {
@@ -726,6 +773,20 @@ class SqliteStore {
726
773
  CREATE INDEX IF NOT EXISTS idx_hub_users_status ON hub_users(status);
727
774
  CREATE INDEX IF NOT EXISTS idx_hub_users_role ON hub_users(role);
728
775
 
776
+ CREATE TABLE IF NOT EXISTS hub_groups (
777
+ id TEXT PRIMARY KEY,
778
+ name TEXT NOT NULL,
779
+ description TEXT NOT NULL DEFAULT '',
780
+ created_at INTEGER NOT NULL
781
+ );
782
+
783
+ CREATE TABLE IF NOT EXISTS hub_group_members (
784
+ group_id TEXT NOT NULL REFERENCES hub_groups(id) ON DELETE CASCADE,
785
+ user_id TEXT NOT NULL REFERENCES hub_users(id) ON DELETE CASCADE,
786
+ joined_at INTEGER NOT NULL,
787
+ PRIMARY KEY (group_id, user_id)
788
+ );
789
+
729
790
  CREATE TABLE IF NOT EXISTS hub_tasks (
730
791
  id TEXT PRIMARY KEY,
731
792
  source_task_id TEXT NOT NULL,
@@ -1580,16 +1641,18 @@ class SqliteStore {
1580
1641
  // ─── Hub / Client connection ───
1581
1642
  setClientHubConnection(conn) {
1582
1643
  this.db.prepare(`
1583
- INSERT INTO client_hub_connection (id, hub_url, user_id, username, user_token, role, connected_at)
1584
- VALUES (1, ?, ?, ?, ?, ?, ?)
1644
+ INSERT INTO client_hub_connection (id, hub_url, user_id, username, user_token, role, connected_at, identity_key, last_known_status)
1645
+ VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?)
1585
1646
  ON CONFLICT(id) DO UPDATE SET
1586
1647
  hub_url = excluded.hub_url,
1587
1648
  user_id = excluded.user_id,
1588
1649
  username = excluded.username,
1589
1650
  user_token = excluded.user_token,
1590
1651
  role = excluded.role,
1591
- connected_at = excluded.connected_at
1592
- `).run(conn.hubUrl, conn.userId, conn.username, conn.userToken, conn.role, conn.connectedAt);
1652
+ connected_at = excluded.connected_at,
1653
+ identity_key = excluded.identity_key,
1654
+ last_known_status = excluded.last_known_status
1655
+ `).run(conn.hubUrl, conn.userId, conn.username, conn.userToken, conn.role, conn.connectedAt, conn.identityKey ?? "", conn.lastKnownStatus ?? "");
1593
1656
  }
1594
1657
  getClientHubConnection() {
1595
1658
  const row = this.db.prepare('SELECT * FROM client_hub_connection WHERE id = 1').get();
@@ -1682,8 +1745,8 @@ class SqliteStore {
1682
1745
  // ─── Hub Users / Groups ───
1683
1746
  upsertHubUser(user) {
1684
1747
  this.db.prepare(`
1685
- INSERT INTO hub_users (id, username, device_name, role, status, token_hash, created_at, approved_at)
1686
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
1748
+ INSERT INTO hub_users (id, username, device_name, role, status, token_hash, created_at, approved_at, identity_key, left_at, removed_at, rejected_at, rejoin_requested_at)
1749
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1687
1750
  ON CONFLICT(id) DO UPDATE SET
1688
1751
  username = excluded.username,
1689
1752
  device_name = excluded.device_name,
@@ -1691,20 +1754,31 @@ class SqliteStore {
1691
1754
  status = excluded.status,
1692
1755
  token_hash = excluded.token_hash,
1693
1756
  created_at = excluded.created_at,
1694
- approved_at = excluded.approved_at
1695
- `).run(user.id, user.username, user.deviceName ?? "", user.role, user.status, user.tokenHash, user.createdAt, user.approvedAt);
1757
+ approved_at = excluded.approved_at,
1758
+ identity_key = excluded.identity_key,
1759
+ left_at = excluded.left_at,
1760
+ removed_at = excluded.removed_at,
1761
+ rejected_at = excluded.rejected_at,
1762
+ rejoin_requested_at = excluded.rejoin_requested_at
1763
+ `).run(user.id, user.username, user.deviceName ?? "", user.role, user.status, user.tokenHash, user.createdAt, user.approvedAt, user.identityKey ?? "", user.leftAt ?? null, user.removedAt ?? null, user.rejectedAt ?? null, user.rejoinRequestedAt ?? null);
1696
1764
  }
1697
1765
  getHubUser(userId) {
1698
1766
  const row = this.db.prepare('SELECT * FROM hub_users WHERE id = ?').get(userId);
1699
1767
  if (!row)
1700
1768
  return null;
1701
- return rowToHubUser(row);
1769
+ const user = rowToHubUser(row);
1770
+ user.groups = this.getGroupsForHubUser(userId);
1771
+ return user;
1702
1772
  }
1703
1773
  listHubUsers(status) {
1704
1774
  const rows = status
1705
1775
  ? this.db.prepare('SELECT * FROM hub_users WHERE status = ? ORDER BY created_at').all(status)
1706
1776
  : this.db.prepare('SELECT * FROM hub_users ORDER BY created_at').all();
1707
- return rows.map(rowToHubUser);
1777
+ return rows.map(r => {
1778
+ const user = rowToHubUser(r);
1779
+ user.groups = this.getGroupsForHubUser(r.id);
1780
+ return user;
1781
+ });
1708
1782
  }
1709
1783
  deleteHubUser(userId, cleanResources = false) {
1710
1784
  if (cleanResources) {
@@ -1714,12 +1788,46 @@ class SqliteStore {
1714
1788
  const result = this.db.prepare('DELETE FROM hub_users WHERE id = ?').run(userId);
1715
1789
  return result.changes > 0;
1716
1790
  }
1717
- const result = this.db.prepare("UPDATE hub_users SET status = 'removed', token_hash = '' WHERE id = ?").run(userId);
1791
+ const result = this.db.prepare("UPDATE hub_users SET status = 'removed', token_hash = '', removed_at = ? WHERE id = ?").run(Date.now(), userId);
1792
+ return result.changes > 0;
1793
+ }
1794
+ findHubUserByIdentityKey(identityKey) {
1795
+ if (!identityKey)
1796
+ return null;
1797
+ const row = this.db.prepare('SELECT * FROM hub_users WHERE identity_key = ?').get(identityKey);
1798
+ return row ? rowToHubUser(row) : null;
1799
+ }
1800
+ markHubUserLeft(userId) {
1801
+ const result = this.db.prepare("UPDATE hub_users SET status = 'left', token_hash = '', left_at = ? WHERE id = ?").run(Date.now(), userId);
1718
1802
  return result.changes > 0;
1719
1803
  }
1720
1804
  updateHubUserActivity(userId, ip, timestamp) {
1721
1805
  this.db.prepare('UPDATE hub_users SET last_ip = ?, last_active_at = ? WHERE id = ?').run(ip, timestamp ?? Date.now(), userId);
1722
1806
  }
1807
+ // ─── Hub Groups ───
1808
+ upsertHubGroup(group) {
1809
+ this.db.prepare(`
1810
+ INSERT INTO hub_groups (id, name, description, created_at)
1811
+ VALUES (?, ?, ?, ?)
1812
+ ON CONFLICT(id) DO UPDATE SET name = excluded.name, description = excluded.description
1813
+ `).run(group.id, group.name, group.description ?? "", group.createdAt);
1814
+ }
1815
+ addHubGroupMember(groupId, userId, joinedAt) {
1816
+ this.db.prepare(`
1817
+ INSERT OR IGNORE INTO hub_group_members (group_id, user_id, joined_at)
1818
+ VALUES (?, ?, ?)
1819
+ `).run(groupId, userId, joinedAt);
1820
+ }
1821
+ removeHubGroupMember(groupId, userId) {
1822
+ this.db.prepare('DELETE FROM hub_group_members WHERE group_id = ? AND user_id = ?').run(groupId, userId);
1823
+ }
1824
+ getGroupsForHubUser(userId) {
1825
+ return this.db.prepare(`
1826
+ SELECT g.id, g.name, g.description FROM hub_groups g
1827
+ JOIN hub_group_members m ON m.group_id = g.id
1828
+ WHERE m.user_id = ?
1829
+ `).all(userId);
1830
+ }
1723
1831
  getHubUserContributions() {
1724
1832
  const result = {};
1725
1833
  const memRows = this.db.prepare('SELECT source_user_id, COUNT(*) as cnt FROM hub_memories GROUP BY source_user_id').all();
@@ -1836,20 +1944,36 @@ class SqliteStore {
1836
1944
  out.push(row.vector.readFloatLE(i * 4));
1837
1945
  return out;
1838
1946
  }
1947
+ getVisibleHubSkillEmbeddings() {
1948
+ const rows = this.db.prepare(`
1949
+ SELECT hse.skill_id, hse.vector, hse.dimensions
1950
+ FROM hub_skill_embeddings hse
1951
+ JOIN hub_skills hs ON hs.id = hse.skill_id
1952
+ `).all();
1953
+ return rows.map(r => ({
1954
+ skillId: r.skill_id,
1955
+ vector: new Float32Array(r.vector.buffer, r.vector.byteOffset, r.dimensions),
1956
+ }));
1957
+ }
1839
1958
  searchHubChunks(query, options) {
1840
1959
  const limit = options?.maxResults ?? 10;
1841
1960
  const userId = options?.userId ?? "";
1842
1961
  const rows = this.db.prepare(`
1843
- SELECT hc.id, hc.content, hc.summary, hc.role, hc.created_at, ht.title as task_title, ht.visibility, '' as group_name, hu.username as owner_name,
1962
+ SELECT hc.id, hc.content, hc.summary, hc.role, hc.created_at, ht.title as task_title, ht.visibility,
1963
+ COALESCE(hg.name, '') as group_name, hu.username as owner_name,
1844
1964
  bm25(hub_chunks_fts) as rank
1845
1965
  FROM hub_chunks_fts f
1846
1966
  JOIN hub_chunks hc ON hc.rowid = f.rowid
1847
1967
  JOIN hub_tasks ht ON ht.id = hc.hub_task_id
1848
1968
  LEFT JOIN hub_users hu ON hu.id = ht.source_user_id
1969
+ LEFT JOIN hub_groups hg ON hg.id = ht.group_id
1849
1970
  WHERE hub_chunks_fts MATCH ?
1971
+ AND (ht.visibility = 'public'
1972
+ OR ht.source_user_id = ?
1973
+ OR EXISTS (SELECT 1 FROM hub_group_members gm WHERE gm.group_id = ht.group_id AND gm.user_id = ?))
1850
1974
  ORDER BY rank
1851
1975
  LIMIT ?
1852
- `).all(sanitizeFtsQuery(query), limit);
1976
+ `).all(sanitizeFtsQuery(query), userId, userId, limit);
1853
1977
  return rows.map((row, idx) => ({ hit: row, rank: idx + 1 }));
1854
1978
  }
1855
1979
  upsertHubEmbedding(chunkId, vector) {
@@ -1872,7 +1996,10 @@ class SqliteStore {
1872
1996
  FROM hub_embeddings he
1873
1997
  JOIN hub_chunks hc ON hc.id = he.chunk_id
1874
1998
  JOIN hub_tasks ht ON ht.id = hc.hub_task_id
1875
- `).all();
1999
+ WHERE ht.visibility = 'public'
2000
+ OR ht.source_user_id = ?
2001
+ OR EXISTS (SELECT 1 FROM hub_group_members gm WHERE gm.group_id = ht.group_id AND gm.user_id = ?)
2002
+ `).all(userId, userId);
1876
2003
  return rows.map(r => ({
1877
2004
  chunkId: r.chunk_id,
1878
2005
  vector: new Float32Array(r.vector.buffer, r.vector.byteOffset, r.dimensions),
@@ -1880,14 +2007,19 @@ class SqliteStore {
1880
2007
  }
1881
2008
  getVisibleHubSearchHitByChunkId(chunkId, userId) {
1882
2009
  const row = this.db.prepare(`
1883
- SELECT hc.id, hc.content, hc.summary, hc.role, hc.created_at, ht.title as task_title, ht.visibility, '' as group_name, hu.username as owner_name,
2010
+ SELECT hc.id, hc.content, hc.summary, hc.role, hc.created_at, ht.title as task_title, ht.visibility,
2011
+ COALESCE(hg.name, '') as group_name, hu.username as owner_name,
1884
2012
  0 as rank
1885
2013
  FROM hub_chunks hc
1886
2014
  JOIN hub_tasks ht ON ht.id = hc.hub_task_id
1887
2015
  LEFT JOIN hub_users hu ON hu.id = ht.source_user_id
2016
+ LEFT JOIN hub_groups hg ON hg.id = ht.group_id
1888
2017
  WHERE hc.id = ?
2018
+ AND (ht.visibility = 'public'
2019
+ OR ht.source_user_id = ?
2020
+ OR EXISTS (SELECT 1 FROM hub_group_members gm WHERE gm.group_id = ht.group_id AND gm.user_id = ?))
1889
2021
  LIMIT 1
1890
- `).get(chunkId);
2022
+ `).get(chunkId, userId, userId);
1891
2023
  return row ?? null;
1892
2024
  }
1893
2025
  getHubChunkById(chunkId) {
@@ -2276,6 +2408,8 @@ function rowToClientHubConnection(row) {
2276
2408
  userToken: row.user_token,
2277
2409
  role: row.role,
2278
2410
  connectedAt: row.connected_at,
2411
+ identityKey: row.identity_key || "",
2412
+ lastKnownStatus: row.last_known_status || "",
2279
2413
  };
2280
2414
  }
2281
2415
  function rowToHubUser(row) {
@@ -2291,6 +2425,11 @@ function rowToHubUser(row) {
2291
2425
  approvedAt: row.approved_at,
2292
2426
  lastIp: row.last_ip || "",
2293
2427
  lastActiveAt: row.last_active_at ?? null,
2428
+ identityKey: row.identity_key || "",
2429
+ leftAt: row.left_at ?? null,
2430
+ removedAt: row.removed_at ?? null,
2431
+ rejectedAt: row.rejected_at ?? null,
2432
+ rejoinRequestedAt: row.rejoin_requested_at ?? null,
2294
2433
  };
2295
2434
  }
2296
2435
  function rowToHubTask(row) {