@memtensor/memos-local-openclaw-plugin 1.0.4-beta.17 → 1.0.4-beta.19
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.
- package/dist/capture/index.js +3 -1
- package/dist/capture/index.js.map +1 -1
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/server.js +8 -0
- package/dist/hub/server.js.map +1 -1
- package/dist/storage/sqlite.d.ts +13 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +41 -0
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/viewer/html.js +2 -2
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +33 -4
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +4 -2
- package/package.json +1 -1
- package/src/capture/index.ts +4 -1
- package/src/hub/server.ts +8 -0
- package/src/storage/sqlite.ts +49 -0
- package/src/viewer/html.ts +2 -2
- package/src/viewer/server.ts +30 -4
package/index.ts
CHANGED
|
@@ -388,8 +388,7 @@ const memosLocalPlugin = {
|
|
|
388
388
|
|
|
389
389
|
const memoryId = response?.memoryId ?? `${chunk.id}-hub`;
|
|
390
390
|
|
|
391
|
-
//
|
|
392
|
-
// Client mode relies on the remote Hub for storage and search.
|
|
391
|
+
// Hub role: full hub_memories row for local recall/embeddings. Client: metadata only (team_shared_chunks) for UI.
|
|
393
392
|
if (ctx.config.sharing?.role === "hub") {
|
|
394
393
|
const now = Date.now();
|
|
395
394
|
const existing = store.getHubMemoryBySource(hubClient.userId, chunk.id);
|
|
@@ -406,6 +405,8 @@ const memosLocalPlugin = {
|
|
|
406
405
|
createdAt: existing?.createdAt ?? now,
|
|
407
406
|
updatedAt: now,
|
|
408
407
|
});
|
|
408
|
+
} else if (ctx.config.sharing?.enabled && hubClient.userId) {
|
|
409
|
+
store.upsertTeamSharedChunk(chunk.id, { hubMemoryId: memoryId, visibility, groupId });
|
|
409
410
|
}
|
|
410
411
|
|
|
411
412
|
return { memoryId, visibility, groupId };
|
|
@@ -425,6 +426,7 @@ const memosLocalPlugin = {
|
|
|
425
426
|
body: JSON.stringify({ sourceChunkId: chunk.id }),
|
|
426
427
|
});
|
|
427
428
|
store.deleteHubMemoryBySource(hubClient.userId, chunk.id);
|
|
429
|
+
store.deleteTeamSharedChunk(chunk.id);
|
|
428
430
|
};
|
|
429
431
|
|
|
430
432
|
// ─── Tool: memory_search ───
|
package/package.json
CHANGED
package/src/capture/index.ts
CHANGED
|
@@ -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 {
|
package/src/hub/server.ts
CHANGED
|
@@ -414,6 +414,10 @@ export class HubServer {
|
|
|
414
414
|
ttlMs,
|
|
415
415
|
);
|
|
416
416
|
this.userManager.approveUser(updated.id, newToken);
|
|
417
|
+
if (updated.id === this.authState.bootstrapAdminUserId) {
|
|
418
|
+
this.authState.bootstrapAdminToken = newToken;
|
|
419
|
+
this.saveAuthState();
|
|
420
|
+
}
|
|
417
421
|
this.opts.log.info(`Hub: user "${auth.userId}" renamed to "${newUsername}"`);
|
|
418
422
|
return this.json(res, 200, { ok: true, username: newUsername, userToken: newToken });
|
|
419
423
|
}
|
|
@@ -522,6 +526,10 @@ export class HubServer {
|
|
|
522
526
|
const updated = this.opts.store.getHubUser(userId)!;
|
|
523
527
|
const finalUser = { ...updated, username: newUsername };
|
|
524
528
|
this.opts.store.upsertHubUser(finalUser);
|
|
529
|
+
if (userId === this.authState.bootstrapAdminUserId) {
|
|
530
|
+
this.authState.bootstrapAdminToken = newToken;
|
|
531
|
+
this.saveAuthState();
|
|
532
|
+
}
|
|
525
533
|
this.opts.log.info(`Hub: admin "${auth.userId}" renamed user "${userId}" to "${newUsername}"`);
|
|
526
534
|
return this.json(res, 200, { ok: true, username: newUsername });
|
|
527
535
|
}
|
package/src/storage/sqlite.ts
CHANGED
|
@@ -792,6 +792,15 @@ export class SqliteStore {
|
|
|
792
792
|
shared_at INTEGER NOT NULL
|
|
793
793
|
);
|
|
794
794
|
|
|
795
|
+
-- Client: team share UI metadata only (no hub_memories row — avoids local FTS/embed recall duplication)
|
|
796
|
+
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
|
|
802
|
+
);
|
|
803
|
+
|
|
795
804
|
CREATE TABLE IF NOT EXISTS hub_users (
|
|
796
805
|
id TEXT PRIMARY KEY,
|
|
797
806
|
username TEXT NOT NULL UNIQUE,
|
|
@@ -1369,6 +1378,7 @@ export class SqliteStore {
|
|
|
1369
1378
|
"skill_versions",
|
|
1370
1379
|
"skills",
|
|
1371
1380
|
"local_shared_memories",
|
|
1381
|
+
"team_shared_chunks",
|
|
1372
1382
|
"local_shared_tasks",
|
|
1373
1383
|
"embeddings",
|
|
1374
1384
|
"chunks",
|
|
@@ -2355,6 +2365,45 @@ export class SqliteStore {
|
|
|
2355
2365
|
return info.changes > 0;
|
|
2356
2366
|
}
|
|
2357
2367
|
|
|
2368
|
+
// ─── Team share metadata (Client role — UI only, not used for local recall / FTS) ───
|
|
2369
|
+
|
|
2370
|
+
upsertTeamSharedChunk(
|
|
2371
|
+
chunkId: string,
|
|
2372
|
+
row: { hubMemoryId?: string; visibility?: string; groupId?: string | null },
|
|
2373
|
+
): void {
|
|
2374
|
+
const now = Date.now();
|
|
2375
|
+
const vis = row.visibility === "group" ? "group" : "public";
|
|
2376
|
+
const gid = vis === "group" ? (row.groupId ?? null) : null;
|
|
2377
|
+
this.db.prepare(`
|
|
2378
|
+
INSERT INTO team_shared_chunks (chunk_id, hub_memory_id, visibility, group_id, shared_at)
|
|
2379
|
+
VALUES (?, ?, ?, ?, ?)
|
|
2380
|
+
ON CONFLICT(chunk_id) DO UPDATE SET
|
|
2381
|
+
hub_memory_id = excluded.hub_memory_id,
|
|
2382
|
+
visibility = excluded.visibility,
|
|
2383
|
+
group_id = excluded.group_id,
|
|
2384
|
+
shared_at = excluded.shared_at
|
|
2385
|
+
`).run(chunkId, row.hubMemoryId ?? "", vis, gid, now);
|
|
2386
|
+
}
|
|
2387
|
+
|
|
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;
|
|
2391
|
+
} | undefined;
|
|
2392
|
+
if (!r) return null;
|
|
2393
|
+
return {
|
|
2394
|
+
chunkId: r.chunk_id,
|
|
2395
|
+
hubMemoryId: r.hub_memory_id,
|
|
2396
|
+
visibility: r.visibility,
|
|
2397
|
+
groupId: r.group_id,
|
|
2398
|
+
sharedAt: r.shared_at,
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
deleteTeamSharedChunk(chunkId: string): boolean {
|
|
2403
|
+
const info = this.db.prepare("DELETE FROM team_shared_chunks WHERE chunk_id = ?").run(chunkId);
|
|
2404
|
+
return info.changes > 0;
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2358
2407
|
// ─── Hub Notifications ───
|
|
2359
2408
|
|
|
2360
2409
|
insertHubNotification(n: { id: string; userId: string; type: string; resource: string; title: string; message?: string }): void {
|
package/src/viewer/html.ts
CHANGED
|
@@ -287,7 +287,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
287
287
|
.admin-card-tag.tag-version{background:rgba(139,92,246,.1);color:#8b5cf6}
|
|
288
288
|
.admin-card-tag.tag-visibility{background:rgba(99,102,241,.08);color:var(--pri)}
|
|
289
289
|
.admin-card-tag.tag-group{background:rgba(139,92,246,.08);color:#8b5cf6}
|
|
290
|
-
.admin-card-preview{font-size:12px;color:var(--text-sec);line-height:1.5;margin:8px 0;padding:10px 12px;background:rgba(99,102,241,.02);border-radius:10px;border:1px solid rgba(99,102,241,.08);max-height:120px;overflow:hidden;white-space:pre-wrap;word-break:break-all;position:relative;-webkit-mask-image:linear-gradient(to bottom,#000
|
|
290
|
+
.admin-card-preview{font-size:12px;color:var(--text-sec);line-height:1.5;margin:8px 0;padding:10px 12px;background:rgba(99,102,241,.02);border-radius:10px;border:1px solid rgba(99,102,241,.08);max-height:120px;overflow:hidden;white-space:pre-wrap;word-break:break-all;position:relative;-webkit-mask-image:linear-gradient(to bottom,#000 88%,transparent 100%);mask-image:linear-gradient(to bottom,#000 88%,transparent 100%)}
|
|
291
291
|
.admin-card-actions{display:inline-flex;gap:6px;margin-left:auto;align-items:center;flex-shrink:0}
|
|
292
292
|
.admin-card-time{font-size:11px;color:var(--text-muted)}
|
|
293
293
|
.admin-card-detail{display:none;margin-top:0;padding:20px 24px 24px;border-top:1px dashed rgba(99,102,241,.12);background:linear-gradient(180deg,rgba(99,102,241,.02) 0%,transparent 60%);animation:adminDetailIn .25s ease}
|
|
@@ -322,7 +322,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
322
322
|
.adm-msg-side.assistant .adm-msg-role{color:var(--green)}
|
|
323
323
|
.adm-msg-time{font-size:9px;color:var(--text-muted)}
|
|
324
324
|
.adm-msg-body{flex:1;min-width:0;padding:12px 16px;font-size:13px;line-height:1.75;color:var(--text);white-space:pre-wrap;word-break:break-word}
|
|
325
|
-
.adm-msg-body.collapsed{max-height:120px;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000
|
|
325
|
+
.adm-msg-body.collapsed{max-height:120px;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000 88%,transparent);mask-image:linear-gradient(180deg,#000 88%,transparent)}
|
|
326
326
|
.adm-msg-toggle{display:none;padding:0 16px 8px;font-size:11px;color:var(--pri);cursor:pointer;transition:color .15s}
|
|
327
327
|
.adm-msg-toggle:hover{color:var(--pri-dark)}
|
|
328
328
|
.admin-card-expand-btn{font-size:12px;color:var(--pri);cursor:pointer;background:none;border:none;padding:2px 6px;font-family:inherit}
|
package/src/viewer/server.ts
CHANGED
|
@@ -492,6 +492,12 @@ export class ViewerServer {
|
|
|
492
492
|
const placeholders = chunkIds.map(() => "?").join(",");
|
|
493
493
|
const sharedRows = db.prepare(`SELECT source_chunk_id, visibility, group_id FROM hub_memories WHERE source_chunk_id IN (${placeholders})`).all(...chunkIds) as Array<{ source_chunk_id: string; visibility: string; group_id: string | null }>;
|
|
494
494
|
for (const r of sharedRows) sharingMap.set(r.source_chunk_id, r);
|
|
495
|
+
const teamMetaRows = db.prepare(`SELECT chunk_id, visibility, group_id FROM team_shared_chunks WHERE chunk_id IN (${placeholders})`).all(...chunkIds) as Array<{ chunk_id: string; visibility: string; group_id: string | null }>;
|
|
496
|
+
for (const r of teamMetaRows) {
|
|
497
|
+
if (!sharingMap.has(r.chunk_id)) {
|
|
498
|
+
sharingMap.set(r.chunk_id, { visibility: r.visibility, group_id: r.group_id });
|
|
499
|
+
}
|
|
500
|
+
}
|
|
495
501
|
const localRows = db.prepare(`SELECT chunk_id, original_owner, shared_at FROM local_shared_memories WHERE chunk_id IN (${placeholders})`).all(...chunkIds) as Array<{ chunk_id: string; original_owner: string; shared_at: number }>;
|
|
496
502
|
for (const r of localRows) localShareMap.set(r.chunk_id, r);
|
|
497
503
|
} catch {
|
|
@@ -1252,15 +1258,19 @@ export class ViewerServer {
|
|
|
1252
1258
|
body: JSON.stringify({ memory: { sourceChunkId: refreshedChunk.id, role: refreshedChunk.role, content: refreshedChunk.content, summary: refreshedChunk.summary, kind: refreshedChunk.kind, groupId: null, visibility: "public" } }),
|
|
1253
1259
|
});
|
|
1254
1260
|
if (!isLocalShared) this.store.markMemorySharedLocally(chunkId);
|
|
1255
|
-
|
|
1261
|
+
const memoryId = String((response as any)?.memoryId ?? "");
|
|
1262
|
+
const isHubRole = this.ctx?.config?.sharing?.role === "hub";
|
|
1263
|
+
if (hubClient.userId && isHubRole) {
|
|
1256
1264
|
const existing = this.store.getHubMemoryBySource(hubClient.userId, chunkId);
|
|
1257
1265
|
this.store.upsertHubMemory({
|
|
1258
|
-
id:
|
|
1266
|
+
id: memoryId || existing?.id || crypto.randomUUID(),
|
|
1259
1267
|
sourceChunkId: chunkId, sourceUserId: hubClient.userId,
|
|
1260
1268
|
role: refreshedChunk.role, content: refreshedChunk.content, summary: refreshedChunk.summary ?? "",
|
|
1261
1269
|
kind: refreshedChunk.kind, groupId: null, visibility: "public",
|
|
1262
1270
|
createdAt: existing?.createdAt ?? Date.now(), updatedAt: Date.now(),
|
|
1263
1271
|
});
|
|
1272
|
+
} else if (hubClient.userId) {
|
|
1273
|
+
this.store.upsertTeamSharedChunk(chunkId, { hubMemoryId: memoryId, visibility: "public", groupId: null });
|
|
1264
1274
|
}
|
|
1265
1275
|
hubSynced = true;
|
|
1266
1276
|
} else {
|
|
@@ -1274,6 +1284,7 @@ export class ViewerServer {
|
|
|
1274
1284
|
method: "POST", body: JSON.stringify({ sourceChunkId: chunkId }),
|
|
1275
1285
|
});
|
|
1276
1286
|
if (hubClient.userId) this.store.deleteHubMemoryBySource(hubClient.userId, chunkId);
|
|
1287
|
+
this.store.deleteTeamSharedChunk(chunkId);
|
|
1277
1288
|
hubSynced = true;
|
|
1278
1289
|
} catch (err) { this.log.warn(`Failed to unshare memory from team: ${err}`); }
|
|
1279
1290
|
}
|
|
@@ -1286,6 +1297,7 @@ export class ViewerServer {
|
|
|
1286
1297
|
method: "POST", body: JSON.stringify({ sourceChunkId: chunkId }),
|
|
1287
1298
|
});
|
|
1288
1299
|
if (hubClient.userId) this.store.deleteHubMemoryBySource(hubClient.userId, chunkId);
|
|
1300
|
+
this.store.deleteTeamSharedChunk(chunkId);
|
|
1289
1301
|
hubSynced = true;
|
|
1290
1302
|
} catch (err) { this.log.warn(`Failed to unshare memory from team: ${err}`); }
|
|
1291
1303
|
}
|
|
@@ -1495,7 +1507,17 @@ export class ViewerServer {
|
|
|
1495
1507
|
|
|
1496
1508
|
private getHubMemoryForChunk(chunkId: string): any {
|
|
1497
1509
|
const db = (this.store as any).db;
|
|
1498
|
-
|
|
1510
|
+
const hub = db.prepare("SELECT * FROM hub_memories WHERE source_chunk_id = ? LIMIT 1").get(chunkId);
|
|
1511
|
+
if (hub) return hub;
|
|
1512
|
+
const ts = this.store.getTeamSharedChunk(chunkId);
|
|
1513
|
+
if (ts) {
|
|
1514
|
+
return {
|
|
1515
|
+
source_chunk_id: chunkId,
|
|
1516
|
+
visibility: ts.visibility,
|
|
1517
|
+
group_id: ts.groupId,
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
return undefined;
|
|
1499
1521
|
}
|
|
1500
1522
|
|
|
1501
1523
|
private getHubTaskForLocal(taskId: string): any {
|
|
@@ -2105,11 +2127,12 @@ export class ViewerServer {
|
|
|
2105
2127
|
},
|
|
2106
2128
|
}),
|
|
2107
2129
|
});
|
|
2130
|
+
const mid = String((response as any)?.memoryId ?? "");
|
|
2108
2131
|
if (hubClient.userId && this.ctx?.config?.sharing?.role === "hub") {
|
|
2109
2132
|
const now = Date.now();
|
|
2110
2133
|
const existing = this.store.getHubMemoryBySource(hubClient.userId, chunk.id);
|
|
2111
2134
|
this.store.upsertHubMemory({
|
|
2112
|
-
id:
|
|
2135
|
+
id: mid || existing?.id || crypto.randomUUID(),
|
|
2113
2136
|
sourceChunkId: chunk.id,
|
|
2114
2137
|
sourceUserId: hubClient.userId,
|
|
2115
2138
|
role: chunk.role,
|
|
@@ -2121,6 +2144,8 @@ export class ViewerServer {
|
|
|
2121
2144
|
createdAt: existing?.createdAt ?? now,
|
|
2122
2145
|
updatedAt: now,
|
|
2123
2146
|
});
|
|
2147
|
+
} else if (hubClient.userId) {
|
|
2148
|
+
this.store.upsertTeamSharedChunk(chunk.id, { hubMemoryId: mid, visibility, groupId });
|
|
2124
2149
|
}
|
|
2125
2150
|
this.jsonResponse(res, { ok: true, chunkId, visibility, response });
|
|
2126
2151
|
} catch (err) {
|
|
@@ -2142,6 +2167,7 @@ export class ViewerServer {
|
|
|
2142
2167
|
});
|
|
2143
2168
|
const hubUserId = hubClient.userId;
|
|
2144
2169
|
if (hubUserId) this.store.deleteHubMemoryBySource(hubUserId, chunkId);
|
|
2170
|
+
this.store.deleteTeamSharedChunk(chunkId);
|
|
2145
2171
|
this.jsonResponse(res, { ok: true, chunkId });
|
|
2146
2172
|
} catch (err) {
|
|
2147
2173
|
this.jsonResponse(res, { ok: false, error: String(err) });
|