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

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 (99) hide show
  1. package/.env.example +7 -0
  2. package/README.md +94 -27
  3. package/dist/capture/index.js +3 -1
  4. package/dist/capture/index.js.map +1 -1
  5. package/dist/client/connector.d.ts +5 -0
  6. package/dist/client/connector.d.ts.map +1 -1
  7. package/dist/client/connector.js +132 -10
  8. package/dist/client/connector.js.map +1 -1
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js +2 -1
  11. package/dist/config.js.map +1 -1
  12. package/dist/hub/server.d.ts +2 -0
  13. package/dist/hub/server.d.ts.map +1 -1
  14. package/dist/hub/server.js +251 -38
  15. package/dist/hub/server.js.map +1 -1
  16. package/dist/hub/user-manager.d.ts +9 -0
  17. package/dist/hub/user-manager.d.ts.map +1 -1
  18. package/dist/hub/user-manager.js +26 -2
  19. package/dist/hub/user-manager.js.map +1 -1
  20. package/dist/ingest/chunker.d.ts +2 -1
  21. package/dist/ingest/chunker.d.ts.map +1 -1
  22. package/dist/ingest/chunker.js +14 -10
  23. package/dist/ingest/chunker.js.map +1 -1
  24. package/dist/ingest/providers/index.js +2 -2
  25. package/dist/ingest/providers/index.js.map +1 -1
  26. package/dist/recall/engine.d.ts.map +1 -1
  27. package/dist/recall/engine.js +96 -1
  28. package/dist/recall/engine.js.map +1 -1
  29. package/dist/shared/llm-call.d.ts.map +1 -1
  30. package/dist/shared/llm-call.js +2 -1
  31. package/dist/shared/llm-call.js.map +1 -1
  32. package/dist/sharing/types.d.ts +1 -1
  33. package/dist/sharing/types.d.ts.map +1 -1
  34. package/dist/skill/evolver.d.ts +2 -0
  35. package/dist/skill/evolver.d.ts.map +1 -1
  36. package/dist/skill/evolver.js +56 -5
  37. package/dist/skill/evolver.js.map +1 -1
  38. package/dist/skill/generator.d.ts +2 -0
  39. package/dist/skill/generator.d.ts.map +1 -1
  40. package/dist/skill/generator.js +45 -3
  41. package/dist/skill/generator.js.map +1 -1
  42. package/dist/skill/installer.d.ts +26 -0
  43. package/dist/skill/installer.d.ts.map +1 -1
  44. package/dist/skill/installer.js +80 -4
  45. package/dist/skill/installer.js.map +1 -1
  46. package/dist/skill/upgrader.d.ts +2 -0
  47. package/dist/skill/upgrader.d.ts.map +1 -1
  48. package/dist/skill/upgrader.js +139 -1
  49. package/dist/skill/upgrader.js.map +1 -1
  50. package/dist/skill/validator.d.ts +3 -0
  51. package/dist/skill/validator.d.ts.map +1 -1
  52. package/dist/skill/validator.js +75 -0
  53. package/dist/skill/validator.js.map +1 -1
  54. package/dist/storage/sqlite.d.ts +58 -0
  55. package/dist/storage/sqlite.d.ts.map +1 -1
  56. package/dist/storage/sqlite.js +295 -35
  57. package/dist/storage/sqlite.js.map +1 -1
  58. package/dist/telemetry.d.ts.map +1 -1
  59. package/dist/telemetry.js +27 -8
  60. package/dist/telemetry.js.map +1 -1
  61. package/dist/types.d.ts +10 -0
  62. package/dist/types.d.ts.map +1 -1
  63. package/dist/types.js +4 -0
  64. package/dist/types.js.map +1 -1
  65. package/dist/viewer/html.d.ts.map +1 -1
  66. package/dist/viewer/html.js +796 -289
  67. package/dist/viewer/html.js.map +1 -1
  68. package/dist/viewer/server.d.ts +11 -0
  69. package/dist/viewer/server.d.ts.map +1 -1
  70. package/dist/viewer/server.js +456 -92
  71. package/dist/viewer/server.js.map +1 -1
  72. package/index.ts +411 -52
  73. package/openclaw.plugin.json +1 -1
  74. package/package.json +2 -1
  75. package/prebuilds/darwin-arm64/better_sqlite3.node +0 -0
  76. package/prebuilds/darwin-x64/better_sqlite3.node +0 -0
  77. package/prebuilds/linux-x64/better_sqlite3.node +0 -0
  78. package/prebuilds/win32-x64/better_sqlite3.node +0 -0
  79. package/src/capture/index.ts +4 -1
  80. package/src/client/connector.ts +136 -10
  81. package/src/config.ts +2 -1
  82. package/src/hub/server.ts +246 -38
  83. package/src/hub/user-manager.ts +42 -6
  84. package/src/ingest/chunker.ts +19 -13
  85. package/src/ingest/providers/index.ts +2 -2
  86. package/src/recall/engine.ts +89 -1
  87. package/src/shared/llm-call.ts +2 -1
  88. package/src/sharing/types.ts +1 -1
  89. package/src/skill/evolver.ts +58 -6
  90. package/src/skill/generator.ts +44 -5
  91. package/src/skill/installer.ts +107 -4
  92. package/src/skill/upgrader.ts +139 -1
  93. package/src/skill/validator.ts +79 -0
  94. package/src/storage/sqlite.ts +326 -40
  95. package/src/telemetry.ts +27 -9
  96. package/src/types.ts +11 -0
  97. package/src/viewer/html.ts +796 -289
  98. package/src/viewer/server.ts +430 -89
  99. package/telemetry.credentials.json +5 -0
@@ -167,8 +167,11 @@ export function stripInboundMetadata(text: string): string {
167
167
  /** Strip <think…>…</think> blocks emitted by DeepSeek-style reasoning models. */
168
168
  const THINKING_TAG_RE = /<think[\s>][\s\S]*?<\/think>\s*/gi;
169
169
 
170
+ /** Unwrap <final>…</final> tags from MiniMax-style models (keep content, strip tags). */
171
+ const FINAL_TAG_RE = /<\/?final\s*>/gi;
172
+
170
173
  function stripThinkingTags(text: string): string {
171
- return text.replace(THINKING_TAG_RE, "");
174
+ return text.replace(THINKING_TAG_RE, "").replace(FINAL_TAG_RE, "").trim();
172
175
  }
173
176
 
174
177
  function extractEnvelopeTimestamp(text: string): number | null {
@@ -10,6 +10,7 @@ export interface HubSessionInfo {
10
10
  userToken: string;
11
11
  role: UserRole;
12
12
  connectedAt: number;
13
+ identityKey?: string;
13
14
  }
14
15
 
15
16
  export interface HubStatusInfo {
@@ -20,6 +21,7 @@ export interface HubStatusInfo {
20
21
  username: string;
21
22
  role: UserRole;
22
23
  status: UserStatus | string;
24
+ groups?: Array<{ id: string; name: string }>;
23
25
  };
24
26
  }
25
27
 
@@ -34,6 +36,49 @@ export async function connectToHub(store: SqliteStore, config: MemosLocalConfig,
34
36
 
35
37
  if (!userToken && config.sharing?.client?.teamToken) {
36
38
  if (!log) throw new Error("hub client connection is not configured (no userToken, has teamToken but no logger for auto-join)");
39
+
40
+ // If DB has a pending connection (userId exists, no token), check registration-status first
41
+ const persisted = store.getClientHubConnection();
42
+ if (persisted?.userId && !persisted.userToken && hubAddress) {
43
+ const hubUrl = normalizeHubUrl(hubAddress);
44
+ const teamToken = config.sharing.client!.teamToken!;
45
+ try {
46
+ const result = await hubRequestJson(hubUrl, "", "/api/v1/hub/registration-status", {
47
+ method: "POST",
48
+ body: JSON.stringify({ teamToken, userId: persisted.userId }),
49
+ }) as any;
50
+ if (result.status === "active" && result.userToken) {
51
+ log.info(`Pending user approved! Connecting with token. userId=${persisted.userId}`);
52
+ store.setClientHubConnection({
53
+ hubUrl,
54
+ userId: persisted.userId,
55
+ username: persisted.username || "",
56
+ userToken: result.userToken,
57
+ role: "member",
58
+ connectedAt: Date.now(),
59
+ identityKey: persisted.identityKey || "",
60
+ lastKnownStatus: "active",
61
+ });
62
+ return store.getClientHubConnection()!;
63
+ }
64
+ if (result.status === "pending") {
65
+ throw new PendingApprovalError(persisted.userId);
66
+ }
67
+ if (result.status === "rejected") {
68
+ throw new Error("Join request was rejected by the Hub admin.");
69
+ }
70
+ if (result.status === "blocked") {
71
+ throw new Error("Your account has been blocked by the Hub admin.");
72
+ }
73
+ if (result.status === "left" || result.status === "removed") {
74
+ log.info(`User status is "${result.status}", will try to rejoin.`);
75
+ }
76
+ } catch (err) {
77
+ if (err instanceof PendingApprovalError) throw err;
78
+ log.warn(`registration-status check failed, falling back to autoJoinHub: ${err}`);
79
+ }
80
+ }
81
+
37
82
  return autoJoinHub(store, config, log);
38
83
  }
39
84
 
@@ -43,6 +88,7 @@ export async function connectToHub(store: SqliteStore, config: MemosLocalConfig,
43
88
 
44
89
  const hubUrl = normalizeHubUrl(hubAddress);
45
90
  const me = await hubRequestJson(hubUrl, userToken, "/api/v1/hub/me", { method: "GET" }) as any;
91
+ const persisted = store.getClientHubConnection();
46
92
  store.setClientHubConnection({
47
93
  hubUrl,
48
94
  userId: String(me.id),
@@ -50,22 +96,35 @@ export async function connectToHub(store: SqliteStore, config: MemosLocalConfig,
50
96
  userToken,
51
97
  role: String(me.role ?? "member") as UserRole,
52
98
  connectedAt: Date.now(),
99
+ identityKey: persisted?.identityKey || String(me.identityKey ?? ""),
100
+ lastKnownStatus: "active",
53
101
  });
54
102
  return store.getClientHubConnection()!;
55
103
  }
56
104
 
57
105
  export async function getHubStatus(store: SqliteStore, config: MemosLocalConfig): Promise<HubStatusInfo> {
58
106
  const conn = store.getClientHubConnection();
59
- const hubAddress = conn?.hubUrl || config.sharing?.client?.hubAddress || "";
107
+ const configHubAddress = config.sharing?.client?.hubAddress || "";
108
+ const hubAddress = conn?.hubUrl || (configHubAddress ? normalizeHubUrl(configHubAddress) : "");
60
109
  const userToken = conn?.userToken || config.sharing?.client?.userToken || "";
61
110
 
111
+ if (conn && configHubAddress && conn.hubUrl && normalizeHubUrl(configHubAddress) !== conn.hubUrl) {
112
+ store.setClientHubConnection({
113
+ ...conn,
114
+ hubUrl: normalizeHubUrl(configHubAddress),
115
+ userToken: "",
116
+ lastKnownStatus: "hub_changed",
117
+ });
118
+ return { connected: false, user: null };
119
+ }
120
+
62
121
  if (conn && conn.userId && (!userToken || userToken === "")) {
63
122
  const teamToken = config.sharing?.client?.teamToken ?? "";
64
123
  if (hubAddress && teamToken) {
65
124
  try {
66
- const result = await hubRequestJson(normalizeHubUrl(hubAddress), "", "/api/v1/hub/join", {
125
+ const result = await hubRequestJson(normalizeHubUrl(hubAddress), "", "/api/v1/hub/registration-status", {
67
126
  method: "POST",
68
- body: JSON.stringify({ teamToken, username: config.sharing?.client?.nickname || conn.username || "user" }),
127
+ body: JSON.stringify({ teamToken, userId: conn.userId }),
69
128
  }) as any;
70
129
  if (result.status === "pending") {
71
130
  return {
@@ -82,11 +141,13 @@ export async function getHubStatus(store: SqliteStore, config: MemosLocalConfig)
82
141
  if (result.status === "active" && result.userToken) {
83
142
  store.setClientHubConnection({
84
143
  hubUrl: normalizeHubUrl(hubAddress),
85
- userId: String(result.userId),
144
+ userId: conn.userId,
86
145
  username: conn.username || "",
87
146
  userToken: result.userToken,
88
147
  role: "member",
89
148
  connectedAt: Date.now(),
149
+ identityKey: conn.identityKey || "",
150
+ lastKnownStatus: "active",
90
151
  });
91
152
  const me = await hubRequestJson(normalizeHubUrl(hubAddress), result.userToken, "/api/v1/hub/me", { method: "GET" }) as any;
92
153
  return {
@@ -127,12 +188,10 @@ export async function getHubStatus(store: SqliteStore, config: MemosLocalConfig)
127
188
  const latestRole = String(me.role ?? "member") as UserRole;
128
189
  if (conn && (conn.username !== latestUsername || conn.role !== latestRole)) {
129
190
  store.setClientHubConnection({
130
- hubUrl: conn.hubUrl,
131
- userId: conn.userId,
191
+ ...conn,
132
192
  username: latestUsername,
133
- userToken: conn.userToken,
134
193
  role: latestRole,
135
- connectedAt: conn.connectedAt,
194
+ lastKnownStatus: "active",
136
195
  });
137
196
  }
138
197
  return {
@@ -143,9 +202,63 @@ export async function getHubStatus(store: SqliteStore, config: MemosLocalConfig)
143
202
  username: latestUsername,
144
203
  role: latestRole,
145
204
  status: String(me.status ?? "active"),
205
+ groups: Array.isArray(me.groups) ? me.groups : [],
146
206
  },
147
207
  };
148
- } catch {
208
+ } catch (err: any) {
209
+ const is401 = typeof err?.message === "string" && err.message.includes("(401)");
210
+ if (is401 && conn) {
211
+ const teamToken = config.sharing?.client?.teamToken ?? "";
212
+ if (hubAddress && teamToken) {
213
+ try {
214
+ const regResult = await hubRequestJson(normalizeHubUrl(hubAddress), "", "/api/v1/hub/registration-status", {
215
+ method: "POST",
216
+ body: JSON.stringify({ teamToken, userId: conn.userId }),
217
+ }) as any;
218
+ if (regResult.status === "active" && regResult.userToken) {
219
+ store.setClientHubConnection({
220
+ ...conn,
221
+ hubUrl: normalizeHubUrl(hubAddress),
222
+ userToken: regResult.userToken,
223
+ connectedAt: Date.now(),
224
+ lastKnownStatus: "active",
225
+ });
226
+ try {
227
+ const me = await hubRequestJson(normalizeHubUrl(hubAddress), regResult.userToken, "/api/v1/hub/me", { method: "GET" }) as any;
228
+ return {
229
+ connected: true,
230
+ hubUrl: normalizeHubUrl(hubAddress),
231
+ user: {
232
+ id: String(me.id),
233
+ username: String(me.username ?? ""),
234
+ role: String(me.role ?? "member") as UserRole,
235
+ status: String(me.status ?? "active"),
236
+ groups: Array.isArray(me.groups) ? me.groups : [],
237
+ },
238
+ };
239
+ } catch { /* fall through to token-only return */ }
240
+ return {
241
+ connected: true,
242
+ hubUrl: normalizeHubUrl(hubAddress),
243
+ user: { id: conn.userId, username: conn.username || "", role: conn.role as UserRole || "member", status: "active" },
244
+ };
245
+ }
246
+ const realStatus = regResult.status as string;
247
+ store.setClientHubConnection({ ...conn, userToken: "", lastKnownStatus: realStatus });
248
+ return {
249
+ connected: false,
250
+ hubUrl: normalizeHubUrl(hubAddress),
251
+ user: { id: conn.userId, username: conn.username || "", role: "member", status: realStatus },
252
+ };
253
+ } catch { /* registration-status also failed, fall through */ }
254
+ }
255
+ store.setClientHubConnection({ ...conn, userToken: "", lastKnownStatus: "token_expired" });
256
+ return {
257
+ connected: false,
258
+ hubUrl: normalizeHubUrl(hubAddress),
259
+ user: { id: conn.userId, username: conn.username || "", role: "member", status: "token_expired" },
260
+ };
261
+ }
149
262
  return { connected: false, user: null };
150
263
  }
151
264
  }
@@ -176,12 +289,17 @@ export async function autoJoinHub(
176
289
  }
177
290
  }
178
291
 
292
+ const persisted = store.getClientHubConnection();
293
+ const existingIdentityKey = persisted?.identityKey || "";
294
+
179
295
  log.info(`Joining Hub at ${hubUrl} as "${username}"...`);
180
296
  const result = await hubRequestJson(hubUrl, "", "/api/v1/hub/join", {
181
297
  method: "POST",
182
- body: JSON.stringify({ teamToken, username, deviceName: hostname, clientIp }),
298
+ body: JSON.stringify({ teamToken, username, deviceName: hostname, clientIp, identityKey: existingIdentityKey }),
183
299
  }) as any;
184
300
 
301
+ const returnedIdentityKey = String(result.identityKey || existingIdentityKey || "");
302
+
185
303
  if (result.status === "pending") {
186
304
  log.info(`Join request submitted, awaiting admin approval. userId=${result.userId}`);
187
305
  store.setClientHubConnection({
@@ -191,6 +309,8 @@ export async function autoJoinHub(
191
309
  userToken: "",
192
310
  role: "member",
193
311
  connectedAt: Date.now(),
312
+ identityKey: returnedIdentityKey,
313
+ lastKnownStatus: "pending",
194
314
  });
195
315
  throw new PendingApprovalError(result.userId);
196
316
  }
@@ -199,6 +319,10 @@ export async function autoJoinHub(
199
319
  throw new Error(`Join request was rejected by the Hub admin.`);
200
320
  }
201
321
 
322
+ if (result.status === "blocked") {
323
+ throw new Error(`Your account has been blocked by the Hub admin.`);
324
+ }
325
+
202
326
  if (!result.userToken) {
203
327
  throw new Error(`Hub join failed: ${JSON.stringify(result)}`);
204
328
  }
@@ -211,6 +335,8 @@ export async function autoJoinHub(
211
335
  userToken: result.userToken,
212
336
  role: "member",
213
337
  connectedAt: Date.now(),
338
+ identityKey: returnedIdentityKey,
339
+ lastKnownStatus: "active",
214
340
  });
215
341
  return store.getClientHubConnection()!;
216
342
  }
package/src/config.ts CHANGED
@@ -128,7 +128,8 @@ export function resolveConfig(raw: Partial<MemosLocalConfig> | undefined, stateD
128
128
  userToken: cfg.sharing?.client?.userToken ?? "",
129
129
  teamToken: cfg.sharing?.client?.teamToken ?? "",
130
130
  pendingUserId: cfg.sharing?.client?.pendingUserId ?? "",
131
- } : { hubAddress: "", userToken: "", teamToken: "", pendingUserId: "" };
131
+ nickname: cfg.sharing?.client?.nickname ?? "",
132
+ } : { hubAddress: "", userToken: "", teamToken: "", pendingUserId: "", nickname: "" };
132
133
  return { enabled, role, hub, client, capabilities: sharingCapabilities };
133
134
  })(),
134
135
  };