@memtensor/memos-local-openclaw-plugin 1.0.5 → 1.0.6-beta.10

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.
Files changed (66) hide show
  1. package/dist/capture/index.d.ts.map +1 -1
  2. package/dist/capture/index.js +24 -0
  3. package/dist/capture/index.js.map +1 -1
  4. package/dist/client/connector.d.ts.map +1 -1
  5. package/dist/client/connector.js +33 -5
  6. package/dist/client/connector.js.map +1 -1
  7. package/dist/client/hub.d.ts.map +1 -1
  8. package/dist/client/hub.js +4 -0
  9. package/dist/client/hub.js.map +1 -1
  10. package/dist/hub/server.d.ts +2 -0
  11. package/dist/hub/server.d.ts.map +1 -1
  12. package/dist/hub/server.js +116 -54
  13. package/dist/hub/server.js.map +1 -1
  14. package/dist/ingest/providers/index.d.ts +4 -0
  15. package/dist/ingest/providers/index.d.ts.map +1 -1
  16. package/dist/ingest/providers/index.js +32 -86
  17. package/dist/ingest/providers/index.js.map +1 -1
  18. package/dist/ingest/providers/openai.d.ts.map +1 -1
  19. package/dist/ingest/providers/openai.js +29 -13
  20. package/dist/ingest/providers/openai.js.map +1 -1
  21. package/dist/recall/engine.d.ts.map +1 -1
  22. package/dist/recall/engine.js +33 -32
  23. package/dist/recall/engine.js.map +1 -1
  24. package/dist/storage/sqlite.d.ts +43 -7
  25. package/dist/storage/sqlite.d.ts.map +1 -1
  26. package/dist/storage/sqlite.js +179 -58
  27. package/dist/storage/sqlite.js.map +1 -1
  28. package/dist/tools/memory-get.d.ts.map +1 -1
  29. package/dist/tools/memory-get.js +4 -1
  30. package/dist/tools/memory-get.js.map +1 -1
  31. package/dist/types.d.ts +1 -1
  32. package/dist/types.d.ts.map +1 -1
  33. package/dist/types.js.map +1 -1
  34. package/dist/update-check.d.ts.map +1 -1
  35. package/dist/update-check.js +2 -7
  36. package/dist/update-check.js.map +1 -1
  37. package/dist/viewer/html.d.ts.map +1 -1
  38. package/dist/viewer/html.js +115 -27
  39. package/dist/viewer/html.js.map +1 -1
  40. package/dist/viewer/server.d.ts +25 -0
  41. package/dist/viewer/server.d.ts.map +1 -1
  42. package/dist/viewer/server.js +503 -206
  43. package/dist/viewer/server.js.map +1 -1
  44. package/index.ts +273 -282
  45. package/openclaw.plugin.json +1 -1
  46. package/package.json +2 -1
  47. package/scripts/native-binding.cjs +32 -0
  48. package/scripts/postinstall.cjs +24 -11
  49. package/src/capture/index.ts +36 -0
  50. package/src/client/connector.ts +32 -5
  51. package/src/client/hub.ts +4 -0
  52. package/src/hub/server.ts +110 -50
  53. package/src/ingest/providers/index.ts +37 -92
  54. package/src/ingest/providers/openai.ts +31 -13
  55. package/src/recall/engine.ts +32 -30
  56. package/src/storage/sqlite.ts +196 -63
  57. package/src/tools/memory-get.ts +4 -1
  58. package/src/types.ts +2 -0
  59. package/src/update-check.ts +2 -7
  60. package/src/viewer/html.ts +115 -27
  61. package/src/viewer/server.ts +483 -172
  62. package/prebuilds/darwin-arm64/better_sqlite3.node +0 -0
  63. package/prebuilds/darwin-x64/better_sqlite3.node +0 -0
  64. package/prebuilds/linux-x64/better_sqlite3.node +0 -0
  65. package/prebuilds/win32-x64/better_sqlite3.node +0 -0
  66. package/telemetry.credentials.json +0 -5
@@ -6,7 +6,7 @@ return `<!DOCTYPE html>
6
6
  <meta charset="UTF-8">
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
8
  <link rel="icon" href="https://statics.memtensor.com.cn/logo/color-m.svg" type="image/svg+xml">
9
- <title>MemOS 记忆</title>
9
+ <title>OpenClaw 记忆</title>
10
10
  <link rel="preconnect" href="https://fonts.googleapis.com">
11
11
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12
12
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
@@ -1192,7 +1192,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
1192
1192
  <div class="topbar-inner">
1193
1193
  <div class="brand">
1194
1194
  <span class="memos-logo"><svg width="28" height="28" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="topLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#topLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#topLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#topLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg></span>
1195
- <div class="brand-col"><span data-i18n="title" class="brand-title">MemOS</span><span data-i18n="subtitle" class="brand-powered">Powered by MemOS</span></div>${vBadge}
1195
+ <div class="brand-col"><span data-i18n="title" class="brand-title">OpenClaw 记忆</span><span data-i18n="subtitle" class="brand-powered">Powered by MemOS</span></div>${vBadge}
1196
1196
  </div>
1197
1197
  <div class="topbar-center">
1198
1198
  <nav class="nav-tabs">
@@ -2038,7 +2038,7 @@ let _currentAgentOwner='agent:main';
2038
2038
  /* ─── i18n ─── */
2039
2039
  const I18N={
2040
2040
  en:{
2041
- 'title':'MemOS',
2041
+ 'title':'OpenClaw Memory',
2042
2042
  'subtitle':'Powered by MemOS',
2043
2043
  'setup.desc':'Set a password to protect your memories',
2044
2044
  'setup.pw':'Enter a password (4+ characters)',
@@ -2130,6 +2130,8 @@ const I18N={
2130
2130
  'notif.hubShutdown':'The team server has been shut down',
2131
2131
  'notif.rolePromoted':'You have been promoted to admin',
2132
2132
  'notif.roleDemoted':'You have been changed to member',
2133
+ 'notif.usernameRenamed':'Your nickname has been changed by the admin',
2134
+ 'notif.usernameRenamed.detail':'{oldName} → {newName}',
2133
2135
  'notif.clearAll':'Clear all',
2134
2136
  'notif.timeAgo.just':'just now',
2135
2137
  'notif.timeAgo.min':'{n}m ago',
@@ -2233,6 +2235,7 @@ const I18N={
2233
2235
  'logs.empty':'No logs yet. Logs will appear here when tools are called.',
2234
2236
  'logs.ago':'ago',
2235
2237
  'logs.recall.initial':'Initial Retrieval',
2238
+ 'logs.recall.hubRemote':'Hub Remote',
2236
2239
  'logs.recall.filtered':'LLM Filtered',
2237
2240
  'logs.recall.noHits':'No matching memories',
2238
2241
  'logs.recall.noneRelevant':'LLM filter: none relevant',
@@ -2469,6 +2472,10 @@ const I18N={
2469
2472
  'sharing.team.default':'the team',
2470
2473
  'sharing.retryJoin.success':'Join request re-submitted. Waiting for admin approval.',
2471
2474
  'sharing.retryJoin.fail':'Failed to retry join',
2475
+ 'sharing.joinError.hubUnreachable':'Unable to connect to the team server. The server may be offline or the network is unavailable. Please check the server address and try again.',
2476
+ 'sharing.joinError.usernameTaken':'The username is already taken on this team server. Please go to Settings and change your nickname, then try again.',
2477
+ 'sharing.joinError.invalidToken':'The team token is invalid. Please check with your team admin and update the token in Settings.',
2478
+ 'sharing.joinError.blocked':'Your account has been blocked by the team admin. Please contact the admin for assistance.',
2472
2479
  'sharing.ownerRemoved':'(removed)',
2473
2480
  'sharing.cannotJoinSelf':'Cannot join your own server. Please enter a remote server address.',
2474
2481
  'scope.hub':'Team',
@@ -2775,7 +2782,7 @@ const I18N={
2775
2782
  'guide.hub.btn':'\u2192 Configure Server Mode'
2776
2783
  },
2777
2784
  zh:{
2778
- 'title':'MemOS 记忆',
2785
+ 'title':'OpenClaw 记忆',
2779
2786
  'subtitle':'由 MemOS 驱动',
2780
2787
  'setup.desc':'设置密码以保护你的记忆数据',
2781
2788
  'setup.pw':'输入密码(至少4位)',
@@ -2867,6 +2874,8 @@ const I18N={
2867
2874
  'notif.hubShutdown':'团队服务已关闭',
2868
2875
  'notif.rolePromoted':'你已被提升为管理员',
2869
2876
  'notif.roleDemoted':'你已被设为普通成员',
2877
+ 'notif.usernameRenamed':'你的昵称已被管理员修改',
2878
+ 'notif.usernameRenamed.detail':'{oldName} → {newName}',
2870
2879
  'notif.clearAll':'清除全部',
2871
2880
  'notif.timeAgo.just':'刚刚',
2872
2881
  'notif.timeAgo.min':'{n}分钟前',
@@ -2970,6 +2979,7 @@ const I18N={
2970
2979
  'logs.empty':'暂无日志。当工具被调用时日志会显示在这里。',
2971
2980
  'logs.ago':'前',
2972
2981
  'logs.recall.initial':'初始检索',
2982
+ 'logs.recall.hubRemote':'远程召回',
2973
2983
  'logs.recall.filtered':'LLM 过滤后',
2974
2984
  'logs.recall.noHits':'未匹配到记忆',
2975
2985
  'logs.recall.noneRelevant':'LLM 过滤:无相关记忆',
@@ -3206,6 +3216,10 @@ const I18N={
3206
3216
  'sharing.team.default':'该团队',
3207
3217
  'sharing.retryJoin.success':'加入申请已重新提交,请等待管理员审核。',
3208
3218
  'sharing.retryJoin.fail':'重新申请失败',
3219
+ 'sharing.joinError.hubUnreachable':'无法连接到团队服务器,服务器可能已下线或网络不可用。请检查服务器地址后重试。',
3220
+ 'sharing.joinError.usernameTaken':'该用户名在团队服务器上已被占用,请到设置中修改昵称后再重试。',
3221
+ 'sharing.joinError.invalidToken':'团队令牌无效,请向管理员确认令牌并在设置中更新。',
3222
+ 'sharing.joinError.blocked':'您的账号已被团队管理员封禁,请联系管理员处理。',
3209
3223
  'sharing.ownerRemoved':'(已移除)',
3210
3224
  'sharing.cannotJoinSelf':'不能加入自己的服务端,请输入远程服务器地址。',
3211
3225
  'scope.hub':'团队',
@@ -3529,7 +3543,7 @@ function applyI18n(){
3529
3543
  });
3530
3544
  const step2=document.getElementById('resetStep2Desc');
3531
3545
  if(step2) step2.innerHTML=t('reset.step2.desc.pre')+'<span style="font-family:monospace;font-size:12px;color:var(--pri)">password reset token: <strong>a1b2c3d4e5f6...</strong></span>'+t('reset.step2.desc.post');
3532
- document.title=t('title')+' - MemOS';
3546
+ document.title=t('title')+' - OpenClaw';
3533
3547
  if(typeof loadStats==='function' && document.getElementById('app').style.display==='flex'){loadStats();}
3534
3548
  if(document.querySelector('.analytics-view.show') && typeof loadMetrics==='function'){loadMetrics();}
3535
3549
  }
@@ -3702,18 +3716,25 @@ async function testHubConnection(){
3702
3716
  var result=document.getElementById('hubConnTestResult');
3703
3717
  var addr=document.getElementById('cfgClientHubAddress').value.trim();
3704
3718
  if(!addr){result.innerHTML='<span style="color:var(--rose)">\u274C '+t('settings.hub.test.noAddr')+'</span>';return;}
3719
+ var tokenEl=document.getElementById('cfgClientTeamToken');
3720
+ var teamToken=tokenEl?tokenEl.value.trim():'';
3721
+ if(!teamToken){result.innerHTML='<span style="color:var(--rose)">\u274C '+t('settings.hub.teamToken.required')+'</span>';return;}
3722
+ var nicknameEl=document.getElementById('cfgClientNickname');
3723
+ var nickname=nicknameEl?nicknameEl.value.trim():'';
3705
3724
  btn.disabled=true;result.innerHTML=t('settings.hub.test.testing');
3706
- try{
3707
- }catch(e){}
3708
3725
  try{
3709
3726
  var url=addr.match(/^https?:\\/\\//)?addr:'http://'+addr;
3710
3727
  url=url.replace(/\\/+$/,'');
3711
- var r=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:url})});
3728
+ var r=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:url,teamToken:teamToken,nickname:nickname})});
3712
3729
  var d=await r.json();
3713
3730
  if(d.ok){
3714
3731
  result.innerHTML='<span style="color:var(--green)">\u2705 '+t('settings.hub.test.ok')+(d.teamName?' — '+esc(d.teamName):'')+'</span>';
3715
3732
  }else{
3716
- var errMsg=d.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(d.error||t('settings.hub.test.fail'));
3733
+ var errMsg;
3734
+ if(d.error==='cannot_join_self') errMsg=t('sharing.cannotJoinSelf');
3735
+ else if(d.error==='username_taken') errMsg=t('sharing.joinError.usernameTaken');
3736
+ else if(d.error==='invalid_team_token') errMsg=t('sharing.joinError.invalidToken');
3737
+ else errMsg=d.error||t('settings.hub.test.fail');
3717
3738
  result.innerHTML='<span style="color:var(--rose)">\u274C '+errMsg+'</span>';
3718
3739
  }
3719
3740
  }catch(e){
@@ -4079,7 +4100,18 @@ async function retryHubJoin(){
4079
4100
  _lastSidebarFingerprint='';_lastSettingsFingerprint='';_lastSharingConnStatus='';
4080
4101
  setTimeout(function(){loadSharingStatus(true);},800);
4081
4102
  }else{
4082
- toast(d.error||t('sharing.retryJoin.fail'),'error');
4103
+ var code=d.errorCode||'';
4104
+ if(code==='hub_unreachable'){
4105
+ alertModal(t('sharing.joinError.hubUnreachable'));
4106
+ }else if(code==='username_taken'){
4107
+ alertModal(t('sharing.joinError.usernameTaken'));
4108
+ }else if(code==='invalid_team_token'){
4109
+ alertModal(t('sharing.joinError.invalidToken'));
4110
+ }else if(code==='blocked'){
4111
+ alertModal(t('sharing.joinError.blocked'));
4112
+ }else{
4113
+ toast(d.error||t('sharing.retryJoin.fail'),'error');
4114
+ }
4083
4115
  }
4084
4116
  }catch(e){toast(t('sharing.retryJoin.fail')+': '+e.message,'error');}
4085
4117
  }
@@ -5572,6 +5604,24 @@ function buildLogSummary(lg){
5572
5604
  html+='</div>';
5573
5605
  });
5574
5606
  html+='</div></div>';
5607
+ var hubCands=recallData.hubCandidates||[];
5608
+ html+='<div class="recall-layer hub-recall" onclick="this.classList.toggle(\\\'expanded\\\')">';
5609
+ html+='<div class="recall-layer-title"><span class="recall-expand-icon">\u25B6</span>\u{1F310} '+t('logs.recall.hubRemote')+' <span class="recall-count">'+hubCands.length+'</span></div>';
5610
+ if(hubCands.length>0){
5611
+ html+='<div class="recall-items">';
5612
+ hubCands.forEach(function(c){
5613
+ var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
5614
+ var shortText=escapeHtml(c.summary||c.original_excerpt||'');
5615
+ var fullText=escapeHtml(c.original_excerpt||c.summary||'');
5616
+ var owner=c.ownerName?' ['+escapeHtml(c.ownerName)+']':'';
5617
+ html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5618
+ html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'assistant')+'">'+(c.role||'assistant')+'</span><span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>'+owner+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
5619
+ html+='<div class="recall-summary-full">'+fullText+'</div>';
5620
+ html+='</div>';
5621
+ });
5622
+ html+='</div>';
5623
+ }
5624
+ html+='</div>';
5575
5625
  if(filtered.length>0){
5576
5626
  html+='<div class="recall-layer filtered" onclick="this.classList.toggle(\\\'expanded\\\')">';
5577
5627
  html+='<div class="recall-layer-title"><span class="recall-expand-icon">\u25B6</span>\u2705 '+t('logs.recall.filtered')+' <span class="recall-count">'+filtered.length+'</span></div>';
@@ -5637,6 +5687,7 @@ function buildLogSummary(lg){
5637
5687
  function buildRecallDetailHtml(rd){
5638
5688
  var html='<div class="recall-detail">';
5639
5689
  var cands=rd.candidates||[];
5690
+ var hubCands=rd.hubCandidates||[];
5640
5691
  var filtered=rd.filtered||[];
5641
5692
  if(cands.length>0){
5642
5693
  html+='<div class="recall-detail-section" onclick="this.classList.toggle(\\\'expanded\\\')">';
@@ -5654,6 +5705,23 @@ function buildRecallDetailHtml(rd){
5654
5705
  });
5655
5706
  html+='</div></div>';
5656
5707
  }
5708
+ html+='<div class="recall-detail-section hub-recall" onclick="this.classList.toggle(\\\'expanded\\\')">';
5709
+ html+='<div class="recall-detail-title"><span class="recall-expand-icon">\u25B6</span>\u{1F310} '+t('logs.recall.hubRemote')+' ('+hubCands.length+')</div>';
5710
+ if(hubCands.length>0){
5711
+ html+='<div class="recall-detail-items">';
5712
+ hubCands.forEach(function(c,i){
5713
+ var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
5714
+ var shortText=escapeHtml(c.summary||c.original_excerpt||'');
5715
+ var fullText=escapeHtml(c.original_excerpt||c.summary||'');
5716
+ var owner=c.ownerName?' ['+escapeHtml(c.ownerName)+']':'';
5717
+ html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5718
+ html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'assistant')+'">'+(c.role||'assistant')+'</span><span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>'+owner+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
5719
+ html+='<div class="recall-summary-full">'+fullText+'</div>';
5720
+ html+='</div>';
5721
+ });
5722
+ html+='</div>';
5723
+ }
5724
+ html+='</div>';
5657
5725
  if(filtered.length>0){
5658
5726
  html+='<div class="recall-detail-section filtered" onclick="this.classList.toggle(\\\'expanded\\\')">';
5659
5727
  html+='<div class="recall-detail-title"><span class="recall-expand-icon">\u25B6</span>\u2705 '+t('logs.recall.filtered')+' ('+filtered.length+')</div>';
@@ -5669,7 +5737,7 @@ function buildRecallDetailHtml(rd){
5669
5737
  html+='</div>';
5670
5738
  });
5671
5739
  html+='</div></div>';
5672
- }else if(cands.length>0){
5740
+ }else if(cands.length>0||hubCands.length>0){
5673
5741
  html+='<div style="font-size:10px;color:var(--text-muted);margin-top:4px">\u26A0 '+t('logs.recall.noneRelevant')+'</div>';
5674
5742
  }
5675
5743
  if(rd.status==='error'&&rd.error){
@@ -6666,7 +6734,8 @@ async function loadConfig(){
6666
6734
  document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
6667
6735
  _loadedClientHubAddress=client.hubAddress||'';
6668
6736
  document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
6669
- document.getElementById('cfgClientNickname').value=client.nickname||'';
6737
+ var hubUsername=sharingStatusCache&&sharingStatusCache.connection&&sharingStatusCache.connection.user&&sharingStatusCache.connection.user.username;
6738
+ document.getElementById('cfgClientNickname').value=hubUsername||client.nickname||'';
6670
6739
  document.getElementById('cfgClientUserToken').value=client.userToken||'';
6671
6740
  onSharingToggle();
6672
6741
  updateHubShareInfo();
@@ -6867,19 +6936,19 @@ async function saveHubConfig(){
6867
6936
  if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
6868
6937
  cfg.sharing.hub={teamName:'',teamToken:''};
6869
6938
  if(clientAddr){
6870
- try{
6871
- }catch(e){}
6872
6939
  try{
6873
6940
  var testUrl=clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr;
6874
6941
  testUrl=testUrl.replace(/\\/+$/,'');
6875
- var tr=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:testUrl})});
6942
+ var tr=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:testUrl,teamToken:clientTeamToken,nickname:clientNickname})});
6876
6943
  var td=await tr.json();
6877
6944
  if(!td.ok){
6878
- var errMsg=td.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(td.error||t('settings.hub.test.fail'));
6879
- done();toast(errMsg,'error');return;
6880
- }
6881
- }catch(e){
6882
- done();toast(t('settings.hub.test.fail')+': '+String(e),'error');return;
6945
+ if(td.error==='cannot_join_self'){done();alertModal(t('sharing.cannotJoinSelf'));return;}
6946
+ if(td.error==='username_taken'){done();alertModal(t('sharing.joinError.usernameTaken'));return;}
6947
+ if(td.error==='invalid_team_token'){done();alertModal(t('sharing.joinError.invalidToken'));return;}
6948
+ done();alertModal(td.error||t('settings.hub.test.fail'));return;
6949
+ }
6950
+ }catch(e){
6951
+ done();alertModal(t('sharing.joinError.hubUnreachable'));return;
6883
6952
  }
6884
6953
  }
6885
6954
  }
@@ -6909,7 +6978,17 @@ async function saveHubConfig(){
6909
6978
  try{await fetch('/api/sharing/update-username',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:adminNameEl.value.trim()})});}catch(e){}
6910
6979
  }
6911
6980
  }
6912
- if(sharingEnabled&&_sharingRole==='client'&&result.joinStatus){
6981
+ if(sharingEnabled&&_sharingRole==='client'&&result.joinError){
6982
+ if(result.joinError==='hub_unreachable'){
6983
+ alertModal(t('sharing.joinError.hubUnreachable'));
6984
+ }else if(result.joinError==='username_taken'){
6985
+ alertModal(t('sharing.joinError.usernameTaken'));
6986
+ }else if(result.joinError==='invalid_team_token'){
6987
+ alertModal(t('sharing.joinError.invalidToken'));
6988
+ }else{
6989
+ toast(t('sharing.retryJoin.fail'),'error');
6990
+ }
6991
+ }else if(sharingEnabled&&_sharingRole==='client'&&result.joinStatus){
6913
6992
  if(result.joinStatus==='pending'){
6914
6993
  toast(t('sharing.joinSent.pending'),'success');
6915
6994
  }else if(result.joinStatus==='active'){
@@ -7477,6 +7556,7 @@ function notifIcon(resource,type){
7477
7556
  if(type==='hub_shutdown') return '\\u{1F6D1}';
7478
7557
  if(type==='role_promoted') return '\\u{2B06}';
7479
7558
  if(type==='role_demoted') return '\\u{2B07}';
7559
+ if(type==='username_renamed') return '\\u{270F}';
7480
7560
  if(resource==='memory') return '\\u{1F4DD}';
7481
7561
  if(resource==='task') return '\\u{1F4CB}';
7482
7562
  if(resource==='skill') return '\\u{1F9E0}';
@@ -7523,6 +7603,9 @@ function notifTypeText(n){
7523
7603
  if(n.type==='role_demoted'){
7524
7604
  return t('notif.roleDemoted');
7525
7605
  }
7606
+ if(n.type==='username_renamed'){
7607
+ return t('notif.usernameRenamed');
7608
+ }
7526
7609
  return n.message||n.type;
7527
7610
  }
7528
7611
 
@@ -7557,7 +7640,7 @@ function renderNotifBadge(){
7557
7640
  }
7558
7641
  }
7559
7642
 
7560
- var _notifKnownTypes={membership_approved:1,membership_rejected:1,membership_removed:1,hub_shutdown:1,user_left:1,user_online:1,user_offline:1,user_join_request:1,role_promoted:1,role_demoted:1,resource_removed:1,resource_shared:1,resource_unshared:1};
7643
+ var _notifKnownTypes={membership_approved:1,membership_rejected:1,membership_removed:1,hub_shutdown:1,user_left:1,user_online:1,user_offline:1,user_join_request:1,role_promoted:1,role_demoted:1,resource_removed:1,resource_shared:1,resource_unshared:1,username_renamed:1};
7561
7644
  function notifDisplayTitle(n){
7562
7645
  if(_notifKnownTypes[n.type]) return notifTypeText(n);
7563
7646
  return n.title||notifTypeText(n);
@@ -7565,6 +7648,11 @@ function notifDisplayTitle(n){
7565
7648
  function notifDisplayDetail(n){
7566
7649
  if(_notifKnownTypes[n.type]){
7567
7650
  if(n.type==='resource_removed'||n.type==='resource_shared'||n.type==='resource_unshared') return n.title||'';
7651
+ if(n.type==='username_renamed'){
7652
+ var rm=n.title&&n.title.match(/from "([^"]+)" to "([^"]+)"/);
7653
+ if(rm) return t('notif.usernameRenamed.detail').replace('{oldName}',rm[1]).replace('{newName}',rm[2]);
7654
+ return '';
7655
+ }
7568
7656
  var m=n.title&&n.title.match(/["\u201C]([^"\u201D]+)["\u201D]/);
7569
7657
  if(m) return m[1];
7570
7658
  if(n.type==='user_left'||n.type==='user_online'||n.type==='user_offline'||n.type==='user_join_request') return n.title||'';
@@ -8963,11 +9051,11 @@ function waitForGatewayAndReload(maxAttempts,attempt){
8963
9051
  });
8964
9052
  },delay);
8965
9053
  }
8966
- function doUpdateInstall(packageSpec,btnEl,statusEl){
9054
+ function doUpdateInstall(packageSpec,btnEl,statusEl,targetVersion){
8967
9055
  btnEl.disabled=true;
8968
9056
  btnEl.textContent=t('update.installing');
8969
9057
  btnEl.style.cssText='background:rgba(99,102,241,.15);color:var(--pri);border:1px solid rgba(99,102,241,.3);border-radius:6px;padding:4px 14px;font-size:12px;font-weight:600;cursor:wait;white-space:nowrap';
8970
- fetch('/api/update-install',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({packageSpec:packageSpec})})
9058
+ fetch('/api/update-install',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({packageSpec:packageSpec,targetVersion:targetVersion||''})})
8971
9059
  .then(function(r){return r.json()})
8972
9060
  .then(function(d){
8973
9061
  if(d.ok){
@@ -8990,11 +9078,11 @@ function doUpdateInstall(packageSpec,btnEl,statusEl){
8990
9078
  }
8991
9079
  async function checkForUpdate(){
8992
9080
  try{
8993
- const r=await fetch('/api/update-check');
9081
+ const r=await fetch('/api/update-check?_t='+Date.now(),{cache:'no-store'});
8994
9082
  if(!r.ok)return;
8995
9083
  const d=await r.json();
8996
9084
  if(!d.updateAvailable)return;
8997
- const pkgSpec=d.installCommand?d.installCommand.replace(/^(?:npx\s+)?openclaw\s+plugins\s+install\s+/,''):(d.packageName+'@'+d.latest);
9085
+ const pkgSpec=d.packageName+'@'+d.latest;
8998
9086
  var bannerWrap=document.createElement('div');
8999
9087
  bannerWrap.id='updateBannerWrap';
9000
9088
  bannerWrap.style.cssText='background:linear-gradient(135deg,rgba(99,102,241,.08),rgba(139,92,246,.06));border-bottom:1px solid rgba(99,102,241,.18);backdrop-filter:blur(8px);animation:slideIn .3s ease';
@@ -9011,7 +9099,7 @@ async function checkForUpdate(){
9011
9099
  btnUpdate.onmouseleave=function(){this.style.opacity='1';this.style.transform='scale(1)'};
9012
9100
  var statusDiv=document.createElement('div');
9013
9101
  statusDiv.style.cssText='font-size:11px;opacity:.7;flex-shrink:0';
9014
- btnUpdate.onclick=function(){doUpdateInstall(pkgSpec,btnUpdate,statusDiv)};
9102
+ btnUpdate.onclick=function(){doUpdateInstall(pkgSpec,btnUpdate,statusDiv,d.latest)};
9015
9103
  textNode.appendChild(btnUpdate);
9016
9104
  var spacer=document.createElement('div');
9017
9105
  spacer.style.cssText='flex:1';