@memtensor/memos-local-openclaw-plugin 1.0.4 → 1.0.6-beta.1
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.d.ts.map +1 -1
- package/dist/capture/index.js +24 -0
- package/dist/capture/index.js.map +1 -1
- package/dist/client/connector.d.ts.map +1 -1
- package/dist/client/connector.js +23 -1
- package/dist/client/connector.js.map +1 -1
- package/dist/client/hub.d.ts.map +1 -1
- package/dist/client/hub.js +4 -0
- package/dist/client/hub.js.map +1 -1
- package/dist/hub/server.d.ts +1 -1
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/server.js +39 -31
- package/dist/hub/server.js.map +1 -1
- package/dist/ingest/providers/index.d.ts.map +1 -1
- package/dist/ingest/providers/index.js +16 -86
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/ingest/providers/openai.d.ts +3 -0
- package/dist/ingest/providers/openai.d.ts.map +1 -1
- package/dist/ingest/providers/openai.js +34 -19
- package/dist/ingest/providers/openai.js.map +1 -1
- package/dist/recall/engine.d.ts.map +1 -1
- package/dist/recall/engine.js +28 -19
- package/dist/recall/engine.js.map +1 -1
- package/dist/storage/sqlite.d.ts +30 -7
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +139 -60
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/telemetry.d.ts +4 -1
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +26 -18
- package/dist/telemetry.js.map +1 -1
- package/dist/tools/memory-get.d.ts.map +1 -1
- package/dist/tools/memory-get.js +4 -1
- package/dist/tools/memory-get.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/viewer/server.d.ts +24 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +332 -130
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +66 -30
- package/package.json +1 -1
- package/scripts/postinstall.cjs +21 -5
- package/src/capture/index.ts +36 -0
- package/src/client/connector.ts +22 -1
- package/src/client/hub.ts +4 -0
- package/src/hub/server.ts +42 -26
- package/src/ingest/providers/index.ts +30 -93
- package/src/ingest/providers/openai.ts +32 -15
- package/src/recall/engine.ts +28 -19
- package/src/storage/sqlite.ts +156 -65
- package/src/telemetry.ts +25 -18
- package/src/tools/memory-get.ts +4 -1
- package/src/types.ts +2 -0
- package/src/viewer/server.ts +313 -125
- package/prebuilds/darwin-arm64/better_sqlite3.node +0 -0
- package/prebuilds/darwin-x64/better_sqlite3.node +0 -0
- package/prebuilds/linux-x64/better_sqlite3.node +0 -0
- package/prebuilds/win32-x64/better_sqlite3.node +0 -0
- package/telemetry.credentials.json +0 -5
package/dist/viewer/server.js
CHANGED
|
@@ -37,6 +37,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.ViewerServer = void 0;
|
|
40
|
+
exports.computeMigrationSuccess = computeMigrationSuccess;
|
|
41
|
+
exports.createInitialMigrationState = createInitialMigrationState;
|
|
42
|
+
exports.applyMigrationItemToState = applyMigrationItemToState;
|
|
40
43
|
const node_http_1 = __importDefault(require("node:http"));
|
|
41
44
|
const node_os_1 = __importDefault(require("node:os"));
|
|
42
45
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
@@ -57,10 +60,73 @@ const hub_1 = require("../client/hub");
|
|
|
57
60
|
const skill_sync_1 = require("../client/skill-sync");
|
|
58
61
|
const html_1 = require("./html");
|
|
59
62
|
const uuid_1 = require("uuid");
|
|
60
|
-
function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
function createInitialStepFailures() {
|
|
64
|
+
return { summarization: 0, dedup: 0, embedding: 0 };
|
|
65
|
+
}
|
|
66
|
+
function computeMigrationSuccess(state) {
|
|
67
|
+
const sf = state.stepFailures;
|
|
68
|
+
return state.errors === 0 && sf.summarization === 0 && sf.dedup === 0 && sf.embedding === 0;
|
|
69
|
+
}
|
|
70
|
+
function createInitialMigrationState() {
|
|
71
|
+
const stepFailures = createInitialStepFailures();
|
|
72
|
+
return {
|
|
73
|
+
phase: "",
|
|
74
|
+
stored: 0,
|
|
75
|
+
skipped: 0,
|
|
76
|
+
merged: 0,
|
|
77
|
+
errors: 0,
|
|
78
|
+
processed: 0,
|
|
79
|
+
total: 0,
|
|
80
|
+
lastItem: null,
|
|
81
|
+
done: false,
|
|
82
|
+
stopped: false,
|
|
83
|
+
stepFailures,
|
|
84
|
+
success: computeMigrationSuccess({ errors: 0, stepFailures }),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function applyMigrationItemToState(state, d) {
|
|
88
|
+
if (d.status === "stored")
|
|
89
|
+
state.stored++;
|
|
90
|
+
else if (d.status === "skipped" || d.status === "duplicate")
|
|
91
|
+
state.skipped++;
|
|
92
|
+
else if (d.status === "merged")
|
|
93
|
+
state.merged++;
|
|
94
|
+
else if (d.status === "error")
|
|
95
|
+
state.errors++;
|
|
96
|
+
if (Array.isArray(d.stepFailures)) {
|
|
97
|
+
for (const step of d.stepFailures) {
|
|
98
|
+
if (step === "summarization")
|
|
99
|
+
state.stepFailures.summarization++;
|
|
100
|
+
else if (step === "dedup")
|
|
101
|
+
state.stepFailures.dedup++;
|
|
102
|
+
else if (step === "embedding")
|
|
103
|
+
state.stepFailures.embedding++;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
state.processed = d.index ?? state.processed + 1;
|
|
107
|
+
state.total = d.total ?? state.total;
|
|
108
|
+
state.lastItem = d;
|
|
109
|
+
state.success = computeMigrationSuccess(state);
|
|
110
|
+
}
|
|
111
|
+
/** Epoch ms for Chunk; OpenClaw SQLite may store Unix seconds or ms. */
|
|
112
|
+
function normalizeTimestamp(value) {
|
|
113
|
+
if (value == null)
|
|
114
|
+
return Date.now();
|
|
115
|
+
if (typeof value === "string") {
|
|
116
|
+
const parsed = Date.parse(value.trim());
|
|
117
|
+
if (Number.isFinite(parsed))
|
|
118
|
+
return parsed;
|
|
119
|
+
const n = Number(value);
|
|
120
|
+
if (Number.isFinite(n))
|
|
121
|
+
return normalizeTimestamp(n);
|
|
122
|
+
return Date.now();
|
|
123
|
+
}
|
|
124
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
125
|
+
if (value > 0 && value < 5_000_000_000)
|
|
126
|
+
return Math.round(value * 1000);
|
|
127
|
+
return Math.round(value);
|
|
128
|
+
}
|
|
129
|
+
return Date.now();
|
|
64
130
|
}
|
|
65
131
|
class ViewerServer {
|
|
66
132
|
server = null;
|
|
@@ -87,7 +153,7 @@ class ViewerServer {
|
|
|
87
153
|
resetToken;
|
|
88
154
|
migrationRunning = false;
|
|
89
155
|
migrationAbort = false;
|
|
90
|
-
migrationState =
|
|
156
|
+
migrationState = createInitialMigrationState();
|
|
91
157
|
migrationSSEClients = [];
|
|
92
158
|
ppRunning = false;
|
|
93
159
|
ppAbort = false;
|
|
@@ -591,14 +657,15 @@ class ViewerServer {
|
|
|
591
657
|
if (chunkIds.length > 0) {
|
|
592
658
|
try {
|
|
593
659
|
const placeholders = chunkIds.map(() => "?").join(",");
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
660
|
+
if (this.sharingRole === "hub") {
|
|
661
|
+
const sharedRows = db.prepare(`SELECT source_chunk_id, visibility, group_id FROM hub_memories WHERE source_chunk_id IN (${placeholders})`).all(...chunkIds);
|
|
662
|
+
for (const r of sharedRows)
|
|
663
|
+
sharingMap.set(r.source_chunk_id, r);
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
const teamMetaRows = db.prepare(`SELECT chunk_id, visibility, group_id FROM team_shared_chunks WHERE chunk_id IN (${placeholders})`).all(...chunkIds);
|
|
667
|
+
for (const r of teamMetaRows)
|
|
600
668
|
sharingMap.set(r.chunk_id, { visibility: r.visibility, group_id: r.group_id });
|
|
601
|
-
}
|
|
602
669
|
}
|
|
603
670
|
const localRows = db.prepare(`SELECT chunk_id, original_owner, shared_at FROM local_shared_memories WHERE chunk_id IN (${placeholders})`).all(...chunkIds);
|
|
604
671
|
for (const r of localRows)
|
|
@@ -662,7 +729,7 @@ class ViewerServer {
|
|
|
662
729
|
const db = this.store.db;
|
|
663
730
|
const items = tasks.map((t) => {
|
|
664
731
|
const meta = db.prepare("SELECT skill_status, owner FROM tasks WHERE id = ?").get(t.id);
|
|
665
|
-
const
|
|
732
|
+
const hubTask = this.getHubTaskForLocal(t.id);
|
|
666
733
|
return {
|
|
667
734
|
id: t.id,
|
|
668
735
|
sessionKey: t.sessionKey,
|
|
@@ -674,7 +741,7 @@ class ViewerServer {
|
|
|
674
741
|
chunkCount: this.store.countChunksByTask(t.id),
|
|
675
742
|
skillStatus: meta?.skill_status ?? null,
|
|
676
743
|
owner: meta?.owner ?? "agent:main",
|
|
677
|
-
sharingVisibility:
|
|
744
|
+
sharingVisibility: hubTask?.visibility ?? null,
|
|
678
745
|
};
|
|
679
746
|
});
|
|
680
747
|
this.jsonResponse(res, { tasks: items, total, limit, offset });
|
|
@@ -703,7 +770,7 @@ class ViewerServer {
|
|
|
703
770
|
}));
|
|
704
771
|
const db = this.store.db;
|
|
705
772
|
const meta = db.prepare("SELECT skill_status, skill_reason FROM tasks WHERE id = ?").get(taskId);
|
|
706
|
-
const
|
|
773
|
+
const hubTask = this.getHubTaskForLocal(taskId);
|
|
707
774
|
this.jsonResponse(res, {
|
|
708
775
|
id: task.id,
|
|
709
776
|
sessionKey: task.sessionKey,
|
|
@@ -717,9 +784,9 @@ class ViewerServer {
|
|
|
717
784
|
skillStatus: meta?.skill_status ?? null,
|
|
718
785
|
skillReason: meta?.skill_reason ?? null,
|
|
719
786
|
skillLinks,
|
|
720
|
-
sharingVisibility:
|
|
721
|
-
sharingGroupId:
|
|
722
|
-
hubTaskId:
|
|
787
|
+
sharingVisibility: hubTask?.visibility ?? null,
|
|
788
|
+
sharingGroupId: hubTask?.group_id ?? null,
|
|
789
|
+
hubTaskId: hubTask ? true : false,
|
|
723
790
|
});
|
|
724
791
|
}
|
|
725
792
|
serveStats(res, url) {
|
|
@@ -924,10 +991,9 @@ class ViewerServer {
|
|
|
924
991
|
if (visibility) {
|
|
925
992
|
skills = skills.filter(s => s.visibility === visibility);
|
|
926
993
|
}
|
|
927
|
-
const db = this.store.db;
|
|
928
994
|
const enriched = skills.map(s => {
|
|
929
|
-
const
|
|
930
|
-
return { ...s, sharingVisibility:
|
|
995
|
+
const hubSkill = this.getHubSkillForLocal(s.id);
|
|
996
|
+
return { ...s, sharingVisibility: hubSkill?.visibility ?? null };
|
|
931
997
|
});
|
|
932
998
|
this.jsonResponse(res, { skills: enriched });
|
|
933
999
|
}
|
|
@@ -942,10 +1008,9 @@ class ViewerServer {
|
|
|
942
1008
|
const versions = this.store.getSkillVersions(skillId);
|
|
943
1009
|
const relatedTasks = this.store.getTasksBySkill(skillId);
|
|
944
1010
|
const files = node_fs_1.default.existsSync(skill.dirPath) ? this.walkDir(skill.dirPath, skill.dirPath) : [];
|
|
945
|
-
const
|
|
946
|
-
const sharedSkill = db.prepare("SELECT visibility, group_id FROM hub_skills WHERE source_skill_id = ? ORDER BY updated_at DESC LIMIT 1").get(skillId);
|
|
1011
|
+
const hubSkill = this.getHubSkillForLocal(skillId);
|
|
947
1012
|
this.jsonResponse(res, {
|
|
948
|
-
skill: { ...skill, sharingVisibility:
|
|
1013
|
+
skill: { ...skill, sharingVisibility: hubSkill?.visibility ?? null, sharingGroupId: hubSkill?.group_id ?? null },
|
|
949
1014
|
versions: versions.map(v => ({
|
|
950
1015
|
id: v.id,
|
|
951
1016
|
version: v.version,
|
|
@@ -1081,7 +1146,7 @@ class ViewerServer {
|
|
|
1081
1146
|
method: "POST",
|
|
1082
1147
|
body: JSON.stringify({ visibility: "public", groupId: null, metadata: bundle.metadata, bundle: bundle.bundle }),
|
|
1083
1148
|
});
|
|
1084
|
-
if (hubClient.userId) {
|
|
1149
|
+
if (this.sharingRole === "hub" && hubClient.userId) {
|
|
1085
1150
|
const existing = this.store.getHubSkillBySource(hubClient.userId, skillId);
|
|
1086
1151
|
this.store.upsertHubSkill({
|
|
1087
1152
|
id: response?.skillId ?? existing?.id ?? node_crypto_1.default.randomUUID(),
|
|
@@ -1092,6 +1157,15 @@ class ViewerServer {
|
|
|
1092
1157
|
createdAt: existing?.createdAt ?? Date.now(), updatedAt: Date.now(),
|
|
1093
1158
|
});
|
|
1094
1159
|
}
|
|
1160
|
+
else {
|
|
1161
|
+
const conn = this.store.getClientHubConnection();
|
|
1162
|
+
this.store.upsertTeamSharedSkill(skillId, {
|
|
1163
|
+
hubSkillId: String(response?.skillId ?? ""),
|
|
1164
|
+
visibility: "public",
|
|
1165
|
+
groupId: null,
|
|
1166
|
+
hubInstanceId: conn?.hubInstanceId ?? "",
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1095
1169
|
hubSynced = true;
|
|
1096
1170
|
this.log.info(`Skill "${skill.name}" published to Hub`);
|
|
1097
1171
|
}
|
|
@@ -1100,8 +1174,10 @@ class ViewerServer {
|
|
|
1100
1174
|
method: "POST",
|
|
1101
1175
|
body: JSON.stringify({ sourceSkillId: skillId }),
|
|
1102
1176
|
});
|
|
1103
|
-
if (hubClient.userId)
|
|
1177
|
+
if (this.sharingRole === "hub" && hubClient.userId)
|
|
1104
1178
|
this.store.deleteHubSkillBySource(hubClient.userId, skillId);
|
|
1179
|
+
else
|
|
1180
|
+
this.store.deleteTeamSharedSkill(skillId);
|
|
1105
1181
|
hubSynced = true;
|
|
1106
1182
|
this.log.info(`Skill "${skill.name}" unpublished from Hub`);
|
|
1107
1183
|
}
|
|
@@ -1399,7 +1475,8 @@ class ViewerServer {
|
|
|
1399
1475
|
});
|
|
1400
1476
|
}
|
|
1401
1477
|
else if (hubClient.userId) {
|
|
1402
|
-
this.store.
|
|
1478
|
+
const conn = this.store.getClientHubConnection();
|
|
1479
|
+
this.store.upsertTeamSharedChunk(chunkId, { hubMemoryId: memoryId, visibility: "public", groupId: null, hubInstanceId: conn?.hubInstanceId ?? "" });
|
|
1403
1480
|
}
|
|
1404
1481
|
hubSynced = true;
|
|
1405
1482
|
}
|
|
@@ -1415,7 +1492,7 @@ class ViewerServer {
|
|
|
1415
1492
|
await (0, hub_1.hubRequestJson)(hubClient.hubUrl, hubClient.userToken, "/api/v1/hub/memories/unshare", {
|
|
1416
1493
|
method: "POST", body: JSON.stringify({ sourceChunkId: chunkId }),
|
|
1417
1494
|
});
|
|
1418
|
-
if (hubClient.userId)
|
|
1495
|
+
if (this.sharingRole === "hub" && hubClient.userId)
|
|
1419
1496
|
this.store.deleteHubMemoryBySource(hubClient.userId, chunkId);
|
|
1420
1497
|
this.store.deleteTeamSharedChunk(chunkId);
|
|
1421
1498
|
hubSynced = true;
|
|
@@ -1434,7 +1511,7 @@ class ViewerServer {
|
|
|
1434
1511
|
await (0, hub_1.hubRequestJson)(hubClient.hubUrl, hubClient.userToken, "/api/v1/hub/memories/unshare", {
|
|
1435
1512
|
method: "POST", body: JSON.stringify({ sourceChunkId: chunkId }),
|
|
1436
1513
|
});
|
|
1437
|
-
if (hubClient.userId)
|
|
1514
|
+
if (this.sharingRole === "hub" && hubClient.userId)
|
|
1438
1515
|
this.store.deleteHubMemoryBySource(hubClient.userId, chunkId);
|
|
1439
1516
|
this.store.deleteTeamSharedChunk(chunkId);
|
|
1440
1517
|
hubSynced = true;
|
|
@@ -1488,21 +1565,24 @@ class ViewerServer {
|
|
|
1488
1565
|
chunks: chunks.map((c) => ({ id: c.id, hubTaskId: refreshedTask.id, sourceTaskId: refreshedTask.id, sourceChunkId: c.id, role: c.role, content: c.content, summary: c.summary, kind: c.kind, groupId: null, visibility: "public", createdAt: c.createdAt ?? Date.now() })),
|
|
1489
1566
|
}),
|
|
1490
1567
|
});
|
|
1491
|
-
|
|
1568
|
+
const hubTaskId = String(response?.taskId ?? "");
|
|
1569
|
+
if (this.sharingRole === "hub" && hubClient.userId) {
|
|
1492
1570
|
const existing = this.store.getHubTaskBySource(hubClient.userId, taskId);
|
|
1493
1571
|
this.store.upsertHubTask({
|
|
1494
|
-
id:
|
|
1572
|
+
id: hubTaskId || existing?.id || node_crypto_1.default.randomUUID(),
|
|
1495
1573
|
sourceTaskId: taskId, sourceUserId: hubClient.userId, title: refreshedTask.title ?? "",
|
|
1496
1574
|
summary: refreshedTask.summary ?? "", groupId: null, visibility: "public",
|
|
1497
1575
|
createdAt: existing?.createdAt ?? Date.now(), updatedAt: Date.now(),
|
|
1498
1576
|
});
|
|
1499
1577
|
}
|
|
1578
|
+
const conn = this.store.getClientHubConnection();
|
|
1579
|
+
this.store.markTaskShared(taskId, hubTaskId, chunks.length, "public", null, conn?.hubInstanceId ?? "");
|
|
1500
1580
|
hubSynced = true;
|
|
1501
1581
|
}
|
|
1502
1582
|
if (!isLocalShared) {
|
|
1503
1583
|
const originalOwner = task.owner;
|
|
1504
1584
|
const db = this.store.db;
|
|
1505
|
-
db.prepare("INSERT INTO local_shared_tasks (task_id, hub_task_id, original_owner, shared_at) VALUES (?, ?, ?, ?) ON CONFLICT(task_id) DO UPDATE SET original_owner = excluded.original_owner, shared_at = excluded.shared_at").run(taskId, "", originalOwner, Date.now());
|
|
1585
|
+
db.prepare("INSERT INTO local_shared_tasks (task_id, hub_task_id, original_owner, hub_instance_id, shared_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(task_id) DO UPDATE SET original_owner = excluded.original_owner, hub_instance_id = excluded.hub_instance_id, shared_at = excluded.shared_at").run(taskId, "", originalOwner, "", Date.now());
|
|
1506
1586
|
db.prepare("UPDATE tasks SET owner = 'public' WHERE id = ?").run(taskId);
|
|
1507
1587
|
}
|
|
1508
1588
|
}
|
|
@@ -1520,8 +1600,10 @@ class ViewerServer {
|
|
|
1520
1600
|
await (0, hub_1.hubRequestJson)(hubClient.hubUrl, hubClient.userToken, "/api/v1/hub/tasks/unshare", {
|
|
1521
1601
|
method: "POST", body: JSON.stringify({ sourceTaskId: taskId }),
|
|
1522
1602
|
});
|
|
1523
|
-
if (hubClient.userId)
|
|
1603
|
+
if (this.sharingRole === "hub" && hubClient.userId)
|
|
1524
1604
|
this.store.deleteHubTaskBySource(hubClient.userId, taskId);
|
|
1605
|
+
else
|
|
1606
|
+
this.store.downgradeTeamSharedTaskToLocal(taskId);
|
|
1525
1607
|
hubSynced = true;
|
|
1526
1608
|
}
|
|
1527
1609
|
catch (err) {
|
|
@@ -1535,8 +1617,10 @@ class ViewerServer {
|
|
|
1535
1617
|
await (0, hub_1.hubRequestJson)(hubClient.hubUrl, hubClient.userToken, "/api/v1/hub/tasks/unshare", {
|
|
1536
1618
|
method: "POST", body: JSON.stringify({ sourceTaskId: taskId }),
|
|
1537
1619
|
});
|
|
1538
|
-
if (hubClient.userId)
|
|
1620
|
+
if (this.sharingRole === "hub" && hubClient.userId)
|
|
1539
1621
|
this.store.deleteHubTaskBySource(hubClient.userId, taskId);
|
|
1622
|
+
else if (!isLocalShared)
|
|
1623
|
+
this.store.unmarkTaskShared(taskId);
|
|
1540
1624
|
hubSynced = true;
|
|
1541
1625
|
}
|
|
1542
1626
|
catch (err) {
|
|
@@ -1591,10 +1675,11 @@ class ViewerServer {
|
|
|
1591
1675
|
method: "POST",
|
|
1592
1676
|
body: JSON.stringify({ visibility: "public", groupId: null, metadata: bundle.metadata, bundle: bundle.bundle }),
|
|
1593
1677
|
});
|
|
1594
|
-
|
|
1678
|
+
const hubSkillId = String(response?.skillId ?? "");
|
|
1679
|
+
if (this.sharingRole === "hub" && hubClient.userId) {
|
|
1595
1680
|
const existing = this.store.getHubSkillBySource(hubClient.userId, skillId);
|
|
1596
1681
|
this.store.upsertHubSkill({
|
|
1597
|
-
id:
|
|
1682
|
+
id: hubSkillId || existing?.id || node_crypto_1.default.randomUUID(),
|
|
1598
1683
|
sourceSkillId: skillId, sourceUserId: hubClient.userId,
|
|
1599
1684
|
name: skill.name, description: skill.description, version: skill.version,
|
|
1600
1685
|
groupId: null, visibility: "public",
|
|
@@ -1602,6 +1687,10 @@ class ViewerServer {
|
|
|
1602
1687
|
createdAt: existing?.createdAt ?? Date.now(), updatedAt: Date.now(),
|
|
1603
1688
|
});
|
|
1604
1689
|
}
|
|
1690
|
+
else {
|
|
1691
|
+
const conn = this.store.getClientHubConnection();
|
|
1692
|
+
this.store.upsertTeamSharedSkill(skillId, { hubSkillId, visibility: "public", groupId: null, hubInstanceId: conn?.hubInstanceId ?? "" });
|
|
1693
|
+
}
|
|
1605
1694
|
hubSynced = true;
|
|
1606
1695
|
}
|
|
1607
1696
|
if (!isLocalShared)
|
|
@@ -1617,8 +1706,10 @@ class ViewerServer {
|
|
|
1617
1706
|
await (0, hub_1.hubRequestJson)(hubClient.hubUrl, hubClient.userToken, "/api/v1/hub/skills/unpublish", {
|
|
1618
1707
|
method: "POST", body: JSON.stringify({ sourceSkillId: skillId }),
|
|
1619
1708
|
});
|
|
1620
|
-
if (hubClient.userId)
|
|
1709
|
+
if (this.sharingRole === "hub" && hubClient.userId)
|
|
1621
1710
|
this.store.deleteHubSkillBySource(hubClient.userId, skillId);
|
|
1711
|
+
else
|
|
1712
|
+
this.store.deleteTeamSharedSkill(skillId);
|
|
1622
1713
|
hubSynced = true;
|
|
1623
1714
|
}
|
|
1624
1715
|
catch (err) {
|
|
@@ -1632,8 +1723,10 @@ class ViewerServer {
|
|
|
1632
1723
|
await (0, hub_1.hubRequestJson)(hubClient.hubUrl, hubClient.userToken, "/api/v1/hub/skills/unpublish", {
|
|
1633
1724
|
method: "POST", body: JSON.stringify({ sourceSkillId: skillId }),
|
|
1634
1725
|
});
|
|
1635
|
-
if (hubClient.userId)
|
|
1726
|
+
if (this.sharingRole === "hub" && hubClient.userId)
|
|
1636
1727
|
this.store.deleteHubSkillBySource(hubClient.userId, skillId);
|
|
1728
|
+
else
|
|
1729
|
+
this.store.deleteTeamSharedSkill(skillId);
|
|
1637
1730
|
hubSynced = true;
|
|
1638
1731
|
}
|
|
1639
1732
|
catch (err) {
|
|
@@ -1650,28 +1743,52 @@ class ViewerServer {
|
|
|
1650
1743
|
}
|
|
1651
1744
|
});
|
|
1652
1745
|
}
|
|
1746
|
+
get sharingRole() {
|
|
1747
|
+
return this.ctx?.config?.sharing?.role;
|
|
1748
|
+
}
|
|
1749
|
+
isCurrentClientHubInstance(hubInstanceId) {
|
|
1750
|
+
if (this.sharingRole !== "client")
|
|
1751
|
+
return true;
|
|
1752
|
+
const scopedHubInstanceId = String(hubInstanceId ?? "");
|
|
1753
|
+
if (!scopedHubInstanceId)
|
|
1754
|
+
return true;
|
|
1755
|
+
const currentHubInstanceId = this.store.getClientHubConnection()?.hubInstanceId ?? "";
|
|
1756
|
+
if (!currentHubInstanceId)
|
|
1757
|
+
return true;
|
|
1758
|
+
return scopedHubInstanceId === currentHubInstanceId;
|
|
1759
|
+
}
|
|
1653
1760
|
getHubMemoryForChunk(chunkId) {
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1761
|
+
if (this.sharingRole === "hub") {
|
|
1762
|
+
const db = this.store.db;
|
|
1763
|
+
return db.prepare("SELECT * FROM hub_memories WHERE source_chunk_id = ? LIMIT 1").get(chunkId);
|
|
1764
|
+
}
|
|
1658
1765
|
const ts = this.store.getTeamSharedChunk(chunkId);
|
|
1659
|
-
if (ts) {
|
|
1660
|
-
return {
|
|
1661
|
-
source_chunk_id: chunkId,
|
|
1662
|
-
visibility: ts.visibility,
|
|
1663
|
-
group_id: ts.groupId,
|
|
1664
|
-
};
|
|
1766
|
+
if (ts && this.isCurrentClientHubInstance(ts.hubInstanceId)) {
|
|
1767
|
+
return { source_chunk_id: chunkId, visibility: ts.visibility, group_id: ts.groupId };
|
|
1665
1768
|
}
|
|
1666
1769
|
return undefined;
|
|
1667
1770
|
}
|
|
1668
1771
|
getHubTaskForLocal(taskId) {
|
|
1669
|
-
|
|
1670
|
-
|
|
1772
|
+
if (this.sharingRole === "hub") {
|
|
1773
|
+
const db = this.store.db;
|
|
1774
|
+
return db.prepare("SELECT * FROM hub_tasks WHERE source_task_id = ? LIMIT 1").get(taskId);
|
|
1775
|
+
}
|
|
1776
|
+
const shared = this.store.getLocalSharedTask(taskId);
|
|
1777
|
+
if (shared && shared.hubTaskId && this.isCurrentClientHubInstance(shared.hubInstanceId)) {
|
|
1778
|
+
return { source_task_id: taskId, visibility: shared.visibility, group_id: shared.groupId };
|
|
1779
|
+
}
|
|
1780
|
+
return undefined;
|
|
1671
1781
|
}
|
|
1672
1782
|
getHubSkillForLocal(skillId) {
|
|
1673
|
-
|
|
1674
|
-
|
|
1783
|
+
if (this.sharingRole === "hub") {
|
|
1784
|
+
const db = this.store.db;
|
|
1785
|
+
return db.prepare("SELECT * FROM hub_skills WHERE source_skill_id = ? LIMIT 1").get(skillId);
|
|
1786
|
+
}
|
|
1787
|
+
const ts = this.store.getTeamSharedSkill(skillId);
|
|
1788
|
+
if (ts && this.isCurrentClientHubInstance(ts.hubInstanceId)) {
|
|
1789
|
+
return { source_skill_id: skillId, visibility: ts.visibility, group_id: ts.groupId };
|
|
1790
|
+
}
|
|
1791
|
+
return undefined;
|
|
1675
1792
|
}
|
|
1676
1793
|
handleDeleteSession(res, url) {
|
|
1677
1794
|
const key = url.searchParams.get("key");
|
|
@@ -1996,6 +2113,12 @@ class ViewerServer {
|
|
|
1996
2113
|
body: JSON.stringify({ teamToken, username, deviceName: hostname, reapply: true, identityKey: existingIdentityKey }),
|
|
1997
2114
|
});
|
|
1998
2115
|
const returnedIdentityKey = String(result.identityKey || existingIdentityKey || "");
|
|
2116
|
+
let hubInstanceId = persisted?.hubInstanceId || "";
|
|
2117
|
+
try {
|
|
2118
|
+
const info = await (0, hub_1.hubRequestJson)(hubUrl, "", "/api/v1/hub/info", { method: "GET" });
|
|
2119
|
+
hubInstanceId = String(info?.hubInstanceId ?? hubInstanceId);
|
|
2120
|
+
}
|
|
2121
|
+
catch { /* best-effort */ }
|
|
1999
2122
|
this.store.setClientHubConnection({
|
|
2000
2123
|
hubUrl,
|
|
2001
2124
|
userId: String(result.userId || ""),
|
|
@@ -2005,6 +2128,7 @@ class ViewerServer {
|
|
|
2005
2128
|
connectedAt: Date.now(),
|
|
2006
2129
|
identityKey: returnedIdentityKey,
|
|
2007
2130
|
lastKnownStatus: result.status || "",
|
|
2131
|
+
hubInstanceId,
|
|
2008
2132
|
});
|
|
2009
2133
|
this.jsonResponse(res, { ok: true, status: result.status || "pending" });
|
|
2010
2134
|
}
|
|
@@ -2227,9 +2351,10 @@ class ViewerServer {
|
|
|
2227
2351
|
}),
|
|
2228
2352
|
});
|
|
2229
2353
|
const hubUserId = hubClient.userId;
|
|
2230
|
-
|
|
2354
|
+
const hubTaskId = String(response?.taskId ?? task.id);
|
|
2355
|
+
if (this.sharingRole === "hub" && hubUserId) {
|
|
2231
2356
|
this.store.upsertHubTask({
|
|
2232
|
-
id:
|
|
2357
|
+
id: hubTaskId,
|
|
2233
2358
|
sourceTaskId: task.id,
|
|
2234
2359
|
sourceUserId: hubUserId,
|
|
2235
2360
|
title: task.title,
|
|
@@ -2240,6 +2365,10 @@ class ViewerServer {
|
|
|
2240
2365
|
updatedAt: task.updatedAt ?? Date.now(),
|
|
2241
2366
|
});
|
|
2242
2367
|
}
|
|
2368
|
+
else {
|
|
2369
|
+
const conn = this.store.getClientHubConnection();
|
|
2370
|
+
this.store.markTaskShared(task.id, hubTaskId, chunks.length, visibility, groupId, conn?.hubInstanceId ?? "");
|
|
2371
|
+
}
|
|
2243
2372
|
this.jsonResponse(res, { ok: true, taskId, visibility, response });
|
|
2244
2373
|
}
|
|
2245
2374
|
catch (err) {
|
|
@@ -2263,8 +2392,12 @@ class ViewerServer {
|
|
|
2263
2392
|
body: JSON.stringify({ sourceTaskId: task.id }),
|
|
2264
2393
|
});
|
|
2265
2394
|
const hubUserId = hubClient.userId;
|
|
2266
|
-
if (hubUserId)
|
|
2395
|
+
if (this.sharingRole === "hub" && hubUserId)
|
|
2267
2396
|
this.store.deleteHubTaskBySource(hubUserId, task.id);
|
|
2397
|
+
else if (task.owner === "public")
|
|
2398
|
+
this.store.downgradeTeamSharedTaskToLocal(task.id);
|
|
2399
|
+
else
|
|
2400
|
+
this.store.unmarkTaskShared(task.id);
|
|
2268
2401
|
this.jsonResponse(res, { ok: true, taskId });
|
|
2269
2402
|
}
|
|
2270
2403
|
catch (err) {
|
|
@@ -2319,7 +2452,8 @@ class ViewerServer {
|
|
|
2319
2452
|
});
|
|
2320
2453
|
}
|
|
2321
2454
|
else if (hubClient.userId) {
|
|
2322
|
-
this.store.
|
|
2455
|
+
const conn = this.store.getClientHubConnection();
|
|
2456
|
+
this.store.upsertTeamSharedChunk(chunk.id, { hubMemoryId: mid, visibility, groupId, hubInstanceId: conn?.hubInstanceId ?? "" });
|
|
2323
2457
|
}
|
|
2324
2458
|
this.jsonResponse(res, { ok: true, chunkId, visibility, response });
|
|
2325
2459
|
}
|
|
@@ -2341,9 +2475,10 @@ class ViewerServer {
|
|
|
2341
2475
|
body: JSON.stringify({ sourceChunkId: chunkId }),
|
|
2342
2476
|
});
|
|
2343
2477
|
const hubUserId = hubClient.userId;
|
|
2344
|
-
if (hubUserId)
|
|
2478
|
+
if (this.sharingRole === "hub" && hubUserId)
|
|
2345
2479
|
this.store.deleteHubMemoryBySource(hubUserId, chunkId);
|
|
2346
|
-
|
|
2480
|
+
else
|
|
2481
|
+
this.store.deleteTeamSharedChunk(chunkId);
|
|
2347
2482
|
this.jsonResponse(res, { ok: true, chunkId });
|
|
2348
2483
|
}
|
|
2349
2484
|
catch (err) {
|
|
@@ -2391,7 +2526,7 @@ class ViewerServer {
|
|
|
2391
2526
|
}),
|
|
2392
2527
|
});
|
|
2393
2528
|
const hubUserId = hubClient.userId;
|
|
2394
|
-
if (hubUserId) {
|
|
2529
|
+
if (this.sharingRole === "hub" && hubUserId) {
|
|
2395
2530
|
const existing = this.store.getHubSkillBySource(hubUserId, skillId);
|
|
2396
2531
|
this.store.upsertHubSkill({
|
|
2397
2532
|
id: response?.skillId ?? existing?.id ?? node_crypto_1.default.randomUUID(),
|
|
@@ -2408,6 +2543,15 @@ class ViewerServer {
|
|
|
2408
2543
|
updatedAt: Date.now(),
|
|
2409
2544
|
});
|
|
2410
2545
|
}
|
|
2546
|
+
else {
|
|
2547
|
+
const conn = this.store.getClientHubConnection();
|
|
2548
|
+
this.store.upsertTeamSharedSkill(skillId, {
|
|
2549
|
+
hubSkillId: String(response?.skillId ?? ""),
|
|
2550
|
+
visibility,
|
|
2551
|
+
groupId,
|
|
2552
|
+
hubInstanceId: conn?.hubInstanceId ?? "",
|
|
2553
|
+
});
|
|
2554
|
+
}
|
|
2411
2555
|
this.jsonResponse(res, { ok: true, skillId, visibility, response });
|
|
2412
2556
|
}
|
|
2413
2557
|
catch (err) {
|
|
@@ -2431,8 +2575,10 @@ class ViewerServer {
|
|
|
2431
2575
|
body: JSON.stringify({ sourceSkillId: skill.id }),
|
|
2432
2576
|
});
|
|
2433
2577
|
const hubUserId = hubClient.userId;
|
|
2434
|
-
if (hubUserId)
|
|
2578
|
+
if (this.sharingRole === "hub" && hubUserId)
|
|
2435
2579
|
this.store.deleteHubSkillBySource(hubUserId, skill.id);
|
|
2580
|
+
else
|
|
2581
|
+
this.store.deleteTeamSharedSkill(skill.id);
|
|
2436
2582
|
this.jsonResponse(res, { ok: true, skillId });
|
|
2437
2583
|
}
|
|
2438
2584
|
catch (err) {
|
|
@@ -2939,18 +3085,20 @@ class ViewerServer {
|
|
|
2939
3085
|
const isClient = newEnabled && newRole === "client";
|
|
2940
3086
|
if (wasClient && !isClient) {
|
|
2941
3087
|
await this.withdrawOrLeaveHub();
|
|
3088
|
+
this.store.clearAllTeamSharingState();
|
|
2942
3089
|
this.store.clearClientHubConnection();
|
|
2943
|
-
this.log.info("Client hub connection cleared (sharing disabled or role changed)");
|
|
3090
|
+
this.log.info("Client hub connection and team sharing state cleared (sharing disabled or role changed)");
|
|
2944
3091
|
}
|
|
2945
3092
|
if (wasClient && isClient) {
|
|
2946
3093
|
const newClientAddr = String(merged.client?.hubAddress || "");
|
|
2947
3094
|
if (newClientAddr && oldClientHubAddress && (0, hub_1.normalizeHubUrl)(newClientAddr) !== (0, hub_1.normalizeHubUrl)(oldClientHubAddress)) {
|
|
2948
3095
|
this.notifyHubLeave();
|
|
3096
|
+
this.store.clearAllTeamSharingState();
|
|
2949
3097
|
const oldConn = this.store.getClientHubConnection();
|
|
2950
3098
|
if (oldConn) {
|
|
2951
|
-
this.store.setClientHubConnection({ ...oldConn, hubUrl: (0, hub_1.normalizeHubUrl)(newClientAddr), userToken: "", lastKnownStatus: "hub_changed" });
|
|
3099
|
+
this.store.setClientHubConnection({ ...oldConn, hubUrl: (0, hub_1.normalizeHubUrl)(newClientAddr), userToken: "", hubInstanceId: "", lastKnownStatus: "hub_changed" });
|
|
2952
3100
|
}
|
|
2953
|
-
this.log.info("Client hub connection
|
|
3101
|
+
this.log.info("Client hub connection and team sharing state cleared (switched to different Hub)");
|
|
2954
3102
|
}
|
|
2955
3103
|
}
|
|
2956
3104
|
if (merged.role === "hub") {
|
|
@@ -3014,6 +3162,12 @@ class ViewerServer {
|
|
|
3014
3162
|
body: JSON.stringify({ teamToken, username, deviceName: hostname, identityKey: existingIdentityKey }),
|
|
3015
3163
|
});
|
|
3016
3164
|
const returnedIdentityKey = String(result.identityKey || existingIdentityKey || "");
|
|
3165
|
+
let hubInstanceId = persisted?.hubInstanceId || "";
|
|
3166
|
+
try {
|
|
3167
|
+
const info = await (0, hub_1.hubRequestJson)(hubUrl, "", "/api/v1/hub/info", { method: "GET" });
|
|
3168
|
+
hubInstanceId = String(info?.hubInstanceId ?? hubInstanceId);
|
|
3169
|
+
}
|
|
3170
|
+
catch { /* best-effort */ }
|
|
3017
3171
|
this.store.setClientHubConnection({
|
|
3018
3172
|
hubUrl,
|
|
3019
3173
|
userId: String(result.userId || ""),
|
|
@@ -3023,6 +3177,7 @@ class ViewerServer {
|
|
|
3023
3177
|
connectedAt: Date.now(),
|
|
3024
3178
|
identityKey: returnedIdentityKey,
|
|
3025
3179
|
lastKnownStatus: result.status || "",
|
|
3180
|
+
hubInstanceId,
|
|
3026
3181
|
});
|
|
3027
3182
|
this.log.info(`Auto-join on save: status=${result.status}, userId=${result.userId}`);
|
|
3028
3183
|
if (result.userToken) {
|
|
@@ -3034,6 +3189,7 @@ class ViewerServer {
|
|
|
3034
3189
|
this.readBody(_req, async () => {
|
|
3035
3190
|
try {
|
|
3036
3191
|
await this.withdrawOrLeaveHub();
|
|
3192
|
+
this.store.clearAllTeamSharingState();
|
|
3037
3193
|
this.store.clearClientHubConnection();
|
|
3038
3194
|
const configPath = this.getOpenClawConfigPath();
|
|
3039
3195
|
if (configPath && node_fs_1.default.existsSync(configPath)) {
|
|
@@ -3445,7 +3601,8 @@ class ViewerServer {
|
|
|
3445
3601
|
node_fs_1.default.renameSync(srcDir, extDir);
|
|
3446
3602
|
// Install dependencies
|
|
3447
3603
|
this.log.info(`update-install: installing dependencies...`);
|
|
3448
|
-
|
|
3604
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
3605
|
+
(0, node_child_process_1.execFile)(npmCmd, ["install", "--omit=dev", "--ignore-scripts"], { cwd: extDir, timeout: 120_000 }, (npmErr, npmOut, npmStderr) => {
|
|
3449
3606
|
if (npmErr) {
|
|
3450
3607
|
try {
|
|
3451
3608
|
node_fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
@@ -3455,18 +3612,15 @@ class ViewerServer {
|
|
|
3455
3612
|
this.jsonResponse(res, { ok: false, error: `Dependency install failed: ${npmStderr || npmErr.message}` });
|
|
3456
3613
|
return;
|
|
3457
3614
|
}
|
|
3458
|
-
|
|
3459
|
-
(0, node_child_process_1.exec)(`cd ${extDir} && npm rebuild better-sqlite3`, { timeout: 60_000 }, (rebuildErr, rebuildOut, rebuildStderr) => {
|
|
3615
|
+
(0, node_child_process_1.execFile)(npmCmd, ["rebuild", "better-sqlite3"], { cwd: extDir, timeout: 60_000 }, (rebuildErr, rebuildOut, rebuildStderr) => {
|
|
3460
3616
|
if (rebuildErr) {
|
|
3461
3617
|
this.log.warn(`update-install: better-sqlite3 rebuild failed: ${rebuildErr.message}`);
|
|
3462
3618
|
const stderr = String(rebuildStderr || "").trim();
|
|
3463
3619
|
if (stderr)
|
|
3464
3620
|
this.log.warn(`update-install: rebuild stderr: ${stderr.slice(0, 500)}`);
|
|
3465
|
-
// Continue so postinstall.cjs can run (it will try rebuild again and show user guidance)
|
|
3466
3621
|
}
|
|
3467
|
-
// Run postinstall.cjs: legacy cleanup, skill install, version marker, and optional sqlite re-check
|
|
3468
3622
|
this.log.info(`update-install: running postinstall...`);
|
|
3469
|
-
(0, node_child_process_1.
|
|
3623
|
+
(0, node_child_process_1.execFile)(process.execPath, ["scripts/postinstall.cjs"], { cwd: extDir, timeout: 180_000 }, (postErr, postOut, postStderr) => {
|
|
3470
3624
|
try {
|
|
3471
3625
|
node_fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
3472
3626
|
}
|
|
@@ -3476,7 +3630,6 @@ class ViewerServer {
|
|
|
3476
3630
|
const postStderrStr = String(postStderr || "").trim();
|
|
3477
3631
|
if (postStderrStr)
|
|
3478
3632
|
this.log.warn(`update-install: postinstall stderr: ${postStderrStr.slice(0, 500)}`);
|
|
3479
|
-
// Still report success; plugin is updated, user can run postinstall manually if needed
|
|
3480
3633
|
}
|
|
3481
3634
|
// Read new version
|
|
3482
3635
|
let newVersion = "unknown";
|
|
@@ -3833,7 +3986,7 @@ class ViewerServer {
|
|
|
3833
3986
|
else if (this.migrationState.done) {
|
|
3834
3987
|
const evtName = this.migrationState.stopped ? "stopped" : "done";
|
|
3835
3988
|
res.write(`event: state\ndata: ${JSON.stringify(this.migrationState)}\n\n`);
|
|
3836
|
-
res.write(`event: ${evtName}\ndata: ${JSON.stringify({ ok:
|
|
3989
|
+
res.write(`event: ${evtName}\ndata: ${JSON.stringify({ ok: this.migrationState.success, ...this.migrationState })}\n\n`);
|
|
3837
3990
|
res.end();
|
|
3838
3991
|
}
|
|
3839
3992
|
else {
|
|
@@ -3872,22 +4025,11 @@ class ViewerServer {
|
|
|
3872
4025
|
res.on("close", () => {
|
|
3873
4026
|
this.migrationSSEClients = this.migrationSSEClients.filter(c => c !== res);
|
|
3874
4027
|
});
|
|
3875
|
-
this.
|
|
3876
|
-
this.migrationState = { phase: "", stored: 0, skipped: 0, merged: 0, errors: 0, processed: 0, total: 0, lastItem: null, done: false, stopped: false };
|
|
4028
|
+
this.migrationState = createInitialMigrationState();
|
|
3877
4029
|
const send = (event, data) => {
|
|
3878
4030
|
if (event === "item") {
|
|
3879
4031
|
const d = data;
|
|
3880
|
-
|
|
3881
|
-
this.migrationState.stored++;
|
|
3882
|
-
else if (d.status === "skipped" || d.status === "duplicate")
|
|
3883
|
-
this.migrationState.skipped++;
|
|
3884
|
-
else if (d.status === "merged")
|
|
3885
|
-
this.migrationState.merged++;
|
|
3886
|
-
else if (d.status === "error")
|
|
3887
|
-
this.migrationState.errors++;
|
|
3888
|
-
this.migrationState.processed = d.index ?? this.migrationState.processed + 1;
|
|
3889
|
-
this.migrationState.total = d.total ?? this.migrationState.total;
|
|
3890
|
-
this.migrationState.lastItem = d;
|
|
4032
|
+
applyMigrationItemToState(this.migrationState, d);
|
|
3891
4033
|
}
|
|
3892
4034
|
else if (event === "phase") {
|
|
3893
4035
|
this.migrationState.phase = data.phase;
|
|
@@ -3901,12 +4043,14 @@ class ViewerServer {
|
|
|
3901
4043
|
this.runMigration(send, opts.sources, concurrency).finally(() => {
|
|
3902
4044
|
this.migrationRunning = false;
|
|
3903
4045
|
this.migrationState.done = true;
|
|
4046
|
+
this.migrationState.success = computeMigrationSuccess(this.migrationState);
|
|
4047
|
+
const donePayload = { ok: this.migrationState.success, ...this.migrationState };
|
|
3904
4048
|
if (this.migrationAbort) {
|
|
3905
4049
|
this.migrationState.stopped = true;
|
|
3906
|
-
this.broadcastSSE("stopped",
|
|
4050
|
+
this.broadcastSSE("stopped", donePayload);
|
|
3907
4051
|
}
|
|
3908
4052
|
else {
|
|
3909
|
-
this.broadcastSSE("done",
|
|
4053
|
+
this.broadcastSSE("done", donePayload);
|
|
3910
4054
|
}
|
|
3911
4055
|
this.migrationAbort = false;
|
|
3912
4056
|
const clientsToClose = [...this.migrationSSEClients];
|
|
@@ -3992,12 +4136,25 @@ class ViewerServer {
|
|
|
3992
4136
|
continue;
|
|
3993
4137
|
}
|
|
3994
4138
|
try {
|
|
3995
|
-
const
|
|
4139
|
+
const stepFailures = [];
|
|
4140
|
+
let summary = "";
|
|
4141
|
+
try {
|
|
4142
|
+
summary = await summarizer.summarize(row.text);
|
|
4143
|
+
}
|
|
4144
|
+
catch (err) {
|
|
4145
|
+
stepFailures.push("summarization");
|
|
4146
|
+
this.log.warn(`Migration summarization failed: ${err}`);
|
|
4147
|
+
}
|
|
4148
|
+
if (!summary) {
|
|
4149
|
+
stepFailures.push("summarization");
|
|
4150
|
+
summary = row.text.slice(0, 200);
|
|
4151
|
+
}
|
|
3996
4152
|
let embedding = null;
|
|
3997
4153
|
try {
|
|
3998
4154
|
[embedding] = await this.embedder.embed([summary]);
|
|
3999
4155
|
}
|
|
4000
4156
|
catch (err) {
|
|
4157
|
+
stepFailures.push("embedding");
|
|
4001
4158
|
this.log.warn(`Migration embed failed: ${err}`);
|
|
4002
4159
|
}
|
|
4003
4160
|
let dedupStatus = "active";
|
|
@@ -4013,30 +4170,36 @@ class ViewerServer {
|
|
|
4013
4170
|
return { index: idx + 1, summary: chunk?.summary ?? "", chunkId: s.chunkId };
|
|
4014
4171
|
}).filter(c => c.summary);
|
|
4015
4172
|
if (candidates.length > 0) {
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4173
|
+
try {
|
|
4174
|
+
const dedupResult = await summarizer.judgeDedup(summary, candidates);
|
|
4175
|
+
if (dedupResult?.action === "DUPLICATE" && dedupResult.targetIndex) {
|
|
4176
|
+
const targetId = candidates[dedupResult.targetIndex - 1]?.chunkId;
|
|
4177
|
+
if (targetId) {
|
|
4178
|
+
dedupStatus = "duplicate";
|
|
4179
|
+
dedupTarget = targetId;
|
|
4180
|
+
dedupReason = dedupResult.reason;
|
|
4181
|
+
}
|
|
4023
4182
|
}
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4183
|
+
else if (dedupResult?.action === "UPDATE" && dedupResult.targetIndex && dedupResult.mergedSummary) {
|
|
4184
|
+
const targetId = candidates[dedupResult.targetIndex - 1]?.chunkId;
|
|
4185
|
+
if (targetId) {
|
|
4186
|
+
this.store.updateChunkSummaryAndContent(targetId, dedupResult.mergedSummary, row.text);
|
|
4187
|
+
try {
|
|
4188
|
+
const [newEmb] = await this.embedder.embed([dedupResult.mergedSummary]);
|
|
4189
|
+
if (newEmb)
|
|
4190
|
+
this.store.upsertEmbedding(targetId, newEmb);
|
|
4191
|
+
}
|
|
4192
|
+
catch { /* best-effort */ }
|
|
4193
|
+
dedupStatus = "merged";
|
|
4194
|
+
dedupTarget = targetId;
|
|
4195
|
+
dedupReason = dedupResult.reason;
|
|
4033
4196
|
}
|
|
4034
|
-
catch { /* best-effort */ }
|
|
4035
|
-
dedupStatus = "merged";
|
|
4036
|
-
dedupTarget = targetId;
|
|
4037
|
-
dedupReason = dedupResult.reason;
|
|
4038
4197
|
}
|
|
4039
4198
|
}
|
|
4199
|
+
catch (err) {
|
|
4200
|
+
stepFailures.push("dedup");
|
|
4201
|
+
this.log.warn(`Migration dedup judgment failed: ${err}`);
|
|
4202
|
+
}
|
|
4040
4203
|
}
|
|
4041
4204
|
}
|
|
4042
4205
|
}
|
|
@@ -4075,7 +4238,14 @@ class ViewerServer {
|
|
|
4075
4238
|
preview: row.text.slice(0, 120),
|
|
4076
4239
|
summary: summary.slice(0, 80),
|
|
4077
4240
|
source: file,
|
|
4241
|
+
stepFailures,
|
|
4078
4242
|
});
|
|
4243
|
+
if (stepFailures.length > 0) {
|
|
4244
|
+
this.log.warn(`[MIGRATION] sqlite item imported with step failures: ${stepFailures.join(",")}`);
|
|
4245
|
+
}
|
|
4246
|
+
else {
|
|
4247
|
+
this.log.info("[MIGRATION] sqlite item imported successfully (all steps)");
|
|
4248
|
+
}
|
|
4079
4249
|
}
|
|
4080
4250
|
catch (err) {
|
|
4081
4251
|
totalErrors++;
|
|
@@ -4216,12 +4386,25 @@ class ViewerServer {
|
|
|
4216
4386
|
continue;
|
|
4217
4387
|
}
|
|
4218
4388
|
try {
|
|
4219
|
-
const
|
|
4389
|
+
const stepFailures = [];
|
|
4390
|
+
let summary = "";
|
|
4391
|
+
try {
|
|
4392
|
+
summary = await summarizer.summarize(content);
|
|
4393
|
+
}
|
|
4394
|
+
catch (err) {
|
|
4395
|
+
stepFailures.push("summarization");
|
|
4396
|
+
this.log.warn(`Migration summarization failed: ${err}`);
|
|
4397
|
+
}
|
|
4398
|
+
if (!summary) {
|
|
4399
|
+
stepFailures.push("summarization");
|
|
4400
|
+
summary = content.slice(0, 200);
|
|
4401
|
+
}
|
|
4220
4402
|
let embedding = null;
|
|
4221
4403
|
try {
|
|
4222
4404
|
[embedding] = await this.embedder.embed([summary]);
|
|
4223
4405
|
}
|
|
4224
4406
|
catch (err) {
|
|
4407
|
+
stepFailures.push("embedding");
|
|
4225
4408
|
this.log.warn(`Migration embed failed: ${err}`);
|
|
4226
4409
|
}
|
|
4227
4410
|
let dedupStatus = "active";
|
|
@@ -4237,30 +4420,36 @@ class ViewerServer {
|
|
|
4237
4420
|
return { index: i + 1, summary: chunk?.summary ?? "", chunkId: s.chunkId };
|
|
4238
4421
|
}).filter(c => c.summary);
|
|
4239
4422
|
if (candidates.length > 0) {
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4423
|
+
try {
|
|
4424
|
+
const dedupResult = await summarizer.judgeDedup(summary, candidates);
|
|
4425
|
+
if (dedupResult?.action === "DUPLICATE" && dedupResult.targetIndex) {
|
|
4426
|
+
const targetId = candidates[dedupResult.targetIndex - 1]?.chunkId;
|
|
4427
|
+
if (targetId) {
|
|
4428
|
+
dedupStatus = "duplicate";
|
|
4429
|
+
dedupTarget = targetId;
|
|
4430
|
+
dedupReason = dedupResult.reason;
|
|
4431
|
+
}
|
|
4247
4432
|
}
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4433
|
+
else if (dedupResult?.action === "UPDATE" && dedupResult.targetIndex && dedupResult.mergedSummary) {
|
|
4434
|
+
const targetId = candidates[dedupResult.targetIndex - 1]?.chunkId;
|
|
4435
|
+
if (targetId) {
|
|
4436
|
+
this.store.updateChunkSummaryAndContent(targetId, dedupResult.mergedSummary, content);
|
|
4437
|
+
try {
|
|
4438
|
+
const [newEmb] = await this.embedder.embed([dedupResult.mergedSummary]);
|
|
4439
|
+
if (newEmb)
|
|
4440
|
+
this.store.upsertEmbedding(targetId, newEmb);
|
|
4441
|
+
}
|
|
4442
|
+
catch { /* best-effort */ }
|
|
4443
|
+
dedupStatus = "merged";
|
|
4444
|
+
dedupTarget = targetId;
|
|
4445
|
+
dedupReason = dedupResult.reason;
|
|
4257
4446
|
}
|
|
4258
|
-
catch { /* best-effort */ }
|
|
4259
|
-
dedupStatus = "merged";
|
|
4260
|
-
dedupTarget = targetId;
|
|
4261
|
-
dedupReason = dedupResult.reason;
|
|
4262
4447
|
}
|
|
4263
4448
|
}
|
|
4449
|
+
catch (err) {
|
|
4450
|
+
stepFailures.push("dedup");
|
|
4451
|
+
this.log.warn(`Migration dedup judgment failed: ${err}`);
|
|
4452
|
+
}
|
|
4264
4453
|
}
|
|
4265
4454
|
}
|
|
4266
4455
|
}
|
|
@@ -4277,7 +4466,13 @@ class ViewerServer {
|
|
|
4277
4466
|
if (embedding && dedupStatus === "active")
|
|
4278
4467
|
this.store.upsertEmbedding(chunkId, embedding);
|
|
4279
4468
|
totalStored++;
|
|
4280
|
-
send("item", { index: idx, total: totalMsgs, status: dedupStatus === "active" ? "stored" : dedupStatus, preview: content.slice(0, 120), summary: summary.slice(0, 80), source: file, agent: agentId, role: msgRole });
|
|
4469
|
+
send("item", { index: idx, total: totalMsgs, status: dedupStatus === "active" ? "stored" : dedupStatus, preview: content.slice(0, 120), summary: summary.slice(0, 80), source: file, agent: agentId, role: msgRole, stepFailures });
|
|
4470
|
+
if (stepFailures.length > 0) {
|
|
4471
|
+
this.log.warn(`[MIGRATION] session item imported with step failures: ${stepFailures.join(",")}`);
|
|
4472
|
+
}
|
|
4473
|
+
else {
|
|
4474
|
+
this.log.info("[MIGRATION] session item imported successfully (all steps)");
|
|
4475
|
+
}
|
|
4281
4476
|
}
|
|
4282
4477
|
catch (err) {
|
|
4283
4478
|
totalErrors++;
|
|
@@ -4320,7 +4515,14 @@ class ViewerServer {
|
|
|
4320
4515
|
}
|
|
4321
4516
|
}
|
|
4322
4517
|
send("progress", { total: totalProcessed, processed: totalProcessed, phase: "done" });
|
|
4323
|
-
send("summary", {
|
|
4518
|
+
send("summary", {
|
|
4519
|
+
totalProcessed,
|
|
4520
|
+
totalStored,
|
|
4521
|
+
totalSkipped,
|
|
4522
|
+
totalErrors,
|
|
4523
|
+
success: computeMigrationSuccess(this.migrationState),
|
|
4524
|
+
stepFailures: this.migrationState.stepFailures,
|
|
4525
|
+
});
|
|
4324
4526
|
}
|
|
4325
4527
|
// ─── Post-processing: independent task/skill generation ───
|
|
4326
4528
|
handlePostprocess(req, res) {
|