@memtensor/memos-local-openclaw-plugin 1.0.8-beta.7 → 1.0.8-beta.9

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.
@@ -144,8 +144,6 @@ export class ViewerServer {
144
144
  private lastKnownNotifCount = 0;
145
145
  private hubHeartbeatTimer?: ReturnType<typeof setInterval>;
146
146
  private static readonly HUB_HEARTBEAT_INTERVAL_MS = 45_000;
147
- private static readonly STALE_TASK_TIMEOUT_MS = 4 * 60 * 60 * 1000;
148
- private staleFinalizeRunning = false;
149
147
 
150
148
  constructor(opts: ViewerServerOptions) {
151
149
  this.store = opts.store;
@@ -317,7 +315,6 @@ export class ViewerServer {
317
315
  else if (p === "/api/tool-metrics") this.serveToolMetrics(res, url);
318
316
  else if (p === "/api/search") this.serveSearch(req, res, url);
319
317
  else if (p === "/api/tasks" && req.method === "GET") this.serveTasks(res, url);
320
- else if (p === "/api/task-search" && req.method === "GET") this.serveTaskSearch(res, url);
321
318
  else if (p.match(/^\/api\/task\/[^/]+\/retry-skill$/) && req.method === "POST") this.handleTaskRetrySkill(req, res, p);
322
319
  else if (p.startsWith("/api/task/") && req.method === "DELETE") this.handleTaskDelete(res, p);
323
320
  else if (p.startsWith("/api/task/") && req.method === "PUT") this.handleTaskUpdate(req, res, p);
@@ -326,8 +323,6 @@ export class ViewerServer {
326
323
  else if (p.match(/^\/api\/skill\/[^/]+\/download$/) && req.method === "GET") this.serveSkillDownload(res, p);
327
324
  else if (p.match(/^\/api\/skill\/[^/]+\/files$/) && req.method === "GET") this.serveSkillFiles(res, p);
328
325
  else if (p.match(/^\/api\/skill\/[^/]+\/visibility$/) && req.method === "PUT") this.handleSkillVisibility(req, res, p);
329
- else if (p.match(/^\/api\/skill\/[^/]+\/disable$/) && req.method === "PUT") this.handleSkillDisable(res, p);
330
- else if (p.match(/^\/api\/skill\/[^/]+\/enable$/) && req.method === "PUT") this.handleSkillEnable(res, p);
331
326
  else if (p.startsWith("/api/skill/") && req.method === "DELETE") this.handleSkillDelete(res, p);
332
327
  else if (p.startsWith("/api/skill/") && req.method === "PUT") this.handleSkillUpdate(req, res, p);
333
328
  else if (p.startsWith("/api/skill/") && req.method === "GET") this.serveSkillDetail(res, p);
@@ -613,16 +608,14 @@ export class ViewerServer {
613
608
  this.store.recordViewerEvent("tasks_list");
614
609
  const status = url.searchParams.get("status") ?? undefined;
615
610
  const owner = url.searchParams.get("owner") ?? undefined;
616
- const session = url.searchParams.get("session") ?? undefined;
617
611
  const limit = Math.min(100, Math.max(1, Number(url.searchParams.get("limit")) || 50));
618
612
  const offset = Math.max(0, Number(url.searchParams.get("offset")) || 0);
619
- const { tasks, total } = this.store.listTasks({ status, limit, offset, owner, session });
613
+ const { tasks, total } = this.store.listTasks({ status, limit, offset, owner });
620
614
 
621
615
  const db = (this.store as any).db;
622
616
  const items = tasks.map((t) => {
623
617
  const meta = db.prepare("SELECT skill_status, owner FROM tasks WHERE id = ?").get(t.id) as { skill_status: string | null; owner: string | null } | undefined;
624
618
  const hubTask = this.getHubTaskForLocal(t.id);
625
- const share = this.resolveTaskTeamShareForApi(t.id, hubTask);
626
619
  return {
627
620
  id: t.id,
628
621
  sessionKey: t.sessionKey,
@@ -634,125 +627,11 @@ export class ViewerServer {
634
627
  chunkCount: this.store.countChunksByTask(t.id),
635
628
  skillStatus: meta?.skill_status ?? null,
636
629
  owner: meta?.owner ?? "agent:main",
637
- sharingVisibility: share.visibility,
630
+ sharingVisibility: hubTask?.visibility ?? null,
638
631
  };
639
632
  });
640
633
 
641
- this.backfillTaskEmbeddings(items);
642
634
  this.jsonResponse(res, { tasks: items, total, limit, offset });
643
- this.autoFinalizeStaleTasks();
644
- }
645
-
646
- private getTaskAutoFinalizeMs(): number {
647
- const hours = this.ctx?.config?.taskAutoFinalizeHours;
648
- if (hours !== undefined && hours !== null) return hours * 60 * 60 * 1000;
649
- try {
650
- const cfgPath = this.getOpenClawConfigPath();
651
- if (fs.existsSync(cfgPath)) {
652
- const raw = JSON.parse(fs.readFileSync(cfgPath, "utf-8"));
653
- const entries = raw?.plugins?.entries ?? {};
654
- const pluginCfg = entries["memos-local-openclaw-plugin"]?.config
655
- ?? entries["memos-local"]?.config ?? {};
656
- if (pluginCfg.taskAutoFinalizeHours !== undefined) return pluginCfg.taskAutoFinalizeHours * 60 * 60 * 1000;
657
- }
658
- } catch { /* fall through */ }
659
- return ViewerServer.STALE_TASK_TIMEOUT_MS;
660
- }
661
-
662
- private autoFinalizeStaleTasks(): void {
663
- if (this.staleFinalizeRunning || !this.ctx) return;
664
- const thresholdMs = this.getTaskAutoFinalizeMs();
665
- if (thresholdMs <= 0) return;
666
- const db = (this.store as any).db;
667
- const now = Date.now();
668
- let staleTasks: Array<{ id: string }>;
669
- try {
670
- staleTasks = db.prepare(`
671
- SELECT t.id
672
- FROM tasks t
673
- LEFT JOIN chunks c ON c.task_id = t.id
674
- WHERE t.status = 'active'
675
- GROUP BY t.id
676
- HAVING (? - COALESCE(MAX(c.created_at), t.started_at)) > ?
677
- `).all(now, thresholdMs) as Array<{ id: string }>;
678
- } catch { return; }
679
- if (staleTasks.length === 0) return;
680
-
681
- this.staleFinalizeRunning = true;
682
- const hours = Math.round(thresholdMs / 3600000);
683
- this.log.info(`Auto-finalizing ${staleTasks.length} stale active task(s) (idle > ${hours}h)`);
684
- const tp = new TaskProcessor(this.store, this.ctx);
685
- (async () => {
686
- for (const row of staleTasks) {
687
- const task = this.store.getTask(row.id);
688
- if (!task || task.status !== "active") continue;
689
- try {
690
- await tp.finalizeTask(task);
691
- this.log.info(`Auto-finalized stale task=${task.id}`);
692
- } catch (err) {
693
- this.log.warn(`Failed to auto-finalize task=${task.id}: ${err}`);
694
- }
695
- }
696
- })().catch((err) => this.log.warn(`autoFinalizeStaleTasks error: ${err}`))
697
- .finally(() => { this.staleFinalizeRunning = false; });
698
- }
699
-
700
- private async serveTaskSearch(res: http.ServerResponse, url: URL): Promise<void> {
701
- const q = (url.searchParams.get("q") ?? "").trim();
702
- if (!q) { this.jsonResponse(res, { tasks: [], total: 0 }); return; }
703
-
704
- const owner = url.searchParams.get("owner") ?? undefined;
705
- const maxResults = Math.min(50, Math.max(1, Number(url.searchParams.get("limit")) || 20));
706
-
707
- const scoreMap = new Map<string, number>();
708
-
709
- if (this.embedder) {
710
- try {
711
- const [queryVec] = await this.embedder.embed([q]);
712
- const allEmb = this.store.getTaskEmbeddings(owner);
713
- for (const { taskId, vector } of allEmb) {
714
- let dot = 0, normA = 0, normB = 0;
715
- for (let i = 0; i < queryVec.length && i < vector.length; i++) {
716
- dot += queryVec[i] * vector[i];
717
- normA += queryVec[i] * queryVec[i];
718
- normB += vector[i] * vector[i];
719
- }
720
- const sim = normA > 0 && normB > 0 ? dot / (Math.sqrt(normA) * Math.sqrt(normB)) : 0;
721
- if (sim > 0.3) scoreMap.set(taskId, sim);
722
- }
723
- } catch { /* embedding unavailable, fall through to FTS */ }
724
- }
725
-
726
- const ftsResults = this.store.taskFtsSearch(q, maxResults, owner);
727
- for (const { taskId, score } of ftsResults) {
728
- const existing = scoreMap.get(taskId) ?? 0;
729
- scoreMap.set(taskId, Math.max(existing, score * 0.8));
730
- }
731
-
732
- const sorted = [...scoreMap.entries()]
733
- .sort((a, b) => b[1] - a[1])
734
- .slice(0, maxResults);
735
-
736
- const db = (this.store as any).db;
737
- const tasks = sorted.map(([taskId, score]) => {
738
- const t = this.store.getTask(taskId);
739
- if (!t) return null;
740
- const meta = db.prepare("SELECT skill_status, owner FROM tasks WHERE id = ?").get(taskId) as { skill_status: string | null; owner: string | null } | undefined;
741
- const hubTask = this.getHubTaskForLocal(taskId);
742
- const ts = this.resolveTaskTeamShareForApi(taskId, hubTask);
743
- return {
744
- id: t.id, sessionKey: t.sessionKey, title: t.title,
745
- summary: t.summary ?? "", status: t.status,
746
- startedAt: t.startedAt, endedAt: t.endedAt,
747
- chunkCount: this.store.countChunksByTask(t.id),
748
- skillStatus: meta?.skill_status ?? null,
749
- owner: meta?.owner ?? "agent:main",
750
- sharingVisibility: ts.visibility,
751
- score,
752
- };
753
- }).filter(Boolean);
754
-
755
- this.jsonResponse(res, { tasks, total: tasks.length });
756
635
  }
757
636
 
758
637
  private serveTaskDetail(res: http.ServerResponse, urlPath: string): void {
@@ -784,7 +663,6 @@ export class ViewerServer {
784
663
  const meta = db.prepare("SELECT skill_status, skill_reason FROM tasks WHERE id = ?").get(taskId) as
785
664
  { skill_status: string | null; skill_reason: string | null } | undefined;
786
665
  const hubTask = this.getHubTaskForLocal(taskId);
787
- const ts = this.resolveTaskTeamShareForApi(taskId, hubTask);
788
666
 
789
667
  this.jsonResponse(res, {
790
668
  id: task.id,
@@ -799,15 +677,15 @@ export class ViewerServer {
799
677
  skillStatus: meta?.skill_status ?? null,
800
678
  skillReason: meta?.skill_reason ?? null,
801
679
  skillLinks,
802
- sharingVisibility: ts.visibility,
803
- sharingGroupId: ts.groupId,
804
- hubTaskId: ts.hasHubLink,
680
+ sharingVisibility: hubTask?.visibility ?? null,
681
+ sharingGroupId: hubTask?.group_id ?? null,
682
+ hubTaskId: hubTask ? true : false,
805
683
  });
806
684
  }
807
685
 
808
686
  private serveStats(res: http.ServerResponse, url?: URL): void {
809
687
  const emptyStats = {
810
- totalMemories: 0, totalSessions: 0, totalEmbeddings: 0, totalSkills: 0, totalTasks: 0,
688
+ totalMemories: 0, totalSessions: 0, totalEmbeddings: 0, totalSkills: 0,
811
689
  embeddingProvider: this.embedder?.provider ?? "none",
812
690
  dedupBreakdown: {},
813
691
  timeRange: { earliest: null, latest: null },
@@ -850,30 +728,9 @@ export class ViewerServer {
850
728
  }
851
729
  const sessionList = db.prepare(sessionQuery).all(...sessionParams) as any[];
852
730
 
853
- let taskSessionList: Array<{ session_key: string; count: number; earliest: number | null; latest: number | null }> = [];
854
- try {
855
- taskSessionList = db.prepare(
856
- "SELECT session_key, COUNT(*) as count, MIN(started_at) as earliest, MAX(COALESCE(updated_at, started_at)) as latest FROM tasks GROUP BY session_key ORDER BY latest DESC",
857
- ).all() as any[];
858
- } catch { /* tasks table may not exist yet */ }
859
-
860
- let skillSessionList: Array<{ session_key: string; count: number; earliest: number | null; latest: number | null }> = [];
861
- try {
862
- skillSessionList = db.prepare(
863
- `SELECT t.session_key as session_key, COUNT(DISTINCT ts.skill_id) as count,
864
- MIN(t.started_at) as earliest, MAX(COALESCE(t.updated_at, t.started_at)) as latest
865
- FROM task_skills ts JOIN tasks t ON t.id = ts.task_id
866
- GROUP BY t.session_key
867
- ORDER BY latest DESC`,
868
- ).all() as any[];
869
- } catch { /* task_skills may not exist yet */ }
870
-
871
731
  let skillCount = 0;
872
732
  try { skillCount = (db.prepare("SELECT COUNT(*) as count FROM skills").get() as any).count; } catch { /* table may not exist yet */ }
873
733
 
874
- let taskCount = 0;
875
- try { taskCount = (db.prepare("SELECT COUNT(*) as count FROM tasks").get() as any).count; } catch { /* table may not exist yet */ }
876
-
877
734
  let dedupBreakdown: Record<string, number> = {};
878
735
  try {
879
736
  const dedupRows = db.prepare("SELECT dedup_status, COUNT(*) as count FROM chunks GROUP BY dedup_status").all() as any[];
@@ -882,15 +739,7 @@ export class ViewerServer {
882
739
 
883
740
  let owners: string[] = [];
884
741
  try {
885
- const ownerRows = db.prepare(`
886
- SELECT DISTINCT owner FROM (
887
- SELECT owner FROM chunks WHERE owner IS NOT NULL AND owner LIKE 'agent:%'
888
- UNION
889
- SELECT owner FROM tasks WHERE owner IS NOT NULL AND owner LIKE 'agent:%'
890
- UNION
891
- SELECT owner FROM skills WHERE owner IS NOT NULL AND owner LIKE 'agent:%'
892
- ) ORDER BY owner
893
- `).all() as any[];
742
+ const ownerRows = db.prepare("SELECT DISTINCT owner FROM chunks WHERE owner IS NOT NULL AND owner LIKE 'agent:%' ORDER BY owner").all() as any[];
894
743
  owners = ownerRows.map((o: any) => o.owner);
895
744
  } catch { /* column may not exist yet */ }
896
745
 
@@ -902,13 +751,11 @@ export class ViewerServer {
902
751
 
903
752
  this.jsonResponse(res, {
904
753
  totalMemories: total.count, totalSessions: sessions.count, totalEmbeddings: embCount,
905
- totalSkills: skillCount, totalTasks: taskCount,
754
+ totalSkills: skillCount,
906
755
  embeddingProvider: this.embedder.provider,
907
756
  dedupBreakdown,
908
757
  timeRange: { earliest: timeRange.earliest, latest: timeRange.latest },
909
758
  sessions: sessionList,
910
- taskSessions: taskSessionList,
911
- skillSessions: skillSessionList,
912
759
  owners,
913
760
  currentAgentOwner,
914
761
  });
@@ -1018,9 +865,7 @@ export class ViewerServer {
1018
865
  private serveSkills(res: http.ServerResponse, url: URL): void {
1019
866
  const status = url.searchParams.get("status") ?? undefined;
1020
867
  const visibility = url.searchParams.get("visibility") ?? undefined;
1021
- const session = url.searchParams.get("session") ?? undefined;
1022
- const owner = url.searchParams.get("owner") ?? undefined;
1023
- let skills = this.store.listSkills({ status, session, owner });
868
+ let skills = this.store.listSkills({ status });
1024
869
  if (visibility) {
1025
870
  skills = skills.filter(s => s.visibility === visibility);
1026
871
  }
@@ -1259,27 +1104,6 @@ export class ViewerServer {
1259
1104
  });
1260
1105
  }
1261
1106
 
1262
- private embedTaskInBackground(taskId: string, text: string): void {
1263
- if (!this.embedder || !text.trim()) return;
1264
- this.embedder.embed([text]).then((vecs: number[][]) => {
1265
- if (vecs.length > 0) this.store.upsertTaskEmbedding(taskId, vecs[0]);
1266
- }).catch(() => {});
1267
- }
1268
-
1269
- private backfillTaskEmbeddings(tasks: Array<{ id: string; summary: string; title: string }>): void {
1270
- if (!this.embedder) return;
1271
- const db = (this.store as any).db;
1272
- for (const t of tasks) {
1273
- try {
1274
- const exists = db.prepare("SELECT 1 FROM task_embeddings WHERE task_id = ?").get(t.id);
1275
- if (!exists) {
1276
- const text = `${t.title ?? ""}: ${t.summary ?? ""}`.trim();
1277
- if (text.length > 1) this.embedTaskInBackground(t.id, text);
1278
- }
1279
- } catch { /* best-effort */ }
1280
- }
1281
- }
1282
-
1283
1107
  private handleTaskDelete(res: http.ServerResponse, urlPath: string): void {
1284
1108
  const taskId = urlPath.replace("/api/task/", "");
1285
1109
  const deleted = this.store.deleteTask(taskId);
@@ -1294,15 +1118,12 @@ export class ViewerServer {
1294
1118
  const data = JSON.parse(body);
1295
1119
  const task = this.store.getTask(taskId);
1296
1120
  if (!task) { res.writeHead(404, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Task not found" })); return; }
1297
- const newTitle = data.title ?? task.title;
1298
- const newSummary = data.summary ?? task.summary;
1299
1121
  this.store.updateTask(taskId, {
1300
- title: newTitle,
1301
- summary: newSummary,
1122
+ title: data.title ?? task.title,
1123
+ summary: data.summary ?? task.summary,
1302
1124
  status: data.status ?? task.status,
1303
1125
  endedAt: task.endedAt ?? undefined,
1304
1126
  });
1305
- this.embedTaskInBackground(taskId, `${newTitle ?? ""}: ${newSummary ?? ""}`);
1306
1127
  this.jsonResponse(res, { ok: true, taskId });
1307
1128
  } catch (err) {
1308
1129
  res.writeHead(400, { "Content-Type": "application/json" });
@@ -1359,58 +1180,6 @@ export class ViewerServer {
1359
1180
  });
1360
1181
  }
1361
1182
 
1362
- private async handleSkillDisable(res: http.ServerResponse, urlPath: string): Promise<void> {
1363
- const skillId = urlPath.split("/")[3];
1364
- const skill = this.store.getSkill(skillId);
1365
- if (!skill) { res.writeHead(404, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Skill not found" })); return; }
1366
- if (skill.status === "archived") { this.jsonResponse(res, { ok: true, skillId, message: "already disabled" }); return; }
1367
-
1368
- try {
1369
- if (skill.visibility === "public") {
1370
- this.store.setSkillVisibility(skillId, "private");
1371
- }
1372
- const hub = this.resolveHubConnection();
1373
- if (hub) {
1374
- await hubRequestJson(hub.hubUrl, hub.userToken, "/api/v1/hub/skills/unpublish", {
1375
- method: "POST",
1376
- body: JSON.stringify({ sourceSkillId: skillId }),
1377
- }).catch(() => {});
1378
- }
1379
- } catch (_) {}
1380
-
1381
- try {
1382
- const workspaceSkillsDir = path.join(this.dataDir, "workspace", "skills");
1383
- const installedDir = path.join(workspaceSkillsDir, skill.name);
1384
- if (fs.existsSync(installedDir)) {
1385
- fs.rmSync(installedDir, { recursive: true, force: true });
1386
- }
1387
- } catch (_) {}
1388
-
1389
- this.store.disableSkill(skillId);
1390
- this.jsonResponse(res, { ok: true, skillId });
1391
- }
1392
-
1393
- private handleSkillEnable(res: http.ServerResponse, urlPath: string): void {
1394
- const skillId = urlPath.split("/")[3];
1395
- const skill = this.store.getSkill(skillId);
1396
- if (!skill) { res.writeHead(404, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Skill not found" })); return; }
1397
- if (skill.status !== "archived") { res.writeHead(400, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Only disabled (archived) skills can be enabled" })); return; }
1398
-
1399
- this.store.enableSkill(skillId);
1400
-
1401
- if (this.embedder) {
1402
- const sv = this.store.getLatestSkillVersion(skillId);
1403
- if (sv) {
1404
- const text = `${skill.name}: ${skill.description}`;
1405
- this.embedder.embed([text]).then((vecs: number[][]) => {
1406
- if (vecs.length > 0) this.store.upsertSkillEmbedding(skillId, vecs[0]);
1407
- }).catch(() => {});
1408
- }
1409
- }
1410
-
1411
- this.jsonResponse(res, { ok: true, skillId });
1412
- }
1413
-
1414
1183
  // ─── CRUD ───
1415
1184
 
1416
1185
  private serveMemoryDetail(res: http.ServerResponse, urlPath: string): void {
@@ -1545,7 +1314,7 @@ export class ViewerServer {
1545
1314
  const refreshedChunk = db.prepare("SELECT * FROM chunks WHERE id = ?").get(chunkId) as any;
1546
1315
  const response = await hubRequestJson(hubClient.hubUrl, hubClient.userToken, "/api/v1/hub/memories/share", {
1547
1316
  method: "POST",
1548
- body: JSON.stringify({ memory: { sourceChunkId: refreshedChunk.id, sourceAgent: refreshedChunk.owner || "", role: refreshedChunk.role, content: refreshedChunk.content, summary: refreshedChunk.summary, kind: refreshedChunk.kind, groupId: null, visibility: "public" } }),
1317
+ body: JSON.stringify({ memory: { sourceChunkId: refreshedChunk.id, role: refreshedChunk.role, content: refreshedChunk.content, summary: refreshedChunk.summary, kind: refreshedChunk.kind, groupId: null, visibility: "public" } }),
1549
1318
  });
1550
1319
  if (!isLocalShared) this.store.markMemorySharedLocally(chunkId);
1551
1320
  const memoryId = String((response as any)?.memoryId ?? "");
@@ -1555,7 +1324,6 @@ export class ViewerServer {
1555
1324
  this.store.upsertHubMemory({
1556
1325
  id: memoryId || existing?.id || crypto.randomUUID(),
1557
1326
  sourceChunkId: chunkId, sourceUserId: hubClient.userId,
1558
- sourceAgent: refreshedChunk.owner || "",
1559
1327
  role: refreshedChunk.role, content: refreshedChunk.content, summary: refreshedChunk.summary ?? "",
1560
1328
  kind: refreshedChunk.kind, groupId: null, visibility: "public",
1561
1329
  createdAt: existing?.createdAt ?? Date.now(), updatedAt: Date.now(),
@@ -1621,8 +1389,7 @@ export class ViewerServer {
1621
1389
 
1622
1390
  const isLocalShared = task.owner === "public";
1623
1391
  const hubTask = this.getHubTaskForLocal(taskId);
1624
- const taskShareUi = this.resolveTaskTeamShareForApi(taskId, hubTask);
1625
- const isTeamShared = taskShareUi.hasHubLink;
1392
+ const isTeamShared = !!hubTask;
1626
1393
  const currentScope = isTeamShared ? "team" : isLocalShared ? "local" : "private";
1627
1394
 
1628
1395
  if (scope === currentScope) {
@@ -1682,7 +1449,6 @@ export class ViewerServer {
1682
1449
  });
1683
1450
  if (this.sharingRole === "hub" && hubClient.userId) this.store.deleteHubTaskBySource(hubClient.userId, taskId);
1684
1451
  else this.store.downgradeTeamSharedTaskToLocal(taskId);
1685
- this.store.clearTeamSharedChunksForTask(taskId);
1686
1452
  hubSynced = true;
1687
1453
  } catch (err) { this.log.warn(`Failed to unshare task from team: ${err}`); }
1688
1454
  }
@@ -1696,8 +1462,6 @@ export class ViewerServer {
1696
1462
  });
1697
1463
  if (this.sharingRole === "hub" && hubClient.userId) this.store.deleteHubTaskBySource(hubClient.userId, taskId);
1698
1464
  else if (!isLocalShared) this.store.unmarkTaskShared(taskId);
1699
- else this.store.downgradeTeamSharedTaskToLocal(taskId);
1700
- this.store.clearTeamSharedChunksForTask(taskId);
1701
1465
  hubSynced = true;
1702
1466
  } catch (err) { this.log.warn(`Failed to unshare task from team: ${err}`); }
1703
1467
  }
@@ -1825,39 +1589,6 @@ export class ViewerServer {
1825
1589
  return scopedHubInstanceId === currentHubInstanceId;
1826
1590
  }
1827
1591
 
1828
- /**
1829
- * Task list/detail/search: derive team-share badge when getHubTaskForLocal misses (e.g. client
1830
- * hub_instance_id drift, or empty hub_task_id from hub while synced_chunks was recorded).
1831
- */
1832
- private resolveTaskTeamShareForApi(taskId: string, hubTask: any): { visibility: string | null; hasHubLink: boolean; groupId: string | null } {
1833
- if (hubTask) {
1834
- return {
1835
- visibility: hubTask.visibility ?? null,
1836
- hasHubLink: true,
1837
- groupId: hubTask.group_id ?? null,
1838
- };
1839
- }
1840
- const lst = this.store.getLocalSharedTask(taskId);
1841
- if (lst) {
1842
- const hid = String(lst.hubTaskId ?? "").trim();
1843
- const teamLinked = hid.length > 0 || (lst.syncedChunks ?? 0) > 0;
1844
- if (teamLinked) return { visibility: lst.visibility || null, hasHubLink: true, groupId: lst.groupId ?? null };
1845
- }
1846
- try {
1847
- const db = (this.store as any).db;
1848
- const chunkTeam = db.prepare(`
1849
- SELECT t.visibility AS v, t.group_id AS g FROM team_shared_chunks t
1850
- INNER JOIN chunks c ON c.id = t.chunk_id
1851
- WHERE c.task_id = ?
1852
- LIMIT 1
1853
- `).get(taskId) as { v: string; g: string | null } | undefined;
1854
- if (chunkTeam) {
1855
- return { visibility: chunkTeam.v || null, hasHubLink: true, groupId: chunkTeam.g ?? null };
1856
- }
1857
- } catch { /* schema / db edge */ }
1858
- return { visibility: null, hasHubLink: false, groupId: null };
1859
- }
1860
-
1861
1592
  private getHubMemoryForChunk(chunkId: string): any {
1862
1593
  if (this.sharingRole === "hub") {
1863
1594
  const db = (this.store as any).db;
@@ -2402,7 +2133,6 @@ export class ViewerServer {
2402
2133
  ref: { sessionKey: row.session_key, chunkId: row.id, turnId: row.turn_id, seq: row.seq },
2403
2134
  taskId: row.task_id ?? null,
2404
2135
  skillId: row.skill_id ?? null,
2405
- owner: row.owner || "",
2406
2136
  }));
2407
2137
  return { hits, meta: { total: hits.length, usedMaxResults: maxResults } };
2408
2138
  }
@@ -2512,7 +2242,6 @@ export class ViewerServer {
2512
2242
  body: JSON.stringify({
2513
2243
  memory: {
2514
2244
  sourceChunkId: chunk.id,
2515
- sourceAgent: chunk.owner || "",
2516
2245
  role: chunk.role,
2517
2246
  content: chunk.content,
2518
2247
  summary: chunk.summary,
@@ -2530,7 +2259,6 @@ export class ViewerServer {
2530
2259
  id: mid || existing?.id || crypto.randomUUID(),
2531
2260
  sourceChunkId: chunk.id,
2532
2261
  sourceUserId: hubClient.userId,
2533
- sourceAgent: chunk.owner || "",
2534
2262
  role: chunk.role,
2535
2263
  content: chunk.content,
2536
2264
  summary: chunk.summary ?? "",
@@ -3079,7 +2807,6 @@ export class ViewerServer {
3079
2807
  if (newCfg.summarizer) config.summarizer = newCfg.summarizer;
3080
2808
  if (newCfg.skillEvolution) config.skillEvolution = newCfg.skillEvolution;
3081
2809
  if (newCfg.viewerPort) config.viewerPort = newCfg.viewerPort;
3082
- if (newCfg.taskAutoFinalizeHours !== undefined) config.taskAutoFinalizeHours = newCfg.taskAutoFinalizeHours;
3083
2810
  if (newCfg.telemetry !== undefined) config.telemetry = newCfg.telemetry;
3084
2811
  if (newCfg.sharing !== undefined) {
3085
2812
  const existing = (config.sharing as Record<string, unknown>) || {};
@@ -3740,7 +3467,7 @@ export class ViewerServer {
3740
3467
 
3741
3468
  this.log.info(`update-install: running postinstall...`);
3742
3469
  execFile(process.execPath, ["scripts/postinstall.cjs"], { cwd: extDir, timeout: 180_000 }, (postErr, postOut, postStderr) => {
3743
- cleanupTmpDir();
3470
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
3744
3471
 
3745
3472
  if (postErr) {
3746
3473
  this.log.warn(`update-install: postinstall failed: ${postErr.message}`);
@@ -4024,7 +3751,7 @@ export class ViewerServer {
4024
3751
  try {
4025
3752
  if (this.store) {
4026
3753
  importedSessions = this.store.getDistinctSessionKeys()
4027
- .filter((sk: string) => sk.startsWith("openclaw-import-") || sk.startsWith("openclaw-session-") || /^agent:[^:]+:(import|session:)/.test(sk));
3754
+ .filter((sk: string) => sk.startsWith("openclaw-import-") || sk.startsWith("openclaw-session-"));
4028
3755
  if (importedSessions.length > 0) {
4029
3756
  const placeholders = importedSessions.map(() => "?").join(",");
4030
3757
  const row = (this.store as any).db.prepare(
@@ -4237,7 +3964,7 @@ export class ViewerServer {
4237
3964
  totalProcessed++;
4238
3965
 
4239
3966
  const contentHash = crypto.createHash("sha256").update(row.text).digest("hex");
4240
- if (this.store.chunkExistsByContent(`agent:${agentId}:import`, "assistant", row.text) || this.store.chunkExistsByContent(`openclaw-import-${agentId}`, "assistant", row.text)) {
3967
+ if (this.store.chunkExistsByContent(`openclaw-import-${agentId}`, "assistant", row.text)) {
4241
3968
  totalSkipped++;
4242
3969
  send("item", {
4243
3970
  index: i + 1,
@@ -4337,7 +4064,7 @@ export class ViewerServer {
4337
4064
  const chunkId = uuid();
4338
4065
  const chunk: Chunk = {
4339
4066
  id: chunkId,
4340
- sessionKey: `agent:${agentId}:import`,
4067
+ sessionKey: `openclaw-import-${agentId}`,
4341
4068
  turnId: `import-${row.id}`,
4342
4069
  seq: 0,
4343
4070
  role: "assistant",
@@ -4492,8 +4219,8 @@ export class ViewerServer {
4492
4219
  const idx = incIdx();
4493
4220
  totalProcessed++;
4494
4221
 
4495
- const sessionKey = `agent:${agentId}:session:${sessionId}`;
4496
- if (this.store.chunkExistsByContent(sessionKey, msgRole, content) || this.store.chunkExistsByContent(`openclaw-session-${sessionId}`, msgRole, content)) {
4222
+ const sessionKey = `openclaw-session-${sessionId}`;
4223
+ if (this.store.chunkExistsByContent(sessionKey, msgRole, content)) {
4497
4224
  totalSkipped++;
4498
4225
  send("item", { index: idx, total: totalMsgs, status: "skipped", preview: content.slice(0, 120), source: file, agent: agentId, role: msgRole, reason: "duplicate" });
4499
4226
  continue;
@@ -4744,7 +4471,7 @@ export class ViewerServer {
4744
4471
  const ctx = this.ctx!;
4745
4472
 
4746
4473
  const importSessions = this.store.getDistinctSessionKeys()
4747
- .filter((sk: string) => sk.startsWith("openclaw-import-") || sk.startsWith("openclaw-session-") || /^agent:[^:]+:(import|session:)/.test(sk));
4474
+ .filter((sk: string) => sk.startsWith("openclaw-import-") || sk.startsWith("openclaw-session-"));
4748
4475
 
4749
4476
  type PendingItem = { sessionKey: string; action: "full" | "skill-only"; owner: string };
4750
4477
  const pendingItems: PendingItem[] = [];
@@ -0,0 +1,5 @@
1
+ {
2
+ "endpoint": "https://proj-xtrace-e218d9316b328f196a3c640cc7ca84-cn-hangzhou.cn-hangzhou.log.aliyuncs.com/rum/web/v2?workspace=default-cms-1026429231103299-cn-hangzhou&service_id=a3u72ukxmr@066657d42a13a9a9f337f",
3
+ "pid": "a3u72ukxmr@066657d42a13a9a9f337f",
4
+ "env": "prod"
5
+ }