@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.
@@ -197,65 +197,90 @@ input,textarea,select{font-family:inherit;font-size:inherit}
197
197
  .pending-user-name{font-size:14px;font-weight:700;color:var(--text)}
198
198
  .pending-user-meta{font-size:12px;color:var(--text-sec);margin-top:4px}
199
199
  .pending-user-actions{display:flex;gap:8px;margin-top:10px}
200
- /* ─── Admin Panel ─── */
201
- .admin-header{position:relative;padding:28px 28px 20px;background:linear-gradient(135deg,rgba(99,102,241,.08) 0%,rgba(139,92,246,.06) 50%,rgba(6,182,212,.05) 100%);border:1px solid rgba(99,102,241,.12);border-radius:16px;margin-bottom:20px;overflow:hidden}
202
- .admin-header::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,var(--violet),var(--pri),var(--cyan));border-radius:16px 16px 0 0}
203
- .admin-header-top{display:flex;justify-content:space-between;align-items:center}
204
- .admin-header h2{font-size:20px;font-weight:800;color:var(--text);display:flex;align-items:center;gap:10px;margin:0}
205
- .admin-header h2 .ah-icon{width:36px;height:36px;border-radius:10px;background:linear-gradient(135deg,var(--pri),var(--violet));display:flex;align-items:center;justify-content:center;font-size:18px;box-shadow:0 4px 12px rgba(99,102,241,.25)}
206
- .admin-header-sub{font-size:12px;color:var(--text-muted);margin-top:6px}
207
- .admin-stat-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-top:18px}
208
- .admin-stat-box{position:relative;text-align:center;padding:16px 8px 14px;background:var(--bg-card);border:1px solid var(--border);border-radius:12px;overflow:hidden;transition:all .2s}
209
- .admin-stat-box:hover{border-color:rgba(99,102,241,.25);transform:translateY(-1px);box-shadow:0 4px 12px rgba(0,0,0,.06)}
210
- .admin-stat-box::before{content:'';position:absolute;top:0;left:50%;transform:translateX(-50%);width:40px;height:2px;border-radius:0 0 4px 4px}
211
- .admin-stat-box:nth-child(1)::before{background:var(--green)}
212
- .admin-stat-box:nth-child(2)::before{background:var(--amber)}
213
- .admin-stat-box:nth-child(3)::before{background:var(--violet)}
214
- .admin-stat-box:nth-child(4)::before{background:var(--cyan)}
215
- .admin-stat-box:nth-child(5)::before{background:var(--pri)}
216
- .admin-stat-box:nth-child(6)::before{background:var(--rose)}
217
- .admin-stat-box .as-icon{font-size:16px;margin-bottom:4px;display:block}
218
- .admin-stat-box .val{font-size:22px;font-weight:800;color:var(--text);font-variant-numeric:tabular-nums}
219
- .admin-stat-box .lbl{font-size:10px;color:var(--text-muted);margin-top:3px;letter-spacing:.03em}
220
- .admin-tabs{display:flex;gap:4px;padding:4px;background:var(--bg);border:1px solid var(--border);border-radius:14px;overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:20px}
221
- .admin-tab{position:relative;display:flex;align-items:center;gap:6px;padding:9px 16px;border:none;background:transparent;color:var(--text-muted);font-size:13px;font-weight:500;cursor:pointer;border-radius:10px;transition:all .2s;white-space:nowrap;font-family:inherit}
222
- .admin-tab:hover{background:rgba(99,102,241,.06);color:var(--text)}
223
- .admin-tab.active{background:var(--bg-card);color:var(--text);font-weight:600;box-shadow:0 2px 8px rgba(0,0,0,.06),0 0 0 1px rgba(99,102,241,.1)}
200
+ /* ─── Admin Panel (Cyber) ─── */
201
+ @keyframes adminGlow{0%,100%{opacity:.6}50%{opacity:1}}
202
+ @keyframes adminPulse{0%{box-shadow:0 0 0 0 rgba(99,102,241,.4)}70%{box-shadow:0 0 0 8px rgba(99,102,241,0)}100%{box-shadow:0 0 0 0 rgba(99,102,241,0)}}
203
+ @keyframes adminScanline{0%{background-position:0 0}100%{background-position:0 100%}}
204
+ @keyframes adminSlideIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
205
+ @keyframes adminCountUp{from{opacity:0;transform:translateY(8px) scale(.8)}to{opacity:1;transform:translateY(0) scale(1)}}
206
+ @keyframes pendingPulse{0%,100%{border-color:rgba(251,191,36,.3)}50%{border-color:rgba(251,191,36,.7)}}
207
+ @keyframes dotBreathe{0%,100%{transform:scale(1);opacity:.8}50%{transform:scale(1.3);opacity:1}}
208
+ .admin-header{position:relative;padding:32px 32px 24px;background:linear-gradient(135deg,rgba(99,102,241,.06) 0%,rgba(6,182,212,.04) 50%,rgba(139,92,246,.06) 100%);border:1px solid rgba(99,102,241,.15);border-radius:20px;margin-bottom:24px;overflow:hidden}
209
+ .admin-header::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--pri),var(--cyan),var(--violet),transparent);animation:adminGlow 3s ease-in-out infinite}
210
+ .admin-header::after{content:'';position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(99,102,241,.015) 2px,rgba(99,102,241,.015) 4px);background-size:100% 8px;animation:adminScanline 8s linear infinite;pointer-events:none}
211
+ .admin-header-top{display:flex;justify-content:space-between;align-items:center;position:relative;z-index:1}
212
+ .admin-header h2{font-size:18px;font-weight:800;color:var(--text);display:flex;align-items:center;gap:12px;margin:0;letter-spacing:-.01em}
213
+ .admin-header h2 .ah-icon{width:40px;height:40px;border-radius:12px;background:linear-gradient(135deg,var(--pri),var(--violet));display:flex;align-items:center;justify-content:center;font-size:20px;box-shadow:0 4px 20px rgba(99,102,241,.3),inset 0 1px 0 rgba(255,255,255,.15);animation:adminPulse 2.5s infinite}
214
+ .admin-header-sub{font-size:11px;color:var(--text-muted);margin-top:6px;position:relative;z-index:1;letter-spacing:.02em}
215
+ .admin-stat-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px;margin-top:20px;position:relative;z-index:1}
216
+ .admin-stat-box{position:relative;text-align:center;padding:18px 10px 16px;background:rgba(var(--bg-card-rgb,30,30,40),.6);backdrop-filter:blur(12px);border:1px solid rgba(99,102,241,.12);border-radius:14px;overflow:hidden;transition:all .25s cubic-bezier(.4,0,.2,1)}
217
+ .admin-stat-box:hover{border-color:rgba(99,102,241,.35);transform:translateY(-2px);box-shadow:0 8px 24px rgba(99,102,241,.12)}
218
+ .admin-stat-box::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;opacity:.8}
219
+ .admin-stat-box:nth-child(1)::before{background:linear-gradient(90deg,transparent,#22c55e,transparent)}
220
+ .admin-stat-box:nth-child(2)::before{background:linear-gradient(90deg,transparent,#fbbf24,transparent)}
221
+ .admin-stat-box:nth-child(3)::before{background:linear-gradient(90deg,transparent,#8b5cf6,transparent)}
222
+ .admin-stat-box:nth-child(4)::before{background:linear-gradient(90deg,transparent,#06b6d4,transparent)}
223
+ .admin-stat-box:nth-child(5)::before{background:linear-gradient(90deg,transparent,#6366f1,transparent)}
224
+ .admin-stat-box:nth-child(6)::before{background:linear-gradient(90deg,transparent,#f43f5e,transparent)}
225
+ .admin-stat-box::after{content:'';position:absolute;inset:0;background:radial-gradient(circle at 50% 0%,rgba(99,102,241,.06),transparent 70%);pointer-events:none}
226
+ .admin-stat-box .as-icon{font-size:18px;margin-bottom:6px;display:block;filter:drop-shadow(0 2px 4px rgba(0,0,0,.15))}
227
+ .admin-stat-box .val{font-size:26px;font-weight:800;color:var(--text);font-variant-numeric:tabular-nums;animation:adminCountUp .4s ease-out;text-shadow:0 0 20px rgba(99,102,241,.15)}
228
+ .admin-stat-box .lbl{font-size:10px;color:var(--text-muted);margin-top:4px;letter-spacing:.05em;text-transform:uppercase}
229
+ .admin-tabs{display:flex;gap:3px;padding:3px;background:rgba(99,102,241,.03);border:1px solid rgba(99,102,241,.1);border-radius:14px;overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:24px;backdrop-filter:blur(8px)}
230
+ .admin-tab{position:relative;display:flex;align-items:center;gap:6px;padding:10px 18px;border:none;background:transparent;color:var(--text-muted);font-size:13px;font-weight:500;cursor:pointer;border-radius:11px;transition:all .25s cubic-bezier(.4,0,.2,1);white-space:nowrap;font-family:inherit}
231
+ .admin-tab:hover{background:rgba(99,102,241,.08);color:var(--text)}
232
+ .admin-tab.active{background:linear-gradient(135deg,rgba(99,102,241,.12),rgba(139,92,246,.08));color:var(--text);font-weight:600;box-shadow:0 2px 12px rgba(99,102,241,.1),inset 0 1px 0 rgba(255,255,255,.05);border:1px solid rgba(99,102,241,.15)}
224
233
  .admin-tab .at-icon{font-size:14px;line-height:1}
225
- .admin-tab .at-count{font-size:10px;font-weight:700;padding:1px 6px;border-radius:8px;background:rgba(99,102,241,.1);color:var(--pri);min-width:18px;text-align:center}
226
- .admin-tab.active .at-count{background:rgba(99,102,241,.15)}
234
+ .admin-tab .at-count{font-size:10px;font-weight:700;padding:2px 7px;border-radius:8px;background:rgba(99,102,241,.12);color:var(--pri);min-width:18px;text-align:center;transition:all .2s}
235
+ .admin-tab.active .at-count{background:rgba(99,102,241,.2);box-shadow:0 0 8px rgba(99,102,241,.15)}
227
236
  .admin-panel{display:none}
228
- .admin-panel.active{display:block}
229
- .admin-card{border:1px solid var(--border);border-radius:12px;padding:16px 18px;background:var(--bg-card);margin-bottom:10px;transition:all .2s;position:relative;overflow:hidden}
237
+ .admin-panel.active{display:block;animation:adminSlideIn .3s ease-out}
238
+ .admin-card{border:1px solid var(--border);border-radius:14px;padding:18px 20px;background:var(--bg-card);margin-bottom:12px;transition:all .25s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}
230
239
  .admin-card-clickable{cursor:pointer}
231
- .admin-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--pri);opacity:.5}
232
- .admin-card:hover{border-color:rgba(99,102,241,.25);box-shadow:0 2px 12px rgba(0,0,0,.04);transform:translateY(-1px)}
240
+ .admin-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--pri);opacity:.4;transition:opacity .2s}
241
+ .admin-card:hover{border-color:rgba(99,102,241,.25);box-shadow:0 4px 20px rgba(99,102,241,.06);transform:translateY(-1px)}
242
+ .admin-card:hover::before{opacity:.8}
233
243
  .admin-card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
234
244
  .admin-card-title{font-size:14px;font-weight:700;color:var(--text);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
235
245
  .admin-card-meta{font-size:12px;color:var(--text-muted);line-height:1.5}
236
- .au-contrib{display:flex;gap:16px;padding:10px 0;margin:6px 0;border-top:1px solid var(--border);border-bottom:1px solid var(--border)}
237
- .au-contrib-item{font-size:12px;color:var(--text-sec);display:flex;align-items:center;gap:4px}
238
- .au-contrib-num{font-size:18px;font-weight:700;line-height:1}
239
- .au-info{display:flex;flex-wrap:wrap;gap:6px 14px;padding:8px 0;font-size:12px}
240
- .au-info-item{color:var(--text-muted);white-space:nowrap}
241
- .au-status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:4px;vertical-align:middle;flex-shrink:0}
242
- .au-status-dot.online{background:#22c55e;box-shadow:0 0 6px rgba(34,197,94,.5)}
243
- .au-status-dot.offline{background:#9ca3af}
244
- .au-status-text{font-size:11px;font-weight:500}
245
- .au-status-text.online{color:#22c55e}
246
- .au-status-text.offline{color:#9ca3af}
247
- .au-group-header{font-size:13px;font-weight:600;color:var(--text-sec);margin:18px 0 8px;display:flex;align-items:center;gap:8px}
246
+ .au-contrib{display:flex;gap:20px;padding:12px 0;margin:8px 0;border-top:1px solid rgba(99,102,241,.08);border-bottom:1px solid rgba(99,102,241,.08)}
247
+ .au-contrib-item{font-size:12px;color:var(--text-sec);display:flex;align-items:center;gap:5px}
248
+ .au-contrib-num{font-size:20px;font-weight:800;line-height:1;font-variant-numeric:tabular-nums}
249
+ .au-info{display:flex;flex-wrap:wrap;gap:6px 16px;padding:8px 0;font-size:11px}
250
+ .au-info-item{color:var(--text-muted);white-space:nowrap;display:inline-flex;align-items:center;gap:3px}
251
+ .au-status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:5px;vertical-align:middle;flex-shrink:0;transition:all .3s}
252
+ .au-status-dot.online{background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.6),0 0 16px rgba(34,197,94,.2);animation:dotBreathe 2s ease-in-out infinite}
253
+ .au-status-dot.offline{background:#6b7280;box-shadow:none}
254
+ .au-status-text{font-size:11px;font-weight:600;letter-spacing:.02em}
255
+ .au-status-text.online{color:#22c55e;text-shadow:0 0 8px rgba(34,197,94,.3)}
256
+ .au-status-text.offline{color:#6b7280}
257
+ .au-group-header{font-size:13px;font-weight:700;color:var(--text-sec);margin:20px 0 10px;display:flex;align-items:center;gap:8px;letter-spacing:.02em}
248
258
  .au-group-header:first-child{margin-top:0}
249
259
  .au-group-header .au-group-dot{display:inline-block;width:8px;height:8px;border-radius:50%}
250
- .au-group-header .au-group-dot.online{background:#22c55e}
251
- .au-group-header .au-group-dot.offline{background:#9ca3af}
260
+ .au-group-header .au-group-dot.online{background:#22c55e;box-shadow:0 0 6px rgba(34,197,94,.5)}
261
+ .au-group-header .au-group-dot.offline{background:#6b7280}
252
262
  .au-group-header .au-group-count{font-size:12px;font-weight:400;color:var(--text-muted)}
253
- .au-card.au-offline{opacity:.7}
254
- .au-card.au-offline::before{background:#9ca3af}
255
- .au-card.au-online::before{background:#22c55e}
263
+ .au-card.au-offline{opacity:.55}
264
+ .au-card.au-offline:hover{opacity:.8}
265
+ .au-card.au-offline::before{background:#6b7280}
266
+ .au-card.au-online::before{background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.3)}
267
+ .admin-pending-section{position:relative;margin-bottom:20px;padding:20px;border-radius:16px;border:1px solid rgba(251,191,36,.25);background:linear-gradient(135deg,rgba(251,191,36,.04),rgba(245,158,11,.02));animation:pendingPulse 3s ease-in-out infinite;overflow:hidden}
268
+ .admin-pending-section::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,#fbbf24,#f59e0b,transparent)}
269
+ .admin-pending-section h3{font-size:14px;font-weight:700;color:#fbbf24;margin:0 0 14px;display:flex;align-items:center;gap:8px}
270
+ .admin-pending-section h3 .pending-count{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:22px;padding:0 6px;border-radius:11px;background:rgba(251,191,36,.2);font-size:12px;font-weight:800;color:#fbbf24}
271
+ .admin-pending-card{border:1px solid rgba(251,191,36,.15);border-radius:12px;padding:16px 18px;background:rgba(251,191,36,.03);margin-bottom:8px;transition:all .2s;position:relative;overflow:hidden}
272
+ .admin-pending-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;background:linear-gradient(180deg,#fbbf24,#f59e0b);border-radius:3px 0 0 3px}
273
+ .admin-pending-card:hover{border-color:rgba(251,191,36,.35);box-shadow:0 4px 16px rgba(251,191,36,.08)}
274
+ .admin-pending-card .apc-name{font-size:14px;font-weight:700;color:var(--text)}
275
+ .admin-pending-card .apc-meta{font-size:11px;color:var(--text-muted);margin-top:4px;display:flex;align-items:center;gap:6px}
276
+ .admin-pending-card .apc-actions{display:flex;gap:8px;margin-top:12px}
277
+ .admin-pending-card .apc-actions .btn-approve{background:linear-gradient(135deg,#22c55e,#16a34a);color:#fff;border:none;padding:6px 18px;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s;box-shadow:0 2px 8px rgba(34,197,94,.25)}
278
+ .admin-pending-card .apc-actions .btn-approve:hover{transform:translateY(-1px);box-shadow:0 4px 16px rgba(34,197,94,.35)}
279
+ .admin-pending-card .apc-actions .btn-reject{background:transparent;color:var(--rose);border:1px solid rgba(244,63,94,.2);padding:6px 14px;border-radius:8px;font-size:12px;font-weight:500;cursor:pointer;transition:all .2s}
280
+ .admin-pending-card .apc-actions .btn-reject:hover{background:rgba(244,63,94,.06);border-color:rgba(244,63,94,.4)}
256
281
  .admin-card-tags{display:flex;gap:5px;margin:8px 0;align-items:center}
257
282
  .admin-card-tags-left{display:flex;flex-wrap:wrap;gap:5px;align-items:center;flex:1;min-width:0}
258
- .admin-card-tag{display:inline-flex;align-items:center;gap:3px;padding:2px 8px;border-radius:6px;font-size:11px;font-weight:500}
283
+ .admin-card-tag{display:inline-flex;align-items:center;gap:3px;padding:3px 10px;border-radius:6px;font-size:11px;font-weight:600;letter-spacing:.01em}
259
284
  .admin-card-tag.tag-role{background:rgba(99,102,241,.1);color:var(--pri)}
260
285
  .admin-card-tag.tag-kind{background:rgba(245,158,11,.1);color:#f59e0b}
261
286
  .admin-card-tag.tag-owner{background:rgba(34,197,94,.1);color:#22c55e}
@@ -263,16 +288,16 @@ input,textarea,select{font-family:inherit;font-size:inherit}
263
288
  .admin-card-tag.tag-version{background:rgba(139,92,246,.1);color:#8b5cf6}
264
289
  .admin-card-tag.tag-visibility{background:rgba(99,102,241,.08);color:var(--pri)}
265
290
  .admin-card-tag.tag-group{background:rgba(139,92,246,.08);color:#8b5cf6}
266
- .admin-card-preview{font-size:12px;color:var(--text-sec);line-height:1.5;margin:8px 0;padding:8px 10px;background:var(--bg);border-radius:8px;border:1px solid var(--border);max-height:60px;overflow:hidden;white-space:pre-wrap;word-break:break-all}
267
- .admin-card-actions{display:inline-flex;gap:4px;margin-left:auto;align-items:center;flex-shrink:0}
291
+ .admin-card-preview{font-size:12px;color:var(--text-sec);line-height:1.5;margin:8px 0;padding:10px 12px;background:rgba(99,102,241,.02);border-radius:10px;border:1px solid rgba(99,102,241,.08);max-height:60px;overflow:hidden;white-space:pre-wrap;word-break:break-all}
292
+ .admin-card-actions{display:inline-flex;gap:6px;margin-left:auto;align-items:center;flex-shrink:0}
268
293
  .admin-card-time{font-size:11px;color:var(--text-muted)}
269
- .admin-card-detail{display:none;margin-top:0;padding:20px 24px 24px;border-top:1px dashed var(--border);background:linear-gradient(180deg,rgba(99,102,241,.015) 0%,var(--bg) 60%);animation:adminDetailIn .25s ease}
294
+ .admin-card-detail{display:none;margin-top:0;padding:20px 24px 24px;border-top:1px dashed rgba(99,102,241,.12);background:linear-gradient(180deg,rgba(99,102,241,.02) 0%,transparent 60%);animation:adminDetailIn .25s ease}
270
295
  @keyframes adminDetailIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}
271
296
  .admin-card.expanded .admin-card-detail{display:block}
272
- .admin-card.expanded{border-color:rgba(99,102,241,.3);box-shadow:0 4px 24px rgba(99,102,241,.08),0 0 0 1px rgba(99,102,241,.06)}
297
+ .admin-card.expanded{border-color:rgba(99,102,241,.3);box-shadow:0 4px 24px rgba(99,102,241,.1),0 0 0 1px rgba(99,102,241,.08)}
273
298
  .admin-card-detail-meta{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:18px;font-size:12px;color:var(--text-muted)}
274
- .admin-card-detail-meta .meta-item{display:inline-flex;align-items:center;gap:4px;padding:5px 12px;background:var(--bg-card);border:1px solid var(--border);border-radius:20px;font-size:11px;color:var(--text-sec);transition:border-color .15s,background .15s}
275
- .admin-card-detail-meta .meta-item:hover{border-color:rgba(99,102,241,.25);background:rgba(99,102,241,.03)}
299
+ .admin-card-detail-meta .meta-item{display:inline-flex;align-items:center;gap:4px;padding:5px 12px;background:rgba(99,102,241,.03);border:1px solid rgba(99,102,241,.08);border-radius:20px;font-size:11px;color:var(--text-sec);transition:all .2s}
300
+ .admin-card-detail-meta .meta-item:hover{border-color:rgba(99,102,241,.25);background:rgba(99,102,241,.06)}
276
301
  .admin-card-detail-section{margin-top:20px}
277
302
  .admin-card-detail-section .detail-label{font-size:11px;font-weight:700;color:var(--pri);margin-bottom:12px;text-transform:uppercase;letter-spacing:.06em;display:flex;align-items:center;gap:8px}
278
303
  .admin-card-detail-section .detail-label::before{content:'';width:3px;height:14px;border-radius:2px;background:linear-gradient(180deg,var(--pri),rgba(99,102,241,.3))}
@@ -306,18 +331,20 @@ input,textarea,select{font-family:inherit;font-size:inherit}
306
331
  .admin-toolbar{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap}
307
332
  .admin-toolbar h3{font-size:14px;font-weight:600;color:var(--text);white-space:nowrap;margin:0;margin-right:auto;line-height:32px}
308
333
  .admin-toolbar select{box-sizing:border-box;height:32px;font-size:12px;border:1px solid var(--border);border-radius:8px;background:var(--bg-card);color:var(--text);vertical-align:middle;margin:0;padding:0 10px}
309
- .admin-badge{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:700;padding:3px 10px;border-radius:999px;letter-spacing:.02em}
310
- .admin-badge.admin{background:rgba(52,199,89,.15);color:#34c759}
311
- .admin-badge.member{background:rgba(142,142,147,.12);color:var(--text-muted)}
312
- .admin-badge.pending{background:rgba(255,159,10,.15);color:#ff9f0a}
334
+ .admin-badge{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:700;padding:3px 10px;border-radius:999px;letter-spacing:.03em;text-transform:uppercase}
335
+ .admin-badge.admin{background:linear-gradient(135deg,rgba(34,197,94,.15),rgba(16,185,129,.1));color:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.1)}
336
+ .admin-badge.member{background:rgba(99,102,241,.08);color:var(--text-muted)}
337
+ .admin-badge.pending{background:linear-gradient(135deg,rgba(251,191,36,.2),rgba(245,158,11,.1));color:#fbbf24;box-shadow:0 0 8px rgba(251,191,36,.1)}
313
338
  .admin-badge.public{background:rgba(99,102,241,.1);color:var(--pri)}
314
339
  .admin-badge.group{background:rgba(139,92,246,.1);color:var(--violet)}
315
- .admin-empty{font-size:13px;color:var(--text-muted);padding:40px 20px;text-align:center;border:1px dashed var(--border);border-radius:12px;background:var(--bg)}
316
- .admin-empty .ae-icon{font-size:28px;display:block;margin-bottom:8px;opacity:.5}
340
+ .admin-empty{font-size:13px;color:var(--text-muted);padding:48px 24px;text-align:center;border:1px dashed rgba(99,102,241,.15);border-radius:16px;background:rgba(99,102,241,.02)}
341
+ .admin-empty .ae-icon{font-size:32px;display:block;margin-bottom:10px;opacity:.4}
317
342
  [data-theme="light"] .admin-badge.admin{background:rgba(5,150,105,.1);color:#059669}
318
343
  [data-theme="light"] .admin-badge.member{background:rgba(0,0,0,.06);color:#6b7280}
319
344
  [data-theme="light"] .admin-badge.pending{background:rgba(245,158,11,.1);color:#d97706}
320
- [data-theme="light"] .admin-header{background:linear-gradient(135deg,rgba(99,102,241,.05) 0%,rgba(139,92,246,.04) 50%,rgba(6,182,212,.03) 100%)}
345
+ [data-theme="light"] .admin-header{background:linear-gradient(135deg,rgba(99,102,241,.04) 0%,rgba(6,182,212,.03) 50%,rgba(139,92,246,.04) 100%)}
346
+ [data-theme="light"] .admin-stat-box{background:rgba(255,255,255,.8)}
347
+ [data-theme="light"] .admin-pending-section{background:linear-gradient(135deg,rgba(251,191,36,.03),rgba(245,158,11,.015))}
321
348
  .confirm-overlay{display:none;position:fixed;inset:0;align-items:center;justify-content:center;background:rgba(0,0,0,.45);backdrop-filter:blur(4px);z-index:9999;padding:20px}
322
349
  .confirm-overlay.show{display:flex}
323
350
  .confirm-panel{width:min(400px,90vw);background:var(--bg-card);border:1px solid var(--border);border-radius:16px;box-shadow:0 20px 60px rgba(0,0,0,.2);overflow:hidden;animation:confirmIn .2s ease}
@@ -1789,8 +1816,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
1789
1816
  <div id="adminMainContent">
1790
1817
  <div class="admin-header">
1791
1818
  <div class="admin-header-top">
1792
- <h2><span class="ah-icon">\u{1F6E1}</span> <span data-i18n="admin.title">Team Admin Panel</span></h2>
1793
- <button class="btn btn-sm btn-ghost" onclick="loadAdminData()" style="backdrop-filter:blur(8px)" data-i18n="admin.refresh">\u21BB Refresh</button>
1819
+ <h2><span class="ah-icon">\u{26A1}</span> <span data-i18n="admin.title">Team Admin Panel</span></h2>
1794
1820
  </div>
1795
1821
  <div class="admin-header-sub" data-i18n="admin.subtitle">Manage team members and shared resources</div>
1796
1822
  <div class="admin-stat-row" id="adminStats"></div>
@@ -2003,7 +2029,9 @@ input,textarea,select{font-family:inherit;font-size:inherit}
2003
2029
  <script>
2004
2030
  let activeSession=null,activeRole='',editingId=null,searchTimer=null,memoryCache={},currentPage=1,totalPages=1,totalCount=0,PAGE_SIZE=40,metricsDays=30;
2005
2031
  let memorySearchScope='local',skillSearchScope='local',taskSearchScope='local';
2032
+ let _lastMemoriesFingerprint='',_lastTasksFingerprint='',_lastSkillsFingerprint='';
2006
2033
  let _embeddingWarningShown=false;
2034
+ let _currentAgentOwner='agent:main';
2007
2035
 
2008
2036
  /* ─── i18n ─── */
2009
2037
  const I18N={
@@ -2392,6 +2420,7 @@ const I18N={
2392
2420
  'settings.hub.userToken.hint':'Usually auto-obtained after joining. Only fill if given by admin.',
2393
2421
  'settings.hub.testConnection':'Test Connection',
2394
2422
  'settings.hub.test.noAddr':'Please enter server address first',
2423
+ 'settings.hub.teamToken.required':'Please enter team token',
2395
2424
  'settings.hub.test.testing':'Testing...',
2396
2425
  'settings.hub.test.ok':'Connected successfully',
2397
2426
  'settings.hub.test.fail':'Connection failed',
@@ -2525,6 +2554,7 @@ const I18N={
2525
2554
  'admin.groupsFailed':'Failed to load groups: ',
2526
2555
  'toast.userApproved':'User approved',
2527
2556
  'sharing.approved.toast':'Your join request has been approved!',
2557
+ 'sharing.rejected.toast':'Your join request was rejected by the admin.',
2528
2558
  'toast.userRejected':'User rejected',
2529
2559
  'toast.approveFail':'Approve failed',
2530
2560
  'toast.rejectFail':'Reject failed',
@@ -2685,6 +2715,8 @@ const I18N={
2685
2715
  'sharing.disable.confirm.hub':'You are about to shut down the team server.\\n\\nWhat will happen:\\n\\u2022 All connected team members will be disconnected\\n\\u2022 They will no longer be able to sync memories, tasks, or skills\\n\\u2022 Shared data is preserved and will be available when you re-enable\\n\\nAre you sure?',
2686
2716
  'sharing.disable.confirm.client':'You are about to disconnect from the team.\\n\\nWhat will happen:\\n\\u2022 You will no longer receive shared memories, tasks, or skills from the team\\n\\u2022 Your local data is preserved and will not be affected\\n\\u2022 You can reconnect later by re-enabling sharing\\n\\nAre you sure?',
2687
2717
  'sharing.disable.restartAlert':'Sharing has been disabled. Please restart the OpenClaw gateway for the change to take effect.\\n\\nRun: openclaw gateway stop && openclaw gateway start',
2718
+ 'sharing.switch.hubToClient':'You are about to switch from Server to Client mode.\\n\\nWhat will happen:\\n\\u2022 The Hub server will shut down after restart\\n\\u2022 All connected team members will be disconnected\\n\\u2022 Shared data on the Hub is preserved for future use\\n\\u2022 You will join the specified remote team as a client\\n\\nAre you sure?',
2719
+ 'sharing.switch.clientToHub':'You are about to switch from Client to Server mode.\\n\\nWhat will happen:\\n\\u2022 You will disconnect from the current team\\n\\u2022 A new Hub server will start after restart\\n\\u2022 Your local data is not affected\\n\\nAre you sure?',
2688
2720
  'admin.notEnabled.title':'Team sharing is not enabled',
2689
2721
  'admin.notEnabled.desc':'The Admin Panel is used to manage team members, shared memories, tasks, and skills. To use this feature, you need to enable team sharing first.',
2690
2722
  'admin.notEnabled.setupHub':'Set Up as Team Server',
@@ -3097,6 +3129,7 @@ const I18N={
3097
3129
  'settings.hub.userToken.hint':'通常在加入团队后自动获取,无需手动填写。',
3098
3130
  'settings.hub.testConnection':'测试连接',
3099
3131
  'settings.hub.test.noAddr':'请先输入服务器地址',
3132
+ 'settings.hub.teamToken.required':'请输入团队令牌',
3100
3133
  'settings.hub.test.testing':'测试中...',
3101
3134
  'settings.hub.test.ok':'连接成功',
3102
3135
  'settings.hub.test.fail':'连接失败',
@@ -3230,6 +3263,7 @@ const I18N={
3230
3263
  'admin.groupsFailed':'加载分组失败:',
3231
3264
  'toast.userApproved':'用户已批准',
3232
3265
  'sharing.approved.toast':'您的加入申请已通过审核!',
3266
+ 'sharing.rejected.toast':'您的加入申请已被管理员拒绝。',
3233
3267
  'toast.userRejected':'用户已拒绝',
3234
3268
  'toast.approveFail':'批准失败',
3235
3269
  'toast.rejectFail':'拒绝失败',
@@ -3390,6 +3424,8 @@ const I18N={
3390
3424
  'sharing.disable.confirm.hub':'你即将关闭团队服务。\\n\\n关闭后将会:\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 他们将无法继续同步记忆、任务和技能\\n\\u2022 已共享的数据会保留,重新开启后仍可使用\\n\\n确定要关闭吗?',
3391
3425
  'sharing.disable.confirm.client':'你即将断开与团队的连接。\\n\\n断开后将会:\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以随时重新开启共享来恢复连接\\n\\n确定要断开吗?',
3392
3426
  'sharing.disable.restartAlert':'共享已关闭。请重启 OpenClaw 网关使更改生效。\\n\\n执行命令:openclaw gateway stop && openclaw gateway start',
3427
+ 'sharing.switch.hubToClient':'你即将从服务端模式切换为客户端模式。\\n\\n切换后将会:\\n\\u2022 Hub 服务将在重启后关闭\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 Hub 上的共享数据会保留,以后可恢复使用\\n\\u2022 你将作为客户端加入指定的远程团队\\n\\n确定要切换吗?',
3428
+ 'sharing.switch.clientToHub':'你即将从客户端模式切换为服务端模式。\\n\\n切换后将会:\\n\\u2022 你将断开与当前团队的连接\\n\\u2022 重启后将启动新的 Hub 服务\\n\\u2022 你的本地数据不受影响\\n\\n确定要切换吗?',
3393
3429
  'admin.notEnabled.title':'团队共享尚未开启',
3394
3430
  'admin.notEnabled.desc':'管理面板用于管理团队成员、共享的记忆、任务和技能。使用此功能前,需要先开启团队共享。',
3395
3431
  'admin.notEnabled.setupHub':'配置为团队服务端',
@@ -3652,16 +3688,24 @@ function switchView(view){
3652
3688
 
3653
3689
  function onMemoryScopeChange(){
3654
3690
  memorySearchScope=document.getElementById('memorySearchScope')?.value||'local';
3691
+ currentPage=1;
3692
+ activeSession=null;activeRole='';
3693
+ _lastMemoriesFingerprint='';
3655
3694
  var isHub=memorySearchScope==='hub';
3695
+ var isLocal=memorySearchScope==='local';
3656
3696
  var ownerSel=document.getElementById('filterOwner');
3657
3697
  var filterBar=document.getElementById('filterBar');
3658
3698
  var dateFilter=document.querySelector('.date-filter');
3659
- if(ownerSel) ownerSel.style.display=isHub?'none':'';
3699
+ if(ownerSel) ownerSel.style.display=(isHub||isLocal)?'none':'';
3660
3700
  if(filterBar) filterBar.style.display=isHub?'none':'';
3661
3701
  if(dateFilter) dateFilter.style.display=isHub?'none':'';
3662
3702
  if(document.getElementById('searchInput').value.trim()) doSearch(document.getElementById('searchInput').value);
3663
3703
  else if(isHub) { document.getElementById('sharingSearchMeta').textContent=''; loadHubMemories(); }
3664
- else { document.getElementById('sharingSearchMeta').textContent=''; loadStats(); loadMemories(); }
3704
+ else {
3705
+ document.getElementById('sharingSearchMeta').textContent='';
3706
+ var ownerArg=isLocal?_currentAgentOwner:undefined;
3707
+ loadStats(ownerArg); loadMemories();
3708
+ }
3665
3709
  }
3666
3710
 
3667
3711
  function onSkillScopeChange(){
@@ -3676,6 +3720,7 @@ function onTaskScopeChange(){
3676
3720
  }
3677
3721
 
3678
3722
  var _clientPendingPollTimer=null;
3723
+ var _lastSharingConnStatus='';
3679
3724
  async function loadSharingStatus(forcePending){
3680
3725
  try{
3681
3726
  const r=await fetch('/api/sharing/status');
@@ -3685,13 +3730,26 @@ async function loadSharingStatus(forcePending){
3685
3730
  renderSharingSettings(d);
3686
3731
  updateTeamGuide(d);
3687
3732
  if(forcePending && d && d.admin && d.admin.canManageUsers) loadSharingPendingUsers();
3688
- var conn=d&&d.connection||{};
3689
- if(conn.pendingApproval&&!_clientPendingPollTimer){
3733
+ if(!d||!d.enabled){
3734
+ if(_clientPendingPollTimer){clearInterval(_clientPendingPollTimer);_clientPendingPollTimer=null;}
3735
+ _lastSharingConnStatus='';
3736
+ return;
3737
+ }
3738
+ var conn=d.connection||{};
3739
+ var curStatus=conn.rejected?'rejected':conn.pendingApproval?'pending':conn.connected?'connected':'none';
3740
+ if(_lastSharingConnStatus==='pending'&&curStatus==='rejected'){
3741
+ toast(t('sharing.rejected.toast'),'error');
3742
+ }
3743
+ if(_lastSharingConnStatus==='pending'&&curStatus==='connected'){
3744
+ toast(t('sharing.approved.toast'),'success');
3745
+ }
3746
+ _lastSharingConnStatus=curStatus;
3747
+ if(curStatus==='pending'&&!_clientPendingPollTimer){
3690
3748
  _clientPendingPollTimer=setInterval(function(){loadSharingStatus(false);},10000);
3691
- }else if(!conn.pendingApproval&&_clientPendingPollTimer){
3749
+ }
3750
+ if(curStatus!=='pending'&&_clientPendingPollTimer){
3692
3751
  clearInterval(_clientPendingPollTimer);
3693
3752
  _clientPendingPollTimer=null;
3694
- if(conn.connected) toast(t('sharing.approved.toast'),'success');
3695
3753
  }
3696
3754
  }catch(e){
3697
3755
  renderSharingSidebar(null);
@@ -3700,12 +3758,17 @@ async function loadSharingStatus(forcePending){
3700
3758
  }
3701
3759
  }
3702
3760
 
3761
+ var _lastSidebarFingerprint='';
3703
3762
  function renderSharingSidebar(data){
3704
3763
  var section=document.getElementById('sidebarSharingSection');
3705
3764
  var statusEl=document.getElementById('sharingSidebarStatus');
3706
3765
  var hintEl=document.getElementById('sharingSidebarHint');
3707
3766
  var badgeEl=document.getElementById('sharingSidebarConnBadge');
3708
3767
  if(!statusEl||!hintEl) return;
3768
+ var conn=data&&data.connection||{};
3769
+ var fp=JSON.stringify({e:!!data&&!!data.enabled,r:data&&data.role,pa:!!conn.pendingApproval,rj:!!conn.rejected,c:!!conn.connected,u:conn.user&&conn.user.username,tn:conn.teamName,cc:!!data&&!!data.clientConfigured,hu:data&&data.hubUrl});
3770
+ if(fp===_lastSidebarFingerprint) return;
3771
+ _lastSidebarFingerprint=fp;
3709
3772
  if(!data||!data.enabled){
3710
3773
  if(section) section.style.display='none';
3711
3774
  window._isHubAdmin=false;
@@ -3757,12 +3820,17 @@ function renderSharingSidebar(data){
3757
3820
  }
3758
3821
  }
3759
3822
 
3823
+ var _lastSettingsFingerprint='';
3760
3824
  function renderSharingSettings(data){
3761
3825
  var statusEl=document.getElementById('sharingStatusPanel');
3762
3826
  var teamEl=document.getElementById('sharingTeamPanel');
3763
3827
  var adminEl=document.getElementById('sharingAdminPanel');
3764
3828
  var panelsWrap=document.getElementById('sharingPanelsWrap');
3765
3829
  if(!statusEl||!teamEl||!adminEl) return;
3830
+ var conn2=data&&data.connection||{};
3831
+ var fp2=JSON.stringify({e:!!data&&!!data.enabled,r:data&&data.role,pa:!!conn2.pendingApproval,rj:!!conn2.rejected,c:!!conn2.connected,u:conn2.user&&conn2.user.username,ur:conn2.user&&conn2.user.role,tn:conn2.teamName,cc:!!data&&!!data.clientConfigured,cm:data&&data.admin&&data.admin.canManageUsers});
3832
+ if(fp2===_lastSettingsFingerprint) return;
3833
+ _lastSettingsFingerprint=fp2;
3766
3834
  if(!data||!data.enabled){
3767
3835
  statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
3768
3836
  if(panelsWrap) panelsWrap.style.display='none';
@@ -3976,6 +4044,7 @@ function guideGoToHub(role){
3976
4044
 
3977
4045
  /* ─── Hub Admin Panel ─── */
3978
4046
  var adminDataCache={users:[],groups:[],tasks:[],skills:[],memories:[]};
4047
+ var _lastAdminFingerprint='';
3979
4048
  var hubTasksCache=[];
3980
4049
  var hubSkillsCache=[];
3981
4050
  var ADMIN_PAGE_SIZE=20;
@@ -4072,11 +4141,23 @@ async function loadAdminData(){
4072
4141
  ]);
4073
4142
  }
4074
4143
  var usersR=fetches[0],tasksR=fetches[1],skillsR=fetches[2],pendingR=fetches[3],memoriesR=fetches[4];
4075
- adminDataCache.users=Array.isArray(usersR.users)?usersR.users:[];
4076
- adminDataCache.tasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
4077
- adminDataCache.skills=Array.isArray(skillsR.skills)?skillsR.skills:[];
4078
- adminDataCache.memories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
4144
+ var _newUsers=Array.isArray(usersR.users)?usersR.users:[];
4145
+ var _newTasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
4146
+ var _newSkills=Array.isArray(skillsR.skills)?skillsR.skills:[];
4147
+ var _newMemories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
4079
4148
  var pending=isAdmin?(Array.isArray(pendingR.users)?pendingR.users:[]):[];
4149
+ var _fp=_newUsers.length+':'+_newTasks.length+':'+_newSkills.length+':'+_newMemories.length+':'+pending.length
4150
+ +':'+_newUsers.map(function(u){return u.id+'|'+(u.isOnline?1:0)+'|'+(u.role||'')}).join(',')
4151
+ +':'+_newMemories.map(function(m){return m.id}).join(',')
4152
+ +':'+_newTasks.map(function(t){return t.id+'|'+(t.status||'')}).join(',')
4153
+ +':'+_newSkills.map(function(s){return s.id+'|'+(s.status||'')}).join(',')
4154
+ +':'+pending.map(function(p){return p.id}).join(',');
4155
+ if(_fp===_lastAdminFingerprint) return;
4156
+ _lastAdminFingerprint=_fp;
4157
+ adminDataCache.users=_newUsers;
4158
+ adminDataCache.tasks=_newTasks;
4159
+ adminDataCache.skills=_newSkills;
4160
+ adminDataCache.memories=_newMemories;
4080
4161
  adminDataCache._pending=pending;
4081
4162
  var badge=document.getElementById('adminPendingBadge');
4082
4163
  if(badge){if(pending.length>0){badge.textContent=pending.length;badge.style.display='inline';}else{badge.style.display='none';}}
@@ -4192,14 +4273,14 @@ function renderAdminUserCard(u,adminCount){
4192
4273
  }else{
4193
4274
  actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
4194
4275
  }
4195
- var ownerBadge=u.isOwner?' <span style="font-size:10px;background:linear-gradient(135deg,var(--amber),#f59e0b);color:#fff;padding:1px 6px;border-radius:4px;font-weight:600;vertical-align:middle;margin-left:4px">Owner</span>':'';
4276
+ var ownerBadge=u.isOwner?' <span style="font-size:9px;background:linear-gradient(135deg,#fbbf24,#f59e0b);color:#000;padding:2px 8px;border-radius:6px;font-weight:800;vertical-align:middle;margin-left:4px;letter-spacing:.04em;text-transform:uppercase;box-shadow:0 2px 8px rgba(251,191,36,.3)">Owner</span>':'';
4196
4277
 
4197
4278
  return '<div class="admin-card au-card au-'+statusCls+'"><div class="admin-card-header"><div style="flex:1;min-width:0;display:flex;align-items:center;gap:8px;flex-wrap:wrap">'+
4198
4279
  '<div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+statusLabel+
4199
4280
  '</div>'+
4200
- '<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span>'+ownerBadge+'</div>'+
4281
+ '<div style="display:flex;align-items:center;gap:6px"><span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span>'+ownerBadge+'</div></div>'+
4201
4282
  contribHtml+infoHtml+
4202
- (actions?'<div class="admin-card-actions" style="border-top:1px dashed var(--border);padding-top:10px;margin-top:4px">'+actions+'</div>':'')+
4283
+ (actions?'<div class="admin-card-actions" style="border-top:1px solid rgba(99,102,241,.08);padding-top:12px;margin-top:6px">'+actions+'</div>':'')+
4203
4284
  '</div>';
4204
4285
  }
4205
4286
 
@@ -4213,14 +4294,15 @@ function renderAdminUsers(users,pending){
4213
4294
  }
4214
4295
  var html='';
4215
4296
  if(pending&&pending.length>0){
4216
- html+='<div style="margin-bottom:16px"><h3 style="font-size:14px;font-weight:600;color:var(--amber);margin-bottom:10px">'+t('admin.pendingApproval')+' ('+pending.length+')</h3>';
4297
+ html+='<div class="admin-pending-section"><h3>'+t('admin.pendingApproval')+' <span class="pending-count">'+pending.length+'</span></h3>';
4217
4298
  for(var p=0;p<pending.length;p++){
4218
4299
  var pu=pending[p];
4219
- html+='<div class="admin-card"><div class="admin-card-header"><div class="admin-card-title">'+esc(pu.username||pu.id||'Unknown')+'</div><span class="admin-badge pending">pending</span></div>'+
4220
- '<div class="admin-card-meta">'+t('admin.device')+esc(pu.deviceName||'unknown')+'</div>'+
4221
- '<div class="admin-card-actions">'+
4222
- '<button class="btn btn-sm btn-primary" onclick="adminApproveUser(&quot;'+escAttr(pu.id)+'&quot;,&quot;'+escAttr(pu.username||'')+'&quot;)">'+t('admin.approve')+'</button>'+
4223
- '<button class="btn btn-sm btn-ghost" onclick="adminRejectUser(&quot;'+escAttr(pu.id)+'&quot;)" style="color:var(--rose)">'+t('admin.reject')+'</button>'+
4300
+ html+='<div class="admin-pending-card">'+
4301
+ '<div class="apc-name">'+esc(pu.username||pu.id||'Unknown')+'</div>'+
4302
+ '<div class="apc-meta"><span>\u{1F4BB} '+esc(pu.deviceName||'unknown')+'</span>'+(pu.createdAt?'<span>\u{1F552} '+formatDateTimeSeconds(pu.createdAt)+'</span>':'')+'</div>'+
4303
+ '<div class="apc-actions">'+
4304
+ '<button class="btn-approve" onclick="adminApproveUser(&quot;'+escAttr(pu.id)+'&quot;,&quot;'+escAttr(pu.username||'')+'&quot;)">'+t('admin.approve')+'</button>'+
4305
+ '<button class="btn-reject" onclick="adminRejectUser(&quot;'+escAttr(pu.id)+'&quot;)">'+t('admin.reject')+'</button>'+
4224
4306
  '</div></div>';
4225
4307
  }
4226
4308
  html+='</div>';
@@ -5514,12 +5596,12 @@ function setTaskStatusFilter(btn,status){
5514
5596
  loadTasks();
5515
5597
  }
5516
5598
 
5517
- async function loadTasks(){
5599
+ async function loadTasks(silent){
5518
5600
  const scope=document.getElementById('taskSearchScope')?document.getElementById('taskSearchScope').value:taskSearchScope;
5519
5601
  taskSearchScope=scope||'local';
5520
5602
  if(taskSearchScope==='hub'){ return loadHubTasks(); }
5521
5603
  const list=document.getElementById('tasksList');
5522
- list.innerHTML='<div class="spinner"></div>';
5604
+ if(!silent) list.innerHTML='<div class="spinner"></div>';
5523
5605
  try{
5524
5606
  const params=new URLSearchParams({limit:String(TASKS_PER_PAGE),offset:String(tasksPage*TASKS_PER_PAGE)});
5525
5607
  if(tasksStatusFilter) params.set('status',tasksStatusFilter);
@@ -5533,6 +5615,14 @@ async function loadTasks(){
5533
5615
  fetch('/api/tasks?status=completed&limit=1&offset=0&'+baseP).then(r=>r.json()),
5534
5616
  fetch('/api/tasks?status=skipped&limit=1&offset=0&'+baseP).then(r=>r.json())
5535
5617
  ]);
5618
+ if(silent){
5619
+ var fp=JSON.stringify((data.tasks||[]).map(function(tk){return tk.id+'|'+tk.status+'|'+(tk.updatedAt||tk.startedAt)}));
5620
+ fp+=':'+allD.total+':'+activeD.total+':'+compD.total+':'+skipD.total;
5621
+ if(fp===_lastTasksFingerprint) return;
5622
+ _lastTasksFingerprint=fp;
5623
+ }else{
5624
+ _lastTasksFingerprint='';
5625
+ }
5536
5626
  document.getElementById('tasksTotalCount').textContent=formatNum(allD.total);
5537
5627
  document.getElementById('tasksActiveCount').textContent=formatNum(activeD.total);
5538
5628
  document.getElementById('tasksCompletedCount').textContent=formatNum(compD.total);
@@ -5818,17 +5908,17 @@ function updateSkillCardBadge(skillId,newScope){
5818
5908
  }
5819
5909
  }
5820
5910
 
5821
- async function loadSkills(){
5911
+ async function loadSkills(silent){
5822
5912
  const list=document.getElementById('skillsList');
5823
5913
  const hubList=document.getElementById('hubSkillsList');
5824
- list.innerHTML='<div class="spinner"></div>';
5914
+ if(!silent) list.innerHTML='<div class="spinner"></div>';
5825
5915
  var hubSection=document.getElementById('hubSkillsSection');
5826
5916
  if(hubList){
5827
5917
  if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
5828
5918
  if(hubSection) hubSection.style.display='none';
5829
5919
  }else{
5830
5920
  if(hubSection) hubSection.style.display='block';
5831
- hubList.innerHTML='<div class="spinner"></div>';
5921
+ if(!silent) hubList.innerHTML='<div class="spinner"></div>';
5832
5922
  }
5833
5923
  }
5834
5924
 
@@ -5852,6 +5942,13 @@ async function loadSkills(){
5852
5942
  return haystack.includes(q);
5853
5943
  });
5854
5944
  }
5945
+ if(silent){
5946
+ var fp=JSON.stringify(localSkills.map(function(s){return s.id+'|'+s.status+'|'+s.version+'|'+(s.visibility||'')}));
5947
+ if(fp===_lastSkillsFingerprint) return;
5948
+ _lastSkillsFingerprint=fp;
5949
+ }else{
5950
+ _lastSkillsFingerprint='';
5951
+ }
5855
5952
 
5856
5953
  const renderLocalCards=function(skills){
5857
5954
  if(!skills||skills.length===0){
@@ -5910,7 +6007,8 @@ async function loadSkills(){
5910
6007
 
5911
6008
  if(!query){
5912
6009
  if(hubSection) hubSection.style.display='block';
5913
- if(hubList){ loadHubSkills(hubList); }
6010
+ var localIds=new Set(localSkills.map(function(s){return s.id;}));
6011
+ if(hubList){ loadHubSkills(hubList, localIds); }
5914
6012
  document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localSkills.length;
5915
6013
  document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
5916
6014
  document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
@@ -6008,7 +6106,7 @@ async function loadHubTasks(){
6008
6106
  }
6009
6107
  }
6010
6108
 
6011
- async function loadHubSkills(hubList){
6109
+ async function loadHubSkills(hubList, localIds){
6012
6110
  if(!hubList) hubList=document.getElementById('hubSkillsList');
6013
6111
  if(!hubList) return;
6014
6112
  var hubSection=document.getElementById('hubSkillsSection');
@@ -6016,7 +6114,8 @@ async function loadHubSkills(hubList){
6016
6114
  try{
6017
6115
  const r=await fetch('/api/sharing/skills/list?limit=40');
6018
6116
  const d=await r.json();
6019
- const skills=Array.isArray(d.skills)?d.skills:[];
6117
+ var allSkills=Array.isArray(d.skills)?d.skills:[];
6118
+ const skills=localIds?allSkills.filter(function(s){return !localIds.has(s.sourceSkillId);}):allSkills;
6020
6119
  hubSkillsCache=skills;
6021
6120
  if(!skills.length){
6022
6121
  if(hubSection) hubSection.style.display='none';
@@ -6548,6 +6647,8 @@ async function saveHubConfig(){
6548
6647
  var clientTeamToken=document.getElementById('cfgClientTeamToken').value.trim();
6549
6648
  var clientUserToken=document.getElementById('cfgClientUserToken').value.trim();
6550
6649
  var clientNickname=document.getElementById('cfgClientNickname').value.trim();
6650
+ if(!clientAddr){done();toast(t('settings.hub.test.noAddr'),'error');return;}
6651
+ if(!clientTeamToken){done();toast(t('settings.hub.teamToken.required'),'error');return;}
6551
6652
  cfg.sharing.client={};
6552
6653
  if(clientAddr) cfg.sharing.client.hubAddress=clientAddr;
6553
6654
  if(clientNickname) cfg.sharing.client.nickname=clientNickname;
@@ -6563,6 +6664,18 @@ async function saveHubConfig(){
6563
6664
  done();toast(t('sharing.cannotJoinSelf'),'error');return;
6564
6665
  }
6565
6666
  }catch(e){}
6667
+ try{
6668
+ var testUrl=clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr;
6669
+ testUrl=testUrl.replace(/\\/+$/,'');
6670
+ var tr=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:testUrl})});
6671
+ var td=await tr.json();
6672
+ if(!td.ok){
6673
+ var errMsg=td.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(td.error||t('settings.hub.test.fail'));
6674
+ done();toast(errMsg,'error');return;
6675
+ }
6676
+ }catch(e){
6677
+ done();toast(t('settings.hub.test.fail')+': '+String(e),'error');return;
6678
+ }
6566
6679
  }
6567
6680
  }
6568
6681
 
@@ -6572,6 +6685,10 @@ async function saveHubConfig(){
6572
6685
  var confirmMsg=prevRole==='hub'?t('sharing.disable.confirm.hub'):t('sharing.disable.confirm.client');
6573
6686
  if(!(await confirmModal(confirmMsg,{danger:true}))){done();return;}
6574
6687
  }
6688
+ if(prevSharingEnabled&&sharingEnabled&&prevRole&&prevRole!==_sharingRole){
6689
+ var switchMsg=prevRole==='hub'?t('sharing.switch.hubToClient'):t('sharing.switch.clientToHub');
6690
+ if(!(await confirmModal(switchMsg,{danger:true}))){done();return;}
6691
+ }
6575
6692
 
6576
6693
  var ok=await doSaveConfig(cfg, saveBtn, 'hubSaved');
6577
6694
  if(ok){
@@ -6581,8 +6698,12 @@ async function saveHubConfig(){
6581
6698
  try{await fetch('/api/sharing/update-username',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:adminNameEl.value.trim()})});}catch(e){}
6582
6699
  }
6583
6700
  }
6701
+ _lastSidebarFingerprint='';
6702
+ _lastSettingsFingerprint='';
6584
6703
  loadSharingStatus(false);
6585
- var needsRestart=sharingEnabled||(prevSharingEnabled&&!sharingEnabled);
6704
+ var enabledChanged=(!!prevSharingEnabled)!==(!!sharingEnabled);
6705
+ var roleChanged=prevRole!==_sharingRole;
6706
+ var needsRestart=enabledChanged||roleChanged;
6586
6707
  if(sharingEnabled) updateHubShareInfo();
6587
6708
  if(needsRestart){
6588
6709
  setTimeout(function(){showRestartOverlay(t('settings.restart.waiting'));},300);
@@ -7011,13 +7132,19 @@ async function _livePollTick(){
7011
7132
  if(_livePollBusy||document.hidden) return;
7012
7133
  _livePollBusy=true;
7013
7134
  try{
7014
- if(sharingStatusCache&&sharingStatusCache.enabled) loadSharingStatus(false);
7135
+ if(sharingStatusCache&&sharingStatusCache.enabled&&_lastSharingConnStatus!=='rejected') loadSharingStatus(false);
7015
7136
  if(!_notifSSEConnected) pollNotifCount();
7016
7137
  pollAdminPending();
7017
7138
  if(_activeView==='admin') loadAdminData();
7018
- else if(_activeView==='memories'){loadStats();loadMemories();}
7019
- else if(_activeView==='tasks') loadTasks();
7020
- else if(_activeView==='skills') loadSkills();
7139
+ else if(_activeView==='memories'){
7140
+ var _searchVal=(document.getElementById('searchInput')||{}).value||'';
7141
+ if(!_searchVal.trim()){
7142
+ if(memorySearchScope==='hub') loadHubMemories(true);
7143
+ else{loadStats();loadMemories(null,true);}
7144
+ }
7145
+ }
7146
+ else if(_activeView==='tasks') loadTasks(true);
7147
+ else if(_activeView==='skills') loadSkills(true);
7021
7148
  else if(_activeView==='analytics') loadMetrics();
7022
7149
  }catch(e){}
7023
7150
  _livePollBusy=false;
@@ -7228,7 +7355,10 @@ function stopNotifPoll(){ }
7228
7355
 
7229
7356
  /* ─── Data loading ─── */
7230
7357
  async function loadAll(){
7231
- await Promise.all([loadStats(),loadMemories(),loadSharingStatus(false)]);
7358
+ await loadStats();
7359
+ var initOwner=memorySearchScope==='local'?_currentAgentOwner:undefined;
7360
+ if(initOwner) await loadStats(initOwner);
7361
+ await Promise.all([loadMemories(),loadSharingStatus(false)]);
7232
7362
  checkMigrateStatus();
7233
7363
  connectPPSSE();
7234
7364
  checkForUpdate();
@@ -7245,6 +7375,7 @@ async function loadStats(ownerFilter){
7245
7375
  d=await r.json();
7246
7376
  }catch(e){ d={}; }
7247
7377
  if(!d||typeof d!=='object') d={};
7378
+ if(d.currentAgentOwner) _currentAgentOwner=d.currentAgentOwner;
7248
7379
  const tm=d.totalMemories||0;
7249
7380
  const dedupB=d.dedupBreakdown||{};
7250
7381
  const activeCount=dedupB.active||tm;
@@ -7358,55 +7489,88 @@ function getFilterParams(){
7358
7489
  if(dt) p.set('dateTo',dt);
7359
7490
  const sort=document.getElementById('filterSort').value;
7360
7491
  if(sort==='oldest') p.set('sort','oldest');
7361
- const owner=document.getElementById('filterOwner').value;
7362
- if(owner) p.set('owner',owner);
7492
+ const scope=memorySearchScope||'local';
7493
+ if(scope==='local'){
7494
+ p.set('owner',_currentAgentOwner);
7495
+ }else{
7496
+ const owner=document.getElementById('filterOwner').value;
7497
+ if(owner) p.set('owner',owner);
7498
+ }
7363
7499
  return p;
7364
7500
  }
7365
7501
 
7366
- async function loadMemories(page){
7502
+ async function loadMemories(page,silent){
7367
7503
  if(page) currentPage=page;
7368
7504
  const list=document.getElementById('memoryList');
7369
- list.innerHTML='<div class="spinner"></div>';
7505
+ if(!silent) list.innerHTML='<div class="spinner"></div>';
7370
7506
  try{
7371
7507
  const p=getFilterParams();
7372
7508
  p.set('limit',PAGE_SIZE);
7373
7509
  p.set('page',currentPage);
7374
7510
  const r=await fetch('/api/memories?'+p.toString());
7375
7511
  const d=await r.json();
7512
+ var items=d.memories||[];
7513
+ if(silent){
7514
+ var fp=JSON.stringify(items.map(function(m){return m.id+'|'+m.updated_at}));
7515
+ if(fp===_lastMemoriesFingerprint) return;
7516
+ _lastMemoriesFingerprint=fp;
7517
+ }else{
7518
+ _lastMemoriesFingerprint=JSON.stringify(items.map(function(m){return m.id+'|'+m.updated_at}));
7519
+ }
7376
7520
  totalPages=d.totalPages||1;
7377
7521
  totalCount=d.total||0;
7378
7522
  document.getElementById('searchMeta').textContent=totalCount+t('search.meta.total');
7379
- renderMemories(d.memories||[]);
7523
+ renderMemories(items);
7380
7524
  renderPagination();
7381
7525
  }catch(e){
7382
- list.innerHTML='';
7383
- totalPages=1;totalCount=0;
7384
- renderMemories([]);
7385
- renderPagination();
7526
+ if(!silent){
7527
+ list.innerHTML='';
7528
+ totalPages=1;totalCount=0;
7529
+ _lastMemoriesFingerprint='';
7530
+ renderMemories([]);
7531
+ renderPagination();
7532
+ }
7386
7533
  }
7387
7534
  }
7388
7535
 
7389
- async function loadHubMemories(){
7536
+ async function loadHubMemories(silent){
7390
7537
  const list=document.getElementById('memoryList');
7391
- list.innerHTML='<div class="spinner"></div>';
7538
+ if(!silent) list.innerHTML='<div class="spinner"></div>';
7392
7539
  try{
7393
7540
  const r=await fetch('/api/sharing/memories/list?limit='+PAGE_SIZE);
7394
7541
  const d=await r.json();
7395
7542
  const items=d.memories||[];
7543
+ if(silent){
7544
+ var fp=JSON.stringify(items.map(function(m){return m.id+'|'+(m.updated_at||m.created_at)}));
7545
+ if(fp===_lastMemoriesFingerprint) return;
7546
+ _lastMemoriesFingerprint=fp;
7547
+ }else{
7548
+ _lastMemoriesFingerprint=JSON.stringify(items.map(function(m){return m.id+'|'+(m.updated_at||m.created_at)}));
7549
+ }
7550
+ totalPages=1;totalCount=items.length;currentPage=1;
7396
7551
  document.getElementById('searchMeta').textContent=items.length+t('search.meta.total');
7397
7552
  document.getElementById('sharingSearchMeta').textContent='';
7398
7553
  renderMemories(items);
7399
7554
  document.getElementById('pagination').innerHTML='';
7400
7555
  }catch(e){
7401
- document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
7402
- renderMemories([]);
7403
- document.getElementById('pagination').innerHTML='';
7556
+ if(!silent){
7557
+ _lastMemoriesFingerprint='';
7558
+ document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
7559
+ renderMemories([]);
7560
+ document.getElementById('pagination').innerHTML='';
7561
+ }
7404
7562
  }
7405
7563
  }
7406
7564
 
7407
7565
  async function doSearch(query){
7408
7566
  query=(query||'').trim();
7409
- if(!query){loadMemories();return;}
7567
+ if(!query){
7568
+ currentPage=1;
7569
+ if(memorySearchScope==='hub') loadHubMemories();
7570
+ else loadMemories();
7571
+ return;
7572
+ }
7573
+ currentPage=1;
7410
7574
  var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'local';
7411
7575
  var list=document.getElementById('memoryList');
7412
7576
  list.innerHTML='<div class="spinner"></div>';
@@ -7418,6 +7582,7 @@ async function doSearch(query){
7418
7582
  body:JSON.stringify({query:query,scope:scope,maxResults:20,role:activeRole||undefined})
7419
7583
  });
7420
7584
  var data=await r.json();
7585
+ totalPages=1;totalCount=(data.results||[]).length;
7421
7586
  renderSharingMemorySearchResults(data,query);
7422
7587
  }catch(e){
7423
7588
  document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
@@ -7432,6 +7597,7 @@ async function doSearch(query){
7432
7597
  var r=await fetch('/api/search?'+p.toString());
7433
7598
  var d=await r.json();
7434
7599
  var total=d.total||0;
7600
+ totalPages=1;totalCount=total;
7435
7601
  var meta=[];
7436
7602
  if(d.vectorCount>0) meta.push(d.vectorCount+t('search.meta.semantic'));
7437
7603
  if(d.ftsCount>0) meta.push(d.ftsCount+t('search.meta.text'));
@@ -7520,7 +7686,8 @@ function renderMemories(items){
7520
7686
  const isPublicMem=ownerVal==='public';
7521
7687
  const localManaged=!!m.localSharingManaged;
7522
7688
  const memShared=m.sharingVisibility||null;
7523
- const memScope=memShared?'team':isPublicMem?'local':'private';
7689
+ const isHubScope=memorySearchScope==='hub';
7690
+ const memScope=isHubScope?'team':memShared?'team':isPublicMem?'local':'private';
7524
7691
  const memScopeBadge=renderScopeBadge(memScope);
7525
7692
  let dedupInfo='';
7526
7693
  if(ds==='duplicate'||ds==='merged'){
@@ -7625,7 +7792,8 @@ function renderPagination(){
7625
7792
  function goPage(p){
7626
7793
  if(p<1||p>totalPages||p===currentPage) return;
7627
7794
  currentPage=p;
7628
- loadMemories();
7795
+ if(memorySearchScope==='hub') loadHubMemories();
7796
+ else loadMemories();
7629
7797
  document.getElementById('memoryList').scrollIntoView({behavior:'smooth',block:'start'});
7630
7798
  }
7631
7799
 
@@ -8541,7 +8709,7 @@ async function checkForUpdate(){
8541
8709
 
8542
8710
  /* ─── Init ─── */
8543
8711
  document.getElementById('modalOverlay').addEventListener('click',e=>{if(e.target.id==='modalOverlay')closeModal()});
8544
- document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';loadMemories()}});
8712
+ document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';currentPage=1;if(memorySearchScope==='hub')loadHubMemories();else loadMemories();}});
8545
8713
  applyI18n();
8546
8714
  checkAuth();
8547
8715
  </script>