@memtensor/memos-local-openclaw-plugin 1.0.4-beta.8 → 1.0.4-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.
- package/dist/client/connector.d.ts.map +1 -1
- package/dist/client/connector.js +45 -4
- package/dist/client/connector.js.map +1 -1
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/server.js +12 -4
- package/dist/hub/server.js.map +1 -1
- package/dist/recall/engine.d.ts.map +1 -1
- package/dist/recall/engine.js +78 -1
- package/dist/recall/engine.js.map +1 -1
- package/dist/storage/sqlite.d.ts +1 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +5 -0
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +282 -114
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +2 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +119 -4
- package/dist/viewer/server.js.map +1 -1
- package/package.json +1 -1
- package/src/client/connector.ts +46 -4
- package/src/hub/server.ts +12 -4
- package/src/recall/engine.ts +73 -1
- package/src/storage/sqlite.ts +8 -0
- package/src/viewer/html.ts +282 -114
- package/src/viewer/server.ts +117 -4
package/src/viewer/server.ts
CHANGED
|
@@ -667,6 +667,12 @@ export class ViewerServer {
|
|
|
667
667
|
owners = ownerRows.map((o: any) => o.owner);
|
|
668
668
|
} catch { /* column may not exist yet */ }
|
|
669
669
|
|
|
670
|
+
let currentAgentOwner = "agent:main";
|
|
671
|
+
try {
|
|
672
|
+
const latest = db.prepare("SELECT owner FROM chunks WHERE owner IS NOT NULL AND owner LIKE 'agent:%' ORDER BY created_at DESC LIMIT 1").get() as any;
|
|
673
|
+
if (latest?.owner) currentAgentOwner = latest.owner;
|
|
674
|
+
} catch { /* best-effort */ }
|
|
675
|
+
|
|
670
676
|
this.jsonResponse(res, {
|
|
671
677
|
totalMemories: total.count, totalSessions: sessions.count, totalEmbeddings: embCount,
|
|
672
678
|
totalSkills: skillCount,
|
|
@@ -675,6 +681,7 @@ export class ViewerServer {
|
|
|
675
681
|
timeRange: { earliest: timeRange.earliest, latest: timeRange.latest },
|
|
676
682
|
sessions: sessionList,
|
|
677
683
|
owners,
|
|
684
|
+
currentAgentOwner,
|
|
678
685
|
});
|
|
679
686
|
} catch (e) {
|
|
680
687
|
this.log.warn(`stats error: ${e}`);
|
|
@@ -1742,13 +1749,21 @@ export class ViewerServer {
|
|
|
1742
1749
|
}
|
|
1743
1750
|
try {
|
|
1744
1751
|
const hubUrl = normalizeHubUrl(hubAddress);
|
|
1752
|
+
const localIPs = this.getLocalIPs();
|
|
1753
|
+
localIPs.push("127.0.0.1", "localhost", "0.0.0.0");
|
|
1754
|
+
try {
|
|
1755
|
+
const u = new URL(hubUrl);
|
|
1756
|
+
if (localIPs.includes(u.hostname)) {
|
|
1757
|
+
return this.jsonResponse(res, { ok: false, error: "cannot_join_self" });
|
|
1758
|
+
}
|
|
1759
|
+
} catch {}
|
|
1745
1760
|
const os = await import("os");
|
|
1746
1761
|
const nickname = sharing.client?.nickname;
|
|
1747
1762
|
const username = nickname || os.userInfo().username || "user";
|
|
1748
1763
|
const hostname = os.hostname() || "unknown";
|
|
1749
1764
|
const result = await hubRequestJson(hubUrl, "", "/api/v1/hub/join", {
|
|
1750
1765
|
method: "POST",
|
|
1751
|
-
body: JSON.stringify({ teamToken, username, deviceName: hostname }),
|
|
1766
|
+
body: JSON.stringify({ teamToken, username, deviceName: hostname, reapply: true }),
|
|
1752
1767
|
}) as any;
|
|
1753
1768
|
this.store.setClientHubConnection({
|
|
1754
1769
|
hubUrl,
|
|
@@ -2526,7 +2541,10 @@ export class ViewerServer {
|
|
|
2526
2541
|
if (!entry.config) entry.config = {};
|
|
2527
2542
|
const config = entry.config as Record<string, unknown>;
|
|
2528
2543
|
|
|
2529
|
-
const
|
|
2544
|
+
const oldSharing = config.sharing as Record<string, unknown> | undefined;
|
|
2545
|
+
const oldSharingRole = oldSharing?.role as string | undefined;
|
|
2546
|
+
const oldSharingEnabled = Boolean(oldSharing?.enabled);
|
|
2547
|
+
const oldClientHubAddress = String((oldSharing?.client as Record<string, unknown>)?.hubAddress || "");
|
|
2530
2548
|
|
|
2531
2549
|
if (newCfg.embedding) config.embedding = newCfg.embedding;
|
|
2532
2550
|
if (newCfg.summarizer) config.summarizer = newCfg.summarizer;
|
|
@@ -2556,10 +2574,35 @@ export class ViewerServer {
|
|
|
2556
2574
|
}
|
|
2557
2575
|
}
|
|
2558
2576
|
|
|
2559
|
-
// When switching away from client mode, notify Hub that we're leaving
|
|
2560
2577
|
const newRole = merged.role as string | undefined;
|
|
2561
|
-
|
|
2578
|
+
const newEnabled = Boolean(merged.enabled);
|
|
2579
|
+
|
|
2580
|
+
// Detect disabling sharing or switching away from hub mode
|
|
2581
|
+
const wasHub = oldSharingEnabled && oldSharingRole === "hub";
|
|
2582
|
+
const isHub = newEnabled && newRole === "hub";
|
|
2583
|
+
if (wasHub && !isHub) {
|
|
2584
|
+
await this.notifyHubShutdown();
|
|
2585
|
+
this.stopHubHeartbeat();
|
|
2586
|
+
this.log.info("Hub shutting down: notified connected clients");
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
// Detect disabling sharing or switching away from client mode
|
|
2590
|
+
const wasClient = oldSharingEnabled && oldSharingRole === "client";
|
|
2591
|
+
const isClient = newEnabled && newRole === "client";
|
|
2592
|
+
if (wasClient && !isClient) {
|
|
2562
2593
|
this.notifyHubLeave();
|
|
2594
|
+
this.store.clearClientHubConnection();
|
|
2595
|
+
this.log.info("Cleared client hub connection (sharing disabled or role changed)");
|
|
2596
|
+
}
|
|
2597
|
+
|
|
2598
|
+
// Detect switching to a different Hub while still in client mode
|
|
2599
|
+
if (wasClient && isClient) {
|
|
2600
|
+
const newClientAddr = String((merged.client as Record<string, unknown>)?.hubAddress || "");
|
|
2601
|
+
if (newClientAddr && oldClientHubAddress && normalizeHubUrl(newClientAddr) !== normalizeHubUrl(oldClientHubAddress)) {
|
|
2602
|
+
this.notifyHubLeave();
|
|
2603
|
+
this.store.clearClientHubConnection();
|
|
2604
|
+
this.log.info("Cleared client hub connection (switched to different Hub)");
|
|
2605
|
+
}
|
|
2563
2606
|
}
|
|
2564
2607
|
|
|
2565
2608
|
if (merged.role === "hub") {
|
|
@@ -2574,6 +2617,13 @@ export class ViewerServer {
|
|
|
2574
2617
|
fs.writeFileSync(cfgPath, JSON.stringify(raw, null, 2), "utf-8");
|
|
2575
2618
|
this.log.info("Plugin config updated via Viewer");
|
|
2576
2619
|
this.stopHubHeartbeat();
|
|
2620
|
+
|
|
2621
|
+
// When switching to client mode, immediately send join request
|
|
2622
|
+
const finalSharing = config.sharing as Record<string, unknown> | undefined;
|
|
2623
|
+
if (finalSharing?.role === "client" && oldSharingRole !== "client") {
|
|
2624
|
+
this.autoJoinOnSave(finalSharing).catch(e => this.log.warn(`Auto-join on save failed: ${e}`));
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2577
2627
|
this.jsonResponse(res, { ok: true });
|
|
2578
2628
|
} catch (e) {
|
|
2579
2629
|
this.log.warn(`handleSaveConfig error: ${e}`);
|
|
@@ -2583,6 +2633,34 @@ export class ViewerServer {
|
|
|
2583
2633
|
});
|
|
2584
2634
|
}
|
|
2585
2635
|
|
|
2636
|
+
private async autoJoinOnSave(sharing: Record<string, unknown>): Promise<void> {
|
|
2637
|
+
const clientCfg = sharing.client as Record<string, unknown> | undefined;
|
|
2638
|
+
const hubAddress = String(clientCfg?.hubAddress || "");
|
|
2639
|
+
const teamToken = String(clientCfg?.teamToken || "");
|
|
2640
|
+
if (!hubAddress || !teamToken) return;
|
|
2641
|
+
const hubUrl = normalizeHubUrl(hubAddress);
|
|
2642
|
+
const os = await import("os");
|
|
2643
|
+
const nickname = String(clientCfg?.nickname || "");
|
|
2644
|
+
const username = nickname || os.userInfo().username || "user";
|
|
2645
|
+
const hostname = os.hostname() || "unknown";
|
|
2646
|
+
const result = await hubRequestJson(hubUrl, "", "/api/v1/hub/join", {
|
|
2647
|
+
method: "POST",
|
|
2648
|
+
body: JSON.stringify({ teamToken, username, deviceName: hostname }),
|
|
2649
|
+
}) as any;
|
|
2650
|
+
this.store.setClientHubConnection({
|
|
2651
|
+
hubUrl,
|
|
2652
|
+
userId: String(result.userId || ""),
|
|
2653
|
+
username,
|
|
2654
|
+
userToken: result.userToken || "",
|
|
2655
|
+
role: "member",
|
|
2656
|
+
connectedAt: Date.now(),
|
|
2657
|
+
});
|
|
2658
|
+
this.log.info(`Auto-join on save: status=${result.status}, userId=${result.userId}`);
|
|
2659
|
+
if (result.userToken) {
|
|
2660
|
+
this.startHubHeartbeat();
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2586
2664
|
private async notifyHubLeave(): Promise<void> {
|
|
2587
2665
|
try {
|
|
2588
2666
|
const hub = this.resolveHubConnection();
|
|
@@ -2601,6 +2679,41 @@ export class ViewerServer {
|
|
|
2601
2679
|
}
|
|
2602
2680
|
}
|
|
2603
2681
|
|
|
2682
|
+
private async notifyHubShutdown(): Promise<void> {
|
|
2683
|
+
try {
|
|
2684
|
+
const sharing = this.ctx?.config.sharing;
|
|
2685
|
+
if (!sharing || sharing.role !== "hub") return;
|
|
2686
|
+
const hubPort = sharing.hub?.port ?? 18800;
|
|
2687
|
+
const authPath = path.join(this.dataDir, "hub-auth.json");
|
|
2688
|
+
let adminToken: string | undefined;
|
|
2689
|
+
try {
|
|
2690
|
+
const authData = JSON.parse(fs.readFileSync(authPath, "utf8"));
|
|
2691
|
+
adminToken = authData?.bootstrapAdminToken;
|
|
2692
|
+
} catch { return; }
|
|
2693
|
+
if (!adminToken) return;
|
|
2694
|
+
|
|
2695
|
+
const users = this.store.listHubUsers("active");
|
|
2696
|
+
const { v4: uuidv4 } = require("uuid");
|
|
2697
|
+
for (const u of users) {
|
|
2698
|
+
try {
|
|
2699
|
+
this.store.insertHubNotification({
|
|
2700
|
+
id: uuidv4(),
|
|
2701
|
+
userId: u.id,
|
|
2702
|
+
type: "hub_shutdown",
|
|
2703
|
+
resource: "hub",
|
|
2704
|
+
title: "Hub is shutting down",
|
|
2705
|
+
message: "The Hub server is shutting down. You may be disconnected.",
|
|
2706
|
+
});
|
|
2707
|
+
} catch (e) {
|
|
2708
|
+
this.log.warn(`Failed to insert shutdown notification for user ${u.id}: ${e}`);
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
this.log.info(`Hub shutdown: notified ${users.length} approved user(s)`);
|
|
2712
|
+
} catch (e) {
|
|
2713
|
+
this.log.warn(`notifyHubShutdown error: ${e}`);
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2604
2717
|
private handleUpdateUsername(req: http.IncomingMessage, res: http.ServerResponse): void {
|
|
2605
2718
|
this.readBody(req, async (body) => {
|
|
2606
2719
|
if (!this.ctx) return this.jsonResponse(res, { error: "sharing_unavailable" });
|