@memtensor/memos-local-openclaw-plugin 1.0.4-beta.10 → 1.0.4-beta.11
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 +1 -0
- package/dist/client/connector.d.ts.map +1 -1
- package/dist/client/connector.js +37 -8
- package/dist/client/connector.js.map +1 -1
- package/dist/hub/server.d.ts +1 -0
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/server.js +122 -28
- package/dist/hub/server.js.map +1 -1
- package/dist/hub/user-manager.d.ts +9 -0
- package/dist/hub/user-manager.d.ts.map +1 -1
- package/dist/hub/user-manager.js +26 -2
- package/dist/hub/user-manager.js.map +1 -1
- package/dist/recall/engine.d.ts.map +1 -1
- package/dist/recall/engine.js +2 -0
- package/dist/recall/engine.js.map +1 -1
- package/dist/sharing/types.d.ts +1 -1
- package/dist/sharing/types.d.ts.map +1 -1
- package/dist/skill/evolver.d.ts +2 -0
- package/dist/skill/evolver.d.ts.map +1 -1
- package/dist/skill/evolver.js +56 -5
- package/dist/skill/evolver.js.map +1 -1
- package/dist/skill/generator.d.ts +2 -0
- package/dist/skill/generator.d.ts.map +1 -1
- package/dist/skill/generator.js +45 -3
- package/dist/skill/generator.js.map +1 -1
- package/dist/skill/installer.d.ts +26 -0
- package/dist/skill/installer.d.ts.map +1 -1
- package/dist/skill/installer.js +80 -4
- package/dist/skill/installer.js.map +1 -1
- package/dist/skill/upgrader.d.ts +2 -0
- package/dist/skill/upgrader.d.ts.map +1 -1
- package/dist/skill/upgrader.js +139 -1
- package/dist/skill/upgrader.js.map +1 -1
- package/dist/skill/validator.d.ts +3 -0
- package/dist/skill/validator.d.ts.map +1 -1
- package/dist/skill/validator.js +75 -0
- package/dist/skill/validator.js.map +1 -1
- package/dist/storage/sqlite.d.ts +15 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +91 -9
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +44 -23
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +35 -15
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +316 -13
- package/package.json +1 -1
- package/src/client/connector.ts +41 -8
- package/src/hub/server.ts +123 -27
- package/src/hub/user-manager.ts +42 -6
- package/src/recall/engine.ts +2 -0
- package/src/sharing/types.ts +1 -1
- package/src/skill/evolver.ts +58 -6
- package/src/skill/generator.ts +44 -5
- package/src/skill/installer.ts +107 -4
- package/src/skill/upgrader.ts +139 -1
- package/src/skill/validator.ts +79 -0
- package/src/storage/sqlite.ts +105 -9
- package/src/types.ts +11 -0
- package/src/viewer/html.ts +44 -23
- package/src/viewer/server.ts +35 -15
package/src/viewer/html.ts
CHANGED
|
@@ -804,6 +804,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
804
804
|
.recall-score.high{background:rgba(34,197,94,.12);color:#22c55e}
|
|
805
805
|
.recall-score.mid{background:rgba(251,191,36,.12);color:#f59e0b}
|
|
806
806
|
.recall-score.low{background:rgba(248,113,113,.1);color:var(--text-muted)}
|
|
807
|
+
.recall-origin{flex-shrink:0;font-size:9px;font-weight:600;padding:1px 5px;border-radius:4px}
|
|
808
|
+
.recall-origin.local-shared{background:rgba(59,130,246,.12);color:#3b82f6}
|
|
809
|
+
.recall-origin.hub-memory{background:rgba(139,92,246,.12);color:#8b5cf6}
|
|
810
|
+
.recall-origin.hub-remote{background:rgba(139,92,246,.12);color:#8b5cf6}
|
|
807
811
|
.recall-summary-short{flex:1;color:var(--text-sec);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
808
812
|
.recall-expand-icon{flex-shrink:0;font-size:10px;color:var(--text-muted);transition:transform .15s}
|
|
809
813
|
.recall-item.expanded .recall-expand-icon{transform:rotate(90deg)}
|
|
@@ -1216,7 +1220,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1216
1220
|
</div>
|
|
1217
1221
|
<button class="btn btn-ghost btn-sm" onclick="doLogout()" data-i18n="logout">Logout</button>
|
|
1218
1222
|
</div>
|
|
1219
|
-
|
|
1223
|
+
</div>
|
|
1220
1224
|
</div>
|
|
1221
1225
|
|
|
1222
1226
|
<div class="main-content">
|
|
@@ -2229,6 +2233,9 @@ const I18N={
|
|
|
2229
2233
|
'logs.recall.noHits':'No matching memories',
|
|
2230
2234
|
'logs.recall.noneRelevant':'LLM filter: none relevant',
|
|
2231
2235
|
'logs.recall.more':'{n} more...',
|
|
2236
|
+
'recall.origin.localShared':'Local Shared',
|
|
2237
|
+
'recall.origin.hubMemory':'Team Cache',
|
|
2238
|
+
'recall.origin.hubRemote':'Team',
|
|
2232
2239
|
'tab.import':'\u{1F4E5} Import',
|
|
2233
2240
|
'tab.settings':'\u2699 Settings',
|
|
2234
2241
|
'settings.modelconfig':'Model Configuration',
|
|
@@ -2940,6 +2947,9 @@ const I18N={
|
|
|
2940
2947
|
'logs.recall.noHits':'未匹配到记忆',
|
|
2941
2948
|
'logs.recall.noneRelevant':'LLM 过滤:无相关记忆',
|
|
2942
2949
|
'logs.recall.more':'还有 {n} 条...',
|
|
2950
|
+
'recall.origin.localShared':'本机共享',
|
|
2951
|
+
'recall.origin.hubMemory':'团队缓存',
|
|
2952
|
+
'recall.origin.hubRemote':'团队',
|
|
2943
2953
|
'tab.import':'\u{1F4E5} 导入',
|
|
2944
2954
|
'tab.settings':'\u2699 设置',
|
|
2945
2955
|
'settings.modelconfig':'模型配置',
|
|
@@ -4087,7 +4097,7 @@ function adminPaginateHtml(total,page,refilterFn){
|
|
|
4087
4097
|
if(end<pages) html+=(end<pages-1?'<span class="pg-info">...</span>':'')+'<button class="pg-btn" onclick="'+refilterFn+'Page('+(pages-1)+')">'+pages+'</button>';
|
|
4088
4098
|
html+='<button class="pg-btn'+(page>=pages-1?' disabled':'')+'" onclick="'+refilterFn+'Page('+(page+1)+')">\\u2192</button>';
|
|
4089
4099
|
html+='<span class="pg-info">'+total+' '+t('pagination.total')+'</span>';
|
|
4090
|
-
|
|
4100
|
+
html+='</div>';
|
|
4091
4101
|
return html;
|
|
4092
4102
|
}
|
|
4093
4103
|
|
|
@@ -4149,12 +4159,12 @@ async function loadAdminData(){
|
|
|
4149
4159
|
var fetches;
|
|
4150
4160
|
if(isAdmin){
|
|
4151
4161
|
fetches=await Promise.all([
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4162
|
+
fetch('/api/sharing/users').then(function(r){return r.json();}),
|
|
4163
|
+
fetch('/api/admin/shared-tasks').then(function(r){return r.json();}),
|
|
4164
|
+
fetch('/api/admin/shared-skills').then(function(r){return r.json();}),
|
|
4165
|
+
fetch('/api/sharing/pending-users').then(function(r){return r.json();}),
|
|
4166
|
+
fetch('/api/admin/shared-memories').then(function(r){return r.json();})
|
|
4167
|
+
]);
|
|
4158
4168
|
}else{
|
|
4159
4169
|
fetches=await Promise.all([
|
|
4160
4170
|
Promise.resolve({users:[]}),
|
|
@@ -5389,6 +5399,13 @@ function parseMemoryAddEntries(out){
|
|
|
5389
5399
|
return results;
|
|
5390
5400
|
}
|
|
5391
5401
|
|
|
5402
|
+
function recallOriginBadge(origin){
|
|
5403
|
+
if(origin==='local-shared') return '<span class="recall-origin local-shared">'+t('recall.origin.localShared')+'</span>';
|
|
5404
|
+
if(origin==='hub-memory') return '<span class="recall-origin hub-memory">'+t('recall.origin.hubMemory')+'</span>';
|
|
5405
|
+
if(origin==='hub-remote') return '<span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>';
|
|
5406
|
+
return '';
|
|
5407
|
+
}
|
|
5408
|
+
|
|
5392
5409
|
function buildLogSummary(lg){
|
|
5393
5410
|
let inputObj=null;
|
|
5394
5411
|
try{inputObj=JSON.parse(lg.input);}catch(_){}
|
|
@@ -5413,8 +5430,9 @@ function buildLogSummary(lg){
|
|
|
5413
5430
|
var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
|
|
5414
5431
|
var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
|
|
5415
5432
|
var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
|
|
5433
|
+
var oBadge=recallOriginBadge(c.origin);
|
|
5416
5434
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5417
|
-
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span
|
|
5435
|
+
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5418
5436
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5419
5437
|
html+='</div>';
|
|
5420
5438
|
});
|
|
@@ -5427,8 +5445,9 @@ function buildLogSummary(lg){
|
|
|
5427
5445
|
var scoreClass=f.score>=0.7?'high':f.score>=0.5?'mid':'low';
|
|
5428
5446
|
var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
|
|
5429
5447
|
var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
|
|
5448
|
+
var oBadge=recallOriginBadge(f.origin);
|
|
5430
5449
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5431
|
-
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+f.score.toFixed(2)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span
|
|
5450
|
+
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+f.score.toFixed(2)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5432
5451
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5433
5452
|
html+='</div>';
|
|
5434
5453
|
});
|
|
@@ -5492,8 +5511,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5492
5511
|
var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
|
|
5493
5512
|
var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
|
|
5494
5513
|
var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
|
|
5514
|
+
var oBadge=recallOriginBadge(c.origin);
|
|
5495
5515
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5496
|
-
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+c.score.toFixed(3)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span
|
|
5516
|
+
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+c.score.toFixed(3)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5497
5517
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5498
5518
|
html+='</div>';
|
|
5499
5519
|
});
|
|
@@ -5507,8 +5527,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5507
5527
|
var scoreClass=f.score>=0.7?'high':f.score>=0.5?'mid':'low';
|
|
5508
5528
|
var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
|
|
5509
5529
|
var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
|
|
5530
|
+
var oBadge=recallOriginBadge(f.origin);
|
|
5510
5531
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5511
|
-
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+f.score.toFixed(3)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span
|
|
5532
|
+
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+f.score.toFixed(3)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5512
5533
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5513
5534
|
html+='</div>';
|
|
5514
5535
|
});
|
|
@@ -6714,8 +6735,8 @@ async function saveHubConfig(){
|
|
|
6714
6735
|
if(!td.ok){
|
|
6715
6736
|
var errMsg=td.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(td.error||t('settings.hub.test.fail'));
|
|
6716
6737
|
done();toast(errMsg,'error');return;
|
|
6717
|
-
|
|
6718
|
-
|
|
6738
|
+
}
|
|
6739
|
+
}catch(e){
|
|
6719
6740
|
done();toast(t('settings.hub.test.fail')+': '+String(e),'error');return;
|
|
6720
6741
|
}
|
|
6721
6742
|
}
|
|
@@ -7536,8 +7557,8 @@ function getFilterParams(){
|
|
|
7536
7557
|
if(scope==='local'){
|
|
7537
7558
|
p.set('owner',_currentAgentOwner);
|
|
7538
7559
|
}else if(scope==='allLocal'){
|
|
7539
|
-
|
|
7540
|
-
|
|
7560
|
+
const owner=document.getElementById('filterOwner').value;
|
|
7561
|
+
if(owner) p.set('owner',owner);
|
|
7541
7562
|
}
|
|
7542
7563
|
return p;
|
|
7543
7564
|
}
|
|
@@ -7567,11 +7588,11 @@ async function loadMemories(page,silent){
|
|
|
7567
7588
|
renderPagination();
|
|
7568
7589
|
}catch(e){
|
|
7569
7590
|
if(!silent){
|
|
7570
|
-
|
|
7571
|
-
|
|
7591
|
+
list.innerHTML='';
|
|
7592
|
+
totalPages=1;totalCount=0;
|
|
7572
7593
|
_lastMemoriesFingerprint='';
|
|
7573
|
-
|
|
7574
|
-
|
|
7594
|
+
renderMemories([]);
|
|
7595
|
+
renderPagination();
|
|
7575
7596
|
}
|
|
7576
7597
|
}
|
|
7577
7598
|
}
|
|
@@ -7598,9 +7619,9 @@ async function loadHubMemories(silent){
|
|
|
7598
7619
|
}catch(e){
|
|
7599
7620
|
if(!silent){
|
|
7600
7621
|
_lastMemoriesFingerprint='';
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7622
|
+
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
7623
|
+
renderMemories([]);
|
|
7624
|
+
document.getElementById('pagination').innerHTML='';
|
|
7604
7625
|
}
|
|
7605
7626
|
}
|
|
7606
7627
|
}
|
package/src/viewer/server.ts
CHANGED
|
@@ -1780,7 +1780,8 @@ export class ViewerServer {
|
|
|
1780
1780
|
localIPs.push("127.0.0.1", "localhost", "0.0.0.0");
|
|
1781
1781
|
try {
|
|
1782
1782
|
const u = new URL(hubUrl);
|
|
1783
|
-
|
|
1783
|
+
const targetPort = u.port || (u.protocol === "https:" ? "443" : "80");
|
|
1784
|
+
if (localIPs.includes(u.hostname) && targetPort === String(this.port)) {
|
|
1784
1785
|
return this.jsonResponse(res, { ok: false, error: "cannot_join_self" });
|
|
1785
1786
|
}
|
|
1786
1787
|
} catch {}
|
|
@@ -1788,10 +1789,13 @@ export class ViewerServer {
|
|
|
1788
1789
|
const nickname = sharing.client?.nickname;
|
|
1789
1790
|
const username = nickname || os.userInfo().username || "user";
|
|
1790
1791
|
const hostname = os.hostname() || "unknown";
|
|
1792
|
+
const persisted = this.store.getClientHubConnection();
|
|
1793
|
+
const existingIdentityKey = persisted?.identityKey || "";
|
|
1791
1794
|
const result = await hubRequestJson(hubUrl, "", "/api/v1/hub/join", {
|
|
1792
1795
|
method: "POST",
|
|
1793
|
-
body: JSON.stringify({ teamToken, username, deviceName: hostname, reapply: true }),
|
|
1796
|
+
body: JSON.stringify({ teamToken, username, deviceName: hostname, reapply: true, identityKey: existingIdentityKey }),
|
|
1794
1797
|
}) as any;
|
|
1798
|
+
const returnedIdentityKey = String(result.identityKey || existingIdentityKey || "");
|
|
1795
1799
|
this.store.setClientHubConnection({
|
|
1796
1800
|
hubUrl,
|
|
1797
1801
|
userId: String(result.userId || ""),
|
|
@@ -1799,6 +1803,8 @@ export class ViewerServer {
|
|
|
1799
1803
|
userToken: result.userToken || "",
|
|
1800
1804
|
role: "member",
|
|
1801
1805
|
connectedAt: Date.now(),
|
|
1806
|
+
identityKey: returnedIdentityKey,
|
|
1807
|
+
lastKnownStatus: result.status || "",
|
|
1802
1808
|
});
|
|
1803
1809
|
this.jsonResponse(res, { ok: true, status: result.status || "pending" });
|
|
1804
1810
|
} catch (err) {
|
|
@@ -2592,7 +2598,8 @@ export class ViewerServer {
|
|
|
2592
2598
|
localIPs.push("127.0.0.1", "localhost", "0.0.0.0");
|
|
2593
2599
|
try {
|
|
2594
2600
|
const u = new URL(addr.startsWith("http") ? addr : `http://${addr}`);
|
|
2595
|
-
|
|
2601
|
+
const targetPort = u.port || (u.protocol === "https:" ? "443" : "80");
|
|
2602
|
+
if (localIPs.includes(u.hostname) && targetPort === String(this.port)) {
|
|
2596
2603
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2597
2604
|
res.end(JSON.stringify({ error: "cannot_join_self" }));
|
|
2598
2605
|
return;
|
|
@@ -2618,17 +2625,22 @@ export class ViewerServer {
|
|
|
2618
2625
|
const isClient = newEnabled && newRole === "client";
|
|
2619
2626
|
if (wasClient && !isClient) {
|
|
2620
2627
|
this.notifyHubLeave();
|
|
2621
|
-
this.store.
|
|
2622
|
-
|
|
2628
|
+
const oldConn = this.store.getClientHubConnection();
|
|
2629
|
+
if (oldConn) {
|
|
2630
|
+
this.store.setClientHubConnection({ ...oldConn, userToken: "", lastKnownStatus: "left" });
|
|
2631
|
+
}
|
|
2632
|
+
this.log.info("Client hub connection token cleared (sharing disabled or role changed), identity preserved");
|
|
2623
2633
|
}
|
|
2624
2634
|
|
|
2625
|
-
// Detect switching to a different Hub while still in client mode
|
|
2626
2635
|
if (wasClient && isClient) {
|
|
2627
2636
|
const newClientAddr = String((merged.client as Record<string, unknown>)?.hubAddress || "");
|
|
2628
2637
|
if (newClientAddr && oldClientHubAddress && normalizeHubUrl(newClientAddr) !== normalizeHubUrl(oldClientHubAddress)) {
|
|
2629
2638
|
this.notifyHubLeave();
|
|
2630
|
-
this.store.
|
|
2631
|
-
|
|
2639
|
+
const oldConn = this.store.getClientHubConnection();
|
|
2640
|
+
if (oldConn) {
|
|
2641
|
+
this.store.setClientHubConnection({ ...oldConn, hubUrl: normalizeHubUrl(newClientAddr), userToken: "", lastKnownStatus: "hub_changed" });
|
|
2642
|
+
}
|
|
2643
|
+
this.log.info("Client hub connection token cleared (switched to different Hub), identity preserved");
|
|
2632
2644
|
}
|
|
2633
2645
|
}
|
|
2634
2646
|
|
|
@@ -2645,9 +2657,11 @@ export class ViewerServer {
|
|
|
2645
2657
|
this.log.info("Plugin config updated via Viewer");
|
|
2646
2658
|
this.stopHubHeartbeat();
|
|
2647
2659
|
|
|
2648
|
-
// When switching to client mode,
|
|
2660
|
+
// When switching to client mode or re-enabling sharing as client, send join request
|
|
2649
2661
|
const finalSharing = config.sharing as Record<string, unknown> | undefined;
|
|
2650
|
-
|
|
2662
|
+
const nowClient = Boolean(finalSharing?.enabled) && finalSharing?.role === "client";
|
|
2663
|
+
const previouslyClient = oldSharingEnabled && oldSharingRole === "client";
|
|
2664
|
+
if (nowClient && !previouslyClient) {
|
|
2651
2665
|
this.autoJoinOnSave(finalSharing).catch(e => this.log.warn(`Auto-join on save failed: ${e}`));
|
|
2652
2666
|
}
|
|
2653
2667
|
|
|
@@ -2670,10 +2684,13 @@ export class ViewerServer {
|
|
|
2670
2684
|
const nickname = String(clientCfg?.nickname || "");
|
|
2671
2685
|
const username = nickname || os.userInfo().username || "user";
|
|
2672
2686
|
const hostname = os.hostname() || "unknown";
|
|
2687
|
+
const persisted = this.store.getClientHubConnection();
|
|
2688
|
+
const existingIdentityKey = persisted?.identityKey || "";
|
|
2673
2689
|
const result = await hubRequestJson(hubUrl, "", "/api/v1/hub/join", {
|
|
2674
2690
|
method: "POST",
|
|
2675
|
-
body: JSON.stringify({ teamToken, username, deviceName: hostname }),
|
|
2691
|
+
body: JSON.stringify({ teamToken, username, deviceName: hostname, identityKey: existingIdentityKey }),
|
|
2676
2692
|
}) as any;
|
|
2693
|
+
const returnedIdentityKey = String(result.identityKey || existingIdentityKey || "");
|
|
2677
2694
|
this.store.setClientHubConnection({
|
|
2678
2695
|
hubUrl,
|
|
2679
2696
|
userId: String(result.userId || ""),
|
|
@@ -2681,6 +2698,8 @@ export class ViewerServer {
|
|
|
2681
2698
|
userToken: result.userToken || "",
|
|
2682
2699
|
role: "member",
|
|
2683
2700
|
connectedAt: Date.now(),
|
|
2701
|
+
identityKey: returnedIdentityKey,
|
|
2702
|
+
lastKnownStatus: result.status || "",
|
|
2684
2703
|
});
|
|
2685
2704
|
this.log.info(`Auto-join on save: status=${result.status}, userId=${result.userId}`);
|
|
2686
2705
|
if (result.userToken) {
|
|
@@ -2768,10 +2787,10 @@ export class ViewerServer {
|
|
|
2768
2787
|
this.log.warn(`Failed to update hub-auth.json: ${e}`);
|
|
2769
2788
|
}
|
|
2770
2789
|
} else {
|
|
2771
|
-
const
|
|
2772
|
-
if (
|
|
2790
|
+
const persistedConn = this.store.getClientHubConnection();
|
|
2791
|
+
if (persistedConn) {
|
|
2773
2792
|
this.store.setClientHubConnection({
|
|
2774
|
-
...
|
|
2793
|
+
...persistedConn,
|
|
2775
2794
|
username: result.username,
|
|
2776
2795
|
userToken: result.userToken,
|
|
2777
2796
|
});
|
|
@@ -2798,7 +2817,8 @@ export class ViewerServer {
|
|
|
2798
2817
|
const localIPs = this.getLocalIPs();
|
|
2799
2818
|
localIPs.push("127.0.0.1", "localhost", "0.0.0.0");
|
|
2800
2819
|
const parsed = new URL(hubUrl.startsWith("http") ? hubUrl : `http://${hubUrl}`);
|
|
2801
|
-
|
|
2820
|
+
const targetPort = parsed.port || (parsed.protocol === "https:" ? "443" : "80");
|
|
2821
|
+
if (localIPs.includes(parsed.hostname) && targetPort === String(this.port)) {
|
|
2802
2822
|
this.jsonResponse(res, { ok: false, error: "cannot_join_self" });
|
|
2803
2823
|
return;
|
|
2804
2824
|
}
|