@memtensor/memos-local-openclaw-plugin 1.0.2-beta.5 → 1.0.2
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 +52 -8
- package/dist/capture/index.js.map +1 -1
- package/dist/ingest/chunker.d.ts +3 -4
- package/dist/ingest/chunker.d.ts.map +1 -1
- package/dist/ingest/chunker.js +19 -24
- package/dist/ingest/chunker.js.map +1 -1
- package/dist/ingest/providers/anthropic.d.ts +3 -1
- package/dist/ingest/providers/anthropic.d.ts.map +1 -1
- package/dist/ingest/providers/anthropic.js +79 -39
- package/dist/ingest/providers/anthropic.js.map +1 -1
- package/dist/ingest/providers/bedrock.d.ts +3 -1
- package/dist/ingest/providers/bedrock.d.ts.map +1 -1
- package/dist/ingest/providers/bedrock.js +79 -39
- package/dist/ingest/providers/bedrock.js.map +1 -1
- package/dist/ingest/providers/gemini.d.ts +3 -1
- package/dist/ingest/providers/gemini.d.ts.map +1 -1
- package/dist/ingest/providers/gemini.js +77 -39
- package/dist/ingest/providers/gemini.js.map +1 -1
- package/dist/ingest/providers/index.d.ts +3 -1
- package/dist/ingest/providers/index.d.ts.map +1 -1
- package/dist/ingest/providers/index.js +70 -30
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/ingest/providers/openai.d.ts +3 -1
- package/dist/ingest/providers/openai.d.ts.map +1 -1
- package/dist/ingest/providers/openai.js +80 -39
- package/dist/ingest/providers/openai.js.map +1 -1
- package/dist/ingest/task-processor.d.ts +1 -0
- package/dist/ingest/task-processor.d.ts.map +1 -1
- package/dist/ingest/task-processor.js +33 -9
- package/dist/ingest/task-processor.js.map +1 -1
- package/dist/ingest/worker.d.ts.map +1 -1
- package/dist/ingest/worker.js +29 -13
- package/dist/ingest/worker.js.map +1 -1
- package/dist/recall/engine.d.ts.map +1 -1
- package/dist/recall/engine.js +19 -14
- package/dist/recall/engine.js.map +1 -1
- package/dist/skill/bundled-memory-guide.d.ts +1 -5
- package/dist/skill/bundled-memory-guide.d.ts.map +1 -1
- package/dist/skill/bundled-memory-guide.js +38 -97
- package/dist/skill/bundled-memory-guide.js.map +1 -1
- package/dist/skill/evaluator.js +1 -1
- package/dist/storage/sqlite.d.ts +1 -2
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +90 -17
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/tools/memory-get.d.ts.map +1 -1
- package/dist/tools/memory-get.js +1 -3
- package/dist/tools/memory-get.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/update-check.d.ts +21 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +111 -0
- package/dist/update-check.js.map +1 -0
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +444 -182
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +1 -1
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +142 -78
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +206 -198
- package/openclaw.plugin.json +3 -0
- package/package.json +5 -1
- package/scripts/postinstall.cjs +69 -2
- package/skill/memos-memory-guide/SKILL.md +73 -36
- package/src/capture/index.ts +52 -8
- package/src/ingest/chunker.ts +22 -30
- package/src/ingest/providers/anthropic.ts +89 -41
- package/src/ingest/providers/bedrock.ts +90 -41
- package/src/ingest/providers/gemini.ts +89 -41
- package/src/ingest/providers/index.ts +81 -35
- package/src/ingest/providers/openai.ts +90 -41
- package/src/ingest/task-processor.ts +29 -8
- package/src/ingest/worker.ts +31 -13
- package/src/recall/engine.ts +20 -13
- package/src/skill/bundled-memory-guide.ts +5 -96
- package/src/skill/evaluator.ts +1 -1
- package/src/storage/sqlite.ts +93 -21
- package/src/tools/memory-get.ts +1 -4
- package/src/types.ts +2 -9
- package/src/update-check.ts +96 -0
- package/src/viewer/html.ts +444 -182
- package/src/viewer/server.ts +101 -66
package/src/viewer/server.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import http from "node:http";
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
|
-
import { execSync } from "node:child_process";
|
|
3
|
+
import { execSync, exec } from "node:child_process";
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import readline from "node:readline";
|
|
@@ -75,8 +75,8 @@ export class ViewerServer {
|
|
|
75
75
|
|
|
76
76
|
private ppRunning = false;
|
|
77
77
|
private ppAbort = false;
|
|
78
|
-
private ppState: { running: boolean; done: boolean; stopped: boolean; processed: number; total: number; tasksCreated: number; skillsCreated: number; errors: number } =
|
|
79
|
-
{ running: false, done: false, stopped: false, processed: 0, total: 0, tasksCreated: 0, skillsCreated: 0, errors: 0 };
|
|
78
|
+
private ppState: { running: boolean; done: boolean; stopped: boolean; processed: number; total: number; tasksCreated: number; skillsCreated: number; errors: number; skippedSessions: number; totalSessions: number } =
|
|
79
|
+
{ running: false, done: false, stopped: false, processed: 0, total: 0, tasksCreated: 0, skillsCreated: 0, errors: 0, skippedSessions: 0, totalSessions: 0 };
|
|
80
80
|
private ppSSEClients: http.ServerResponse[] = [];
|
|
81
81
|
|
|
82
82
|
constructor(opts: ViewerServerOptions) {
|
|
@@ -235,7 +235,6 @@ export class ViewerServer {
|
|
|
235
235
|
else if (p.startsWith("/api/skill/") && req.method === "DELETE") this.handleSkillDelete(res, p);
|
|
236
236
|
else if (p.startsWith("/api/skill/") && req.method === "PUT") this.handleSkillUpdate(req, res, p);
|
|
237
237
|
else if (p.startsWith("/api/skill/") && req.method === "GET") this.serveSkillDetail(res, p);
|
|
238
|
-
else if (p === "/api/memory" && req.method === "POST") this.handleCreate(req, res);
|
|
239
238
|
else if (p.startsWith("/api/memory/") && req.method === "GET") this.serveMemoryDetail(res, p);
|
|
240
239
|
else if (p.startsWith("/api/memory/") && req.method === "PUT") this.handleUpdate(req, res, p);
|
|
241
240
|
else if (p.startsWith("/api/memory/") && req.method === "DELETE") this.handleDelete(res, p);
|
|
@@ -249,6 +248,7 @@ export class ViewerServer {
|
|
|
249
248
|
else if (p === "/api/model-health" && req.method === "GET") this.serveModelHealth(res);
|
|
250
249
|
else if (p === "/api/fallback-model" && req.method === "GET") this.serveFallbackModel(res);
|
|
251
250
|
else if (p === "/api/update-check" && req.method === "GET") this.handleUpdateCheck(res);
|
|
251
|
+
else if (p === "/api/update-install" && req.method === "POST") this.handleUpdateInstall(req, res);
|
|
252
252
|
else if (p === "/api/auth/logout" && req.method === "POST") this.handleLogout(req, res);
|
|
253
253
|
else if (p === "/api/cleanup-polluted" && req.method === "POST") this.handleCleanupPolluted(res);
|
|
254
254
|
else if (p === "/api/migrate/scan" && req.method === "GET") this.handleMigrateScan(res);
|
|
@@ -382,7 +382,6 @@ export class ViewerServer {
|
|
|
382
382
|
const offset = (page - 1) * limit;
|
|
383
383
|
const session = url.searchParams.get("session") ?? undefined;
|
|
384
384
|
const role = url.searchParams.get("role") ?? undefined;
|
|
385
|
-
const kind = url.searchParams.get("kind") ?? undefined;
|
|
386
385
|
const dateFrom = url.searchParams.get("dateFrom") ?? undefined;
|
|
387
386
|
const dateTo = url.searchParams.get("dateTo") ?? undefined;
|
|
388
387
|
const owner = url.searchParams.get("owner") ?? undefined;
|
|
@@ -393,7 +392,6 @@ export class ViewerServer {
|
|
|
393
392
|
const params: any[] = [];
|
|
394
393
|
if (session) { conditions.push("session_key = ?"); params.push(session); }
|
|
395
394
|
if (role) { conditions.push("role = ?"); params.push(role); }
|
|
396
|
-
if (kind) { conditions.push("kind = ?"); params.push(kind); }
|
|
397
395
|
if (owner) { conditions.push("owner = ?"); params.push(owner); }
|
|
398
396
|
if (dateFrom) { conditions.push("created_at >= ?"); params.push(new Date(dateFrom).getTime()); }
|
|
399
397
|
if (dateTo) { conditions.push("created_at <= ?"); params.push(new Date(dateTo).getTime()); }
|
|
@@ -401,9 +399,14 @@ export class ViewerServer {
|
|
|
401
399
|
const where = conditions.length > 0 ? " WHERE " + conditions.join(" AND ") : "";
|
|
402
400
|
const totalRow = db.prepare("SELECT COUNT(*) as count FROM chunks" + where).get(...params) as any;
|
|
403
401
|
const rawMemories = db.prepare("SELECT * FROM chunks" + where + ` ORDER BY created_at ${sortBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
|
|
402
|
+
const findMergeSources = db.prepare("SELECT id, summary, role FROM chunks WHERE dedup_target = ? AND (dedup_status = 'merged' OR dedup_status = 'duplicate')");
|
|
404
403
|
const memories = rawMemories.map((m: any) => {
|
|
405
404
|
if (m.role === "user" && m.content) {
|
|
406
|
-
|
|
405
|
+
m = { ...m, content: stripInboundMetadata(m.content) };
|
|
406
|
+
}
|
|
407
|
+
if (m.merge_count > 0) {
|
|
408
|
+
const sources = findMergeSources.all(m.id) as Array<{ id: string; summary: string; role: string }>;
|
|
409
|
+
m.merge_sources = sources;
|
|
407
410
|
}
|
|
408
411
|
return m;
|
|
409
412
|
});
|
|
@@ -441,7 +444,7 @@ export class ViewerServer {
|
|
|
441
444
|
id: t.id,
|
|
442
445
|
sessionKey: t.sessionKey,
|
|
443
446
|
title: t.title,
|
|
444
|
-
summary: t.summary
|
|
447
|
+
summary: t.summary ?? "",
|
|
445
448
|
status: t.status,
|
|
446
449
|
startedAt: t.startedAt,
|
|
447
450
|
endedAt: t.endedAt,
|
|
@@ -464,8 +467,7 @@ export class ViewerServer {
|
|
|
464
467
|
|
|
465
468
|
const chunks = this.store.getChunksByTask(taskId);
|
|
466
469
|
const chunkItems = chunks.map((c) => {
|
|
467
|
-
|
|
468
|
-
if (text.length > 500) text = text.slice(0, 497) + "...";
|
|
470
|
+
const text = c.role === "user" ? stripInboundMetadata(c.content) : c.content;
|
|
469
471
|
return { id: c.id, role: c.role, content: text, summary: c.summary, createdAt: c.createdAt };
|
|
470
472
|
});
|
|
471
473
|
|
|
@@ -502,7 +504,7 @@ export class ViewerServer {
|
|
|
502
504
|
const emptyStats = {
|
|
503
505
|
totalMemories: 0, totalSessions: 0, totalEmbeddings: 0, totalSkills: 0,
|
|
504
506
|
embeddingProvider: this.embedder?.provider ?? "none",
|
|
505
|
-
|
|
507
|
+
dedupBreakdown: {},
|
|
506
508
|
timeRange: { earliest: null, latest: null },
|
|
507
509
|
sessions: [],
|
|
508
510
|
};
|
|
@@ -516,7 +518,6 @@ export class ViewerServer {
|
|
|
516
518
|
const db = (this.store as any).db;
|
|
517
519
|
const total = db.prepare("SELECT COUNT(*) as count FROM chunks").get() as any;
|
|
518
520
|
const sessions = db.prepare("SELECT COUNT(DISTINCT session_key) as count FROM chunks").get() as any;
|
|
519
|
-
const roles = db.prepare("SELECT role, COUNT(*) as count FROM chunks GROUP BY role").all() as any[];
|
|
520
521
|
const timeRange = db.prepare("SELECT MIN(created_at) as earliest, MAX(created_at) as latest FROM chunks WHERE dedup_status = 'active'").get() as any;
|
|
521
522
|
const MIN_VALID_TS = 1704067200000; // 2024-01-01
|
|
522
523
|
if (timeRange.earliest != null && timeRange.earliest < MIN_VALID_TS) {
|
|
@@ -528,7 +529,6 @@ export class ViewerServer {
|
|
|
528
529
|
}
|
|
529
530
|
let embCount = 0;
|
|
530
531
|
try { embCount = (db.prepare("SELECT COUNT(*) as count FROM embeddings").get() as any).count; } catch { /* table may not exist */ }
|
|
531
|
-
const kinds = db.prepare("SELECT kind, COUNT(*) as count FROM chunks GROUP BY kind").all() as any[];
|
|
532
532
|
const sessionList = db.prepare(
|
|
533
533
|
"SELECT session_key, COUNT(*) as count, MIN(created_at) as earliest, MAX(created_at) as latest FROM chunks GROUP BY session_key ORDER BY latest DESC",
|
|
534
534
|
).all() as any[];
|
|
@@ -552,8 +552,6 @@ export class ViewerServer {
|
|
|
552
552
|
totalMemories: total.count, totalSessions: sessions.count, totalEmbeddings: embCount,
|
|
553
553
|
totalSkills: skillCount,
|
|
554
554
|
embeddingProvider: this.embedder.provider,
|
|
555
|
-
roleBreakdown: Object.fromEntries(roles.map((r: any) => [r.role, r.count])),
|
|
556
|
-
kindBreakdown: Object.fromEntries(kinds.map((k: any) => [k.kind, k.count])),
|
|
557
555
|
dedupBreakdown,
|
|
558
556
|
timeRange: { earliest: timeRange.earliest, latest: timeRange.latest },
|
|
559
557
|
sessions: sessionList,
|
|
@@ -570,7 +568,6 @@ export class ViewerServer {
|
|
|
570
568
|
if (!q.trim()) { this.jsonResponse(res, { results: [], query: q }); return; }
|
|
571
569
|
|
|
572
570
|
const role = url.searchParams.get("role") ?? undefined;
|
|
573
|
-
const kind = url.searchParams.get("kind") ?? undefined;
|
|
574
571
|
const session = url.searchParams.get("session") ?? undefined;
|
|
575
572
|
const owner = url.searchParams.get("owner") ?? undefined;
|
|
576
573
|
const dateFrom = url.searchParams.get("dateFrom") ?? undefined;
|
|
@@ -578,7 +575,6 @@ export class ViewerServer {
|
|
|
578
575
|
|
|
579
576
|
const passesFilter = (r: any): boolean => {
|
|
580
577
|
if (role && r.role !== role) return false;
|
|
581
|
-
if (kind && r.kind !== kind) return false;
|
|
582
578
|
if (session && r.session_key !== session) return false;
|
|
583
579
|
if (owner && r.owner !== owner) return false;
|
|
584
580
|
if (dateFrom && r.created_at < new Date(dateFrom).getTime()) return false;
|
|
@@ -920,35 +916,6 @@ export class ViewerServer {
|
|
|
920
916
|
|
|
921
917
|
// ─── CRUD ───
|
|
922
918
|
|
|
923
|
-
private handleCreate(req: http.IncomingMessage, res: http.ServerResponse): void {
|
|
924
|
-
this.readBody(req, (body) => {
|
|
925
|
-
try {
|
|
926
|
-
const data = JSON.parse(body);
|
|
927
|
-
if (!data.content || typeof data.content !== "string" || !data.content.trim()) {
|
|
928
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
929
|
-
res.end(JSON.stringify({ error: "content is required and must be a non-empty string" }));
|
|
930
|
-
return;
|
|
931
|
-
}
|
|
932
|
-
const { v4: uuidv4 } = require("uuid");
|
|
933
|
-
const id = uuidv4();
|
|
934
|
-
const now = Date.now();
|
|
935
|
-
this.store.insertChunk({
|
|
936
|
-
id, sessionKey: data.session_key || "manual", turnId: `manual-${now}`, seq: 0,
|
|
937
|
-
role: data.role || "user", content: data.content, kind: data.kind || "paragraph",
|
|
938
|
-
summary: data.summary || data.content.slice(0, 100),
|
|
939
|
-
taskId: null, skillId: null, owner: data.owner || "agent:main",
|
|
940
|
-
dedupStatus: "active", dedupTarget: null, dedupReason: null,
|
|
941
|
-
mergeCount: 0, lastHitAt: null, mergeHistory: "[]",
|
|
942
|
-
createdAt: now, updatedAt: now, embedding: null,
|
|
943
|
-
});
|
|
944
|
-
this.jsonResponse(res, { ok: true, id, message: "Memory created" });
|
|
945
|
-
} catch (err) {
|
|
946
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
947
|
-
res.end(JSON.stringify({ error: String(err) }));
|
|
948
|
-
}
|
|
949
|
-
});
|
|
950
|
-
}
|
|
951
|
-
|
|
952
919
|
private serveMemoryDetail(res: http.ServerResponse, urlPath: string): void {
|
|
953
920
|
const chunkId = urlPath.replace("/api/memory/", "");
|
|
954
921
|
const chunk = this.store.getChunk(chunkId);
|
|
@@ -973,7 +940,7 @@ export class ViewerServer {
|
|
|
973
940
|
res.end(JSON.stringify({ error: "content must be a non-empty string" }));
|
|
974
941
|
return;
|
|
975
942
|
}
|
|
976
|
-
const ok = this.store.updateChunk(chunkId, { summary: data.summary, content: data.content, role: data.role,
|
|
943
|
+
const ok = this.store.updateChunk(chunkId, { summary: data.summary, content: data.content, role: data.role, owner: data.owner });
|
|
977
944
|
if (ok) this.jsonResponse(res, { ok: true, message: "Memory updated" });
|
|
978
945
|
else { res.writeHead(404, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Not found" })); }
|
|
979
946
|
} catch (err) {
|
|
@@ -1184,20 +1151,20 @@ export class ViewerServer {
|
|
|
1184
1151
|
this.jsonResponse(res, { updateAvailable: false, current });
|
|
1185
1152
|
return;
|
|
1186
1153
|
}
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
this.jsonResponse(res, { updateAvailable: false, current });
|
|
1154
|
+
const { computeUpdateCheck } = await import("../update-check");
|
|
1155
|
+
const result = await computeUpdateCheck(name, current, fetch, 6_000);
|
|
1156
|
+
if (!result) {
|
|
1157
|
+
this.jsonResponse(res, { updateAvailable: false, current, packageName: name });
|
|
1192
1158
|
return;
|
|
1193
1159
|
}
|
|
1194
|
-
const data = await npmResp.json() as { version?: string };
|
|
1195
|
-
const latest = data.version ?? current;
|
|
1196
1160
|
this.jsonResponse(res, {
|
|
1197
|
-
updateAvailable:
|
|
1198
|
-
current,
|
|
1199
|
-
latest,
|
|
1200
|
-
packageName:
|
|
1161
|
+
updateAvailable: result.updateAvailable,
|
|
1162
|
+
current: result.current,
|
|
1163
|
+
latest: result.latest,
|
|
1164
|
+
packageName: result.packageName,
|
|
1165
|
+
channel: result.channel,
|
|
1166
|
+
installCommand: result.installCommand,
|
|
1167
|
+
stableChannel: result.stableChannel,
|
|
1201
1168
|
});
|
|
1202
1169
|
} catch (e) {
|
|
1203
1170
|
this.log.warn(`handleUpdateCheck error: ${e}`);
|
|
@@ -1205,6 +1172,47 @@ export class ViewerServer {
|
|
|
1205
1172
|
}
|
|
1206
1173
|
}
|
|
1207
1174
|
|
|
1175
|
+
private handleUpdateInstall(req: http.IncomingMessage, res: http.ServerResponse): void {
|
|
1176
|
+
let body = "";
|
|
1177
|
+
req.on("data", (chunk: Buffer) => { body += chunk.toString(); });
|
|
1178
|
+
req.on("end", () => {
|
|
1179
|
+
try {
|
|
1180
|
+
const { packageSpec } = JSON.parse(body);
|
|
1181
|
+
if (!packageSpec || typeof packageSpec !== "string") {
|
|
1182
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1183
|
+
res.end(JSON.stringify({ ok: false, error: "Missing packageSpec" }));
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
const allowed = /^@[\w-]+\/[\w.-]+(@[\w.-]+)?$/;
|
|
1187
|
+
if (!allowed.test(packageSpec)) {
|
|
1188
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1189
|
+
res.end(JSON.stringify({ ok: false, error: "Invalid package spec" }));
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
this.log.info(`update-install: installing ${packageSpec}...`);
|
|
1193
|
+
exec(`npx openclaw plugins install ${packageSpec}`, { timeout: 120_000 }, (err, stdout, stderr) => {
|
|
1194
|
+
if (err) {
|
|
1195
|
+
this.log.warn(`update-install failed: ${err.message}\n${stderr}`);
|
|
1196
|
+
this.jsonResponse(res, { ok: false, error: stderr || err.message });
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
this.log.info(`update-install success: ${stdout}`);
|
|
1200
|
+
this.jsonResponse(res, { ok: true, output: stdout });
|
|
1201
|
+
this.log.info(`update-install: restarting gateway...`);
|
|
1202
|
+
setTimeout(() => {
|
|
1203
|
+
exec("npx openclaw gateway restart", { timeout: 30_000 }, (restartErr) => {
|
|
1204
|
+
if (restartErr) this.log.warn(`gateway restart failed: ${restartErr.message}`);
|
|
1205
|
+
else this.log.info("gateway restart initiated");
|
|
1206
|
+
});
|
|
1207
|
+
}, 1000);
|
|
1208
|
+
});
|
|
1209
|
+
} catch (e) {
|
|
1210
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1211
|
+
res.end(JSON.stringify({ ok: false, error: String(e) }));
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1208
1216
|
private async testEmbeddingModel(provider: string, model: string, endpoint: string, apiKey: string): Promise<number | undefined> {
|
|
1209
1217
|
if (provider === "local") {
|
|
1210
1218
|
return 384;
|
|
@@ -1438,10 +1446,18 @@ export class ViewerServer {
|
|
|
1438
1446
|
}
|
|
1439
1447
|
|
|
1440
1448
|
let importedSessions: string[] = [];
|
|
1449
|
+
let importedChunkCount = 0;
|
|
1441
1450
|
try {
|
|
1442
1451
|
if (this.store) {
|
|
1443
1452
|
importedSessions = this.store.getDistinctSessionKeys()
|
|
1444
1453
|
.filter((sk: string) => sk.startsWith("openclaw-import-") || sk.startsWith("openclaw-session-"));
|
|
1454
|
+
if (importedSessions.length > 0) {
|
|
1455
|
+
const placeholders = importedSessions.map(() => "?").join(",");
|
|
1456
|
+
const row = (this.store as any).db.prepare(
|
|
1457
|
+
`SELECT COUNT(*) as cnt FROM chunks WHERE session_key IN (${placeholders})`
|
|
1458
|
+
).get(...importedSessions) as { cnt: number };
|
|
1459
|
+
importedChunkCount = row?.cnt ?? 0;
|
|
1460
|
+
}
|
|
1445
1461
|
}
|
|
1446
1462
|
} catch (storeErr) {
|
|
1447
1463
|
this.log.warn(`migrate/scan: store query failed: ${storeErr}`);
|
|
@@ -1456,6 +1472,7 @@ export class ViewerServer {
|
|
|
1456
1472
|
hasSummarizer,
|
|
1457
1473
|
hasImportedData: importedSessions.length > 0,
|
|
1458
1474
|
importedSessionCount: importedSessions.length,
|
|
1475
|
+
importedChunkCount,
|
|
1459
1476
|
});
|
|
1460
1477
|
} catch (e) {
|
|
1461
1478
|
this.log.warn(`migrate/scan error: ${e}`);
|
|
@@ -1587,11 +1604,14 @@ export class ViewerServer {
|
|
|
1587
1604
|
} else {
|
|
1588
1605
|
this.broadcastSSE("done", { ok: true });
|
|
1589
1606
|
}
|
|
1590
|
-
for (const c of this.migrationSSEClients) {
|
|
1591
|
-
try { c.end(); } catch { /* ignore */ }
|
|
1592
|
-
}
|
|
1593
|
-
this.migrationSSEClients = [];
|
|
1594
1607
|
this.migrationAbort = false;
|
|
1608
|
+
const clientsToClose = [...this.migrationSSEClients];
|
|
1609
|
+
this.migrationSSEClients = [];
|
|
1610
|
+
setTimeout(() => {
|
|
1611
|
+
for (const c of clientsToClose) {
|
|
1612
|
+
try { c.end(); } catch { /* ignore */ }
|
|
1613
|
+
}
|
|
1614
|
+
}, 500);
|
|
1595
1615
|
});
|
|
1596
1616
|
});
|
|
1597
1617
|
}
|
|
@@ -2022,7 +2042,7 @@ export class ViewerServer {
|
|
|
2022
2042
|
res.on("close", () => { this.ppSSEClients = this.ppSSEClients.filter(c => c !== res); });
|
|
2023
2043
|
|
|
2024
2044
|
this.ppAbort = false;
|
|
2025
|
-
this.ppState = { running: true, done: false, stopped: false, processed: 0, total: 0, tasksCreated: 0, skillsCreated: 0, errors: 0 };
|
|
2045
|
+
this.ppState = { running: true, done: false, stopped: false, processed: 0, total: 0, tasksCreated: 0, skillsCreated: 0, errors: 0, skippedSessions: 0, totalSessions: 0 };
|
|
2026
2046
|
|
|
2027
2047
|
const send = (event: string, data: unknown) => {
|
|
2028
2048
|
this.broadcastPPSSE(event, data);
|
|
@@ -2039,9 +2059,12 @@ export class ViewerServer {
|
|
|
2039
2059
|
} else {
|
|
2040
2060
|
this.broadcastPPSSE("done", { ...this.ppState });
|
|
2041
2061
|
}
|
|
2042
|
-
for (const c of this.ppSSEClients) { try { c.end(); } catch { /* */ } }
|
|
2043
|
-
this.ppSSEClients = [];
|
|
2044
2062
|
this.ppAbort = false;
|
|
2063
|
+
const ppClientsToClose = [...this.ppSSEClients];
|
|
2064
|
+
this.ppSSEClients = [];
|
|
2065
|
+
setTimeout(() => {
|
|
2066
|
+
for (const c of ppClientsToClose) { try { c.end(); } catch { /* */ } }
|
|
2067
|
+
}, 500);
|
|
2045
2068
|
});
|
|
2046
2069
|
});
|
|
2047
2070
|
}
|
|
@@ -2073,7 +2096,13 @@ export class ViewerServer {
|
|
|
2073
2096
|
}
|
|
2074
2097
|
|
|
2075
2098
|
private handlePostprocessStatus(res: http.ServerResponse): void {
|
|
2076
|
-
|
|
2099
|
+
let existingTasks = 0;
|
|
2100
|
+
let existingSkills = 0;
|
|
2101
|
+
try {
|
|
2102
|
+
existingTasks = (this.store as any).db.prepare("SELECT COUNT(*) as c FROM tasks").get()?.c ?? 0;
|
|
2103
|
+
existingSkills = this.store.countSkills("active");
|
|
2104
|
+
} catch { /* */ }
|
|
2105
|
+
this.jsonResponse(res, { ...this.ppState, existingTasks, existingSkills });
|
|
2077
2106
|
}
|
|
2078
2107
|
|
|
2079
2108
|
private broadcastPPSSE(event: string, data: unknown): void {
|
|
@@ -2123,12 +2152,18 @@ export class ViewerServer {
|
|
|
2123
2152
|
}
|
|
2124
2153
|
|
|
2125
2154
|
this.ppState.total = pendingItems.length;
|
|
2155
|
+
this.ppState.skippedSessions = skippedCount;
|
|
2156
|
+
this.ppState.totalSessions = importSessions.length;
|
|
2157
|
+
const existingTaskCount = (this.store as any).db.prepare("SELECT COUNT(*) as c FROM tasks WHERE session_key IN (" + importSessions.map(() => "?").join(",") + ")").get(...importSessions)?.c ?? 0;
|
|
2158
|
+
const existingSkillCount = this.store.countSkills("active");
|
|
2126
2159
|
send("info", {
|
|
2127
2160
|
totalSessions: importSessions.length,
|
|
2128
2161
|
alreadyProcessed: skippedCount,
|
|
2129
2162
|
pending: pendingItems.length,
|
|
2130
2163
|
agents: Array.from(agentGroups.keys()),
|
|
2131
2164
|
concurrency,
|
|
2165
|
+
existingTasks: existingTaskCount,
|
|
2166
|
+
existingSkills: existingSkillCount,
|
|
2132
2167
|
});
|
|
2133
2168
|
send("progress", { processed: 0, total: pendingItems.length });
|
|
2134
2169
|
|