@memtensor/memos-local-openclaw-plugin 1.0.8-beta.7 → 1.0.8-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.
@@ -44,7 +44,6 @@ html{overflow-y:scroll}
44
44
  [data-theme="light"] .auth-card{box-shadow:0 25px 50px -12px rgba(0,0,0,.08)}
45
45
  [data-theme="light"] .topbar{background:rgba(255,255,255,.92);border-bottom-color:var(--border);backdrop-filter:blur(8px)}
46
46
  [data-theme="light"] .session-item .count,[data-theme="light"] .session-tag{background:rgba(0,0,0,.05)}
47
- [data-theme="light"] .owner-tag{background:rgba(99,102,241,.08);border-color:rgba(99,102,241,.18)}
48
47
  [data-theme="light"] .card-content pre{background:#f3f4f6;border-color:var(--border)}
49
48
  [data-theme="light"] .vscore-badge{background:rgba(79,70,229,.06);color:#4f46e5}
50
49
  [data-theme="light"] ::-webkit-scrollbar-thumb{background:rgba(0,0,0,.15)}
@@ -127,24 +126,22 @@ input,textarea,select{font-family:inherit;font-size:inherit}
127
126
  .main-content{display:flex;flex:1;max-width:1400px;margin:0 auto;width:100%;padding:28px 32px;gap:28px}
128
127
 
129
128
  /* ─── Sidebar ─── */
130
- .sidebar{width:260px;min-width:260px;flex-shrink:0;position:sticky;top:84px;max-height:calc(100vh - 112px);display:flex;flex-direction:column}
131
- .sidebar > * {flex-shrink:0}
132
- .sidebar .stats-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:20px}
133
- .stat-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:14px 16px;transition:all .2s;position:relative;overflow:hidden}
134
- .stat-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--border)}
129
+ .sidebar{width:260px;min-width:260px;flex-shrink:0}
130
+ .sidebar .stats-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:24px}
131
+ .stat-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:18px;transition:all .2s}
135
132
  .stat-card:hover{border-color:var(--border-glow);background:var(--bg-card-hover)}
136
- .stat-card .stat-value{font-size:20px;font-weight:700;color:var(--text);letter-spacing:-.02em}
137
- .stat-card .stat-label{font-size:11px;color:var(--text-sec);margin-top:2px;font-weight:500}
138
- .stat-card.pri{border-left-color:transparent}.stat-card.pri::before{background:var(--pri)}
133
+ .stat-card .stat-value{font-size:22px;font-weight:700;color:var(--text);letter-spacing:-.02em}
134
+ .stat-card .stat-label{font-size:12px;color:var(--text-sec);margin-top:4px;font-weight:500}
139
135
  .stat-card.pri .stat-value{color:var(--pri)}
140
- .stat-card.green{border-left-color:transparent}.stat-card.green::before{background:var(--green)}
141
136
  .stat-card.green .stat-value{color:var(--green)}
142
- .stat-card.amber{border-left-color:transparent}.stat-card.amber::before{background:var(--amber)}
143
137
  .stat-card.amber .stat-value{color:var(--amber)}
144
- .stat-card.rose{border-left-color:transparent}.stat-card.rose::before{background:var(--rose)}
145
138
  .stat-card.rose .stat-value{color:var(--rose)}
146
139
 
147
140
  .sidebar .section-title{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em;margin:24px 0 12px;padding:0 2px}
141
+ .sidebar .session-list{display:flex;flex-direction:column;gap:6px;max-height:280px;overflow-y:auto}
142
+ .session-item{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--bg-card);border:1px solid var(--border);border-radius:10px;cursor:pointer;transition:all .15s;font-size:13px;color:var(--text)}
143
+ .session-item:hover{border-color:var(--pri);background:var(--pri-glow)}
144
+ .session-item.active{border-color:var(--pri);background:var(--pri-glow);font-weight:600;color:var(--pri)}
148
145
  .session-item .count{color:var(--text-sec);font-size:11px;font-weight:600;background:rgba(0,0,0,.2);padding:3px 8px;border-radius:8px}
149
146
 
150
147
  .provider-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--green-bg);color:var(--green);border-radius:999px;font-size:11px;font-weight:600;margin-top:10px}
@@ -152,12 +149,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
152
149
 
153
150
  /* ─── Feed ─── */
154
151
  .feed{flex:1;min-width:0}
155
- .search-bar{display:flex;gap:10px;margin-bottom:14px;position:relative;align-items:center}
152
+ .search-bar{display:flex;gap:10px;margin-bottom:16px;position:relative;align-items:center}
156
153
  .search-bar input{flex:1;padding:10px 16px 10px 40px;border:1px solid var(--border);border-radius:10px;font-size:14px;outline:none;background:var(--bg-card);color:var(--text);transition:all .2s}
157
154
  .search-bar input::placeholder{color:var(--text-muted)}
158
155
  .search-bar input:focus{border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-glow)}
159
156
  .search-bar .search-icon{position:absolute;left:14px;top:50%;transform:translateY(-50%);color:var(--text-muted);font-size:14px;pointer-events:none}
160
- .search-bar .filter-select{padding:8px 14px;padding-right:30px;border-radius:10px;font-size:13px;background:var(--bg-card);flex-shrink:0}
161
157
  .search-meta{font-size:12px;color:var(--text-sec);padding:0 2px}.search-meta:not(:empty){margin-bottom:14px}
162
158
  .scope-select{padding:10px 12px;border:1px solid var(--border);border-radius:10px;background:var(--bg-card);color:var(--text);font-size:13px;min-width:110px;outline:none}
163
159
  .sharing-inline-meta{font-size:12px;color:var(--text-muted);margin:-8px 0 14px 2px}
@@ -374,13 +370,13 @@ input,textarea,select{font-family:inherit;font-size:inherit}
374
370
  .hub-source-badge{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border-radius:999px;background:rgba(34,197,94,.12);color:var(--green);font-size:11px;font-weight:700;border:1px solid rgba(34,197,94,.22)}
375
371
  @media (max-width: 960px){.sharing-settings-grid{grid-template-columns:1fr}.search-bar{flex-wrap:wrap}.scope-select{width:100%}.task-detail-actions{width:100%;justify-content:flex-start}}
376
372
 
377
- .filter-bar{display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap;align-items:center}
378
- .filter-chip{padding:5px 14px;border:1px solid var(--border);border-radius:8px;background:transparent;color:var(--text-sec);font-size:12px;font-weight:500;cursor:pointer;transition:all .15s}
379
- .filter-chip:hover{border-color:var(--pri);color:var(--pri);background:rgba(99,102,241,.04)}
380
- .filter-chip.active{background:rgba(99,102,241,.1);color:var(--pri);border-color:rgba(99,102,241,.3);font-weight:600}
373
+ .filter-bar{display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap}
374
+ .filter-chip{padding:5px 14px;border:1px solid var(--border);border-radius:6px;background:transparent;color:var(--text-sec);font-size:12px;font-weight:500;transition:all .15s}
375
+ .filter-chip:hover{border-color:var(--pri);color:var(--pri)}
376
+ .filter-chip.active{background:rgba(99,102,241,.08);color:var(--pri);border-color:rgba(99,102,241,.25)}
381
377
 
382
- .memory-list{display:flex;flex-direction:column;gap:10px}
383
- .memory-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:16px 20px;transition:all .2s}
378
+ .memory-list{display:flex;flex-direction:column;gap:16px}
379
+ .memory-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:20px 24px;transition:all .2s}
384
380
  .memory-card:hover{border-color:var(--border-glow);background:var(--bg-card-hover)}
385
381
  .memory-card .card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;flex-wrap:wrap;gap:8px}
386
382
  .memory-card .meta{display:flex;align-items:center;gap:8px}
@@ -390,20 +386,12 @@ input,textarea,select{font-family:inherit;font-size:inherit}
390
386
  .role-tag.system{background:var(--amber-bg);color:var(--amber);border:1px solid rgba(245,158,11,.2)}
391
387
  .card-time{font-size:12px;color:var(--text-sec);display:flex;align-items:center;gap:8px}
392
388
  .session-tag{font-size:11px;font-family:ui-monospace,monospace;color:var(--text-muted);background:rgba(0,0,0,.2);padding:3px 8px;border-radius:6px;cursor:default}
393
- .owner-tag{font-size:11px;font-weight:600;color:var(--pri);background:var(--pri-glow);padding:3px 9px;border-radius:8px;border:1px solid rgba(99,102,241,.15);cursor:default;white-space:nowrap}
394
389
  .card-summary{font-size:15px;font-weight:600;color:var(--text);margin-bottom:10px;line-height:1.5;letter-spacing:-.01em;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
395
390
  .card-content{font-size:13px;color:var(--text-sec);line-height:1.65;max-height:0;overflow:hidden;transition:max-height .3s ease}
396
391
  .card-content.show{max-height:600px;overflow-y:auto}
397
392
  .card-content pre{white-space:pre-wrap;word-break:break-all;background:rgba(0,0,0,.25);padding:14px;border-radius:10px;font-size:12px;font-family:ui-monospace,monospace;margin-top:10px;border:1px solid var(--border);color:var(--text-sec)}
398
393
  .card-actions{display:flex;align-items:center;gap:8px;margin-top:14px}
399
394
  .card-actions-inline{display:inline-flex;align-items:center;gap:4px;margin-left:auto;flex-shrink:0}
400
- .btn-warn{color:#f59e0b !important}
401
- .btn-warn:hover{background:rgba(245,158,11,.15) !important}
402
- .btn-danger{color:#ef4444 !important}
403
- .btn-danger:hover{background:rgba(239,68,68,.15) !important}
404
- .btn-success{color:#10b981 !important}
405
- .btn-success:hover{background:rgba(16,185,129,.15) !important}
406
- .skill-card.archived{opacity:0.55;border-style:dashed}
407
395
  .vscore-badge{display:inline-flex;align-items:center;background:rgba(59,130,246,.15);color:#60a5fa;font-size:10px;font-weight:700;padding:4px 10px;border-radius:8px;margin-left:auto}
408
396
  .merge-badge{display:inline-flex;align-items:center;gap:4px;background:rgba(16,185,129,.12);color:#10b981;font-size:10px;font-weight:600;padding:3px 10px;border-radius:8px}
409
397
  .merge-history{margin-top:12px;padding:12px 14px;background:rgba(0,0,0,.15);border-radius:10px;border:1px solid var(--border);font-size:12px;line-height:1.7;color:var(--text-sec);max-height:200px;overflow-y:auto}
@@ -585,39 +573,32 @@ input,textarea,select{font-family:inherit;font-size:inherit}
585
573
  ::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15);border-radius:3px}
586
574
  ::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.25)}
587
575
 
588
- .filter-sep{width:1px;height:20px;background:var(--border);margin:0 2px}
589
- .filter-select{padding:5px 14px;border:1px solid var(--border);border-radius:8px;background:transparent;color:var(--text-sec);font-size:12px;font-weight:500;outline:none;cursor:pointer;transition:all .15s;-webkit-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%236b7280'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}
590
- .filter-select:hover{border-color:var(--pri);color:var(--pri)}
591
- .filter-select:focus{border-color:var(--pri);color:var(--pri);background-color:rgba(99,102,241,.04)}
576
+ .filter-sep{width:1px;height:20px;background:var(--border);margin:0 4px}
577
+ .filter-select{padding:6px 12px;border:1px solid var(--border);border-radius:999px;background:var(--bg-card);color:var(--text-sec);font-size:13px;outline:none;cursor:pointer}
578
+ .filter-select:focus{border-color:var(--pri)}
592
579
  .date-filter{display:flex;align-items:center;gap:10px;margin-bottom:18px;font-size:13px;color:var(--text-sec)}
593
- .date-filter input[type="datetime-local"]{padding:5px 12px;border:1px solid var(--border);border-radius:8px;font-size:12px;outline:none;background:transparent;color:var(--text-sec);transition:all .15s}
580
+ .date-filter input[type="datetime-local"]{padding:6px 10px;border:1px solid var(--border);border-radius:8px;font-size:12px;outline:none;background:var(--bg-card);color:var(--text)}
594
581
  .date-filter input[type="datetime-local"]:focus{border-color:var(--pri)}
595
582
  .date-filter label{font-weight:500}
596
- .compact-filter-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
597
- .compact-date{padding:5px 12px;border:1px solid var(--border);border-radius:8px;font-size:12px;font-weight:500;outline:none;background:transparent;color:var(--text-sec);max-width:180px;transition:all .15s}
598
- .compact-date:hover{border-color:var(--pri);color:var(--pri)}
599
- .compact-date:focus{border-color:var(--pri);color:var(--pri);background:rgba(99,102,241,.04)}
600
-
601
- .pagination-row{display:flex;align-items:center;justify-content:center;gap:10px;flex-wrap:wrap;padding:16px 0 8px}
602
- .pagination{display:flex;align-items:center;justify-content:center;gap:4px;padding:0;flex-wrap:wrap}
603
- .pagination .pg-btn{min-width:32px;height:32px;display:flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:8px;background:transparent;color:var(--text-sec);font-size:12px;font-weight:500;cursor:pointer;transition:all .15s}
604
- .pagination .pg-btn:hover{background:rgba(99,102,241,.06);color:var(--pri);border-color:rgba(99,102,241,.15)}
605
- .pagination .pg-btn.active{background:var(--pri-grad);color:#fff;border-color:transparent;box-shadow:0 2px 8px rgba(99,102,241,.3)}
606
- .pagination .pg-btn.disabled{opacity:.3;pointer-events:none}
607
- .pagination .pg-info{font-size:11px;color:var(--text-muted);padding:0 8px}
583
+
584
+ .pagination{display:flex;align-items:center;justify-content:center;gap:6px;padding:28px 0;flex-wrap:wrap}
585
+ .pagination .pg-btn{min-width:38px;height:38px;display:flex;align-items:center;justify-content:center;border:1px solid var(--border);border-radius:10px;background:var(--bg-card);color:var(--text-sec);font-size:13px;font-weight:500;cursor:pointer;transition:all .15s}
586
+ .pagination .pg-btn:hover{border-color:var(--pri);color:var(--pri)}
587
+ .pagination .pg-btn.active{background:var(--pri);color:#000;border-color:var(--pri)}
588
+ .pagination .pg-btn.disabled{opacity:.4;pointer-events:none}
589
+ .pagination .pg-info{font-size:12px;color:var(--text-sec);padding:0 12px}
608
590
 
609
591
  /* ─── Tasks 视图 ─── */
610
592
  .view-container{flex:1;min-width:0}
611
593
  .view-container>.vp{display:none;flex-direction:column}
612
594
  .view-container>.vp.show{display:flex}
613
- .tasks-view{flex:1;min-width:0;flex-direction:column}
614
- .tasks-header{display:flex;flex-direction:column;gap:0}
615
- .tasks-stats{display:flex;gap:10px}
616
- .tasks-stat{display:flex;align-items:center;gap:8px;background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:10px 16px;flex:1;transition:all .2s;position:relative;overflow:hidden}
617
- .tasks-stat::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px}
595
+ .tasks-view{flex:1;min-width:0;flex-direction:column;gap:16px}
596
+ .tasks-header{display:flex;flex-direction:column;gap:14px}
597
+ .tasks-stats{display:flex;gap:16px}
598
+ .tasks-stat{display:flex;align-items:center;gap:8px;background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:12px 18px;flex:1;transition:all .2s}
618
599
  .tasks-stat:hover{border-color:var(--border-glow)}
619
- .tasks-stat-value{font-size:18px;font-weight:700;color:var(--text)}
620
- .tasks-stat-label{font-size:11px;color:var(--text-sec);font-weight:500}
600
+ .tasks-stat-value{font-size:22px;font-weight:700;color:var(--text)}
601
+ .tasks-stat-label{font-size:12px;color:var(--text-sec);font-weight:500}
621
602
  .tasks-filters{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
622
603
  .tasks-list{display:flex;flex-direction:column;gap:10px}
623
604
  .task-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:18px 20px;cursor:pointer;transition:all .25s;position:relative;overflow:hidden}
@@ -689,7 +670,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
689
670
  [data-theme="light"] .tasks-stat{background:#fff}
690
671
 
691
672
  /* ─── Skills ─── */
692
- .skills-view{flex:1;min-width:0;flex-direction:column}
673
+ .skills-view{flex:1;min-width:0;flex-direction:column;gap:16px}
693
674
  .skill-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:18px 20px;cursor:pointer;transition:all .25s;position:relative;overflow:hidden}
694
675
  .skill-card:hover{border-color:var(--border-glow);background:var(--bg-card-hover);transform:translateY(-1px);box-shadow:var(--shadow)}
695
676
  .skill-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--violet)}
@@ -716,10 +697,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
716
697
  .skill-card-bottom .tag{display:flex;align-items:center;gap:4px}
717
698
  .skill-card-tags{display:flex;gap:4px;flex-wrap:wrap}
718
699
  .skill-tag{font-size:10px;padding:2px 8px;border-radius:10px;background:rgba(139,92,246,.1);color:var(--violet);font-weight:500}
719
- .selection-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
720
- #memorySelectionToolbar{margin-bottom:16px}
721
- .item-select-box{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:5px;border:1px solid var(--border);background:var(--bg-card);cursor:pointer;margin-right:8px;vertical-align:middle}
722
- .item-select-box input{width:14px;height:14px;cursor:pointer}
723
700
  .skill-detail-desc{font-size:13px;color:var(--text-sec);line-height:1.6;margin-bottom:16px;padding:12px 16px;background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius)}
724
701
  .skill-version-item{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:12px 16px}
725
702
  .skill-version-header{display:flex;align-items:center;gap:10px;margin-bottom:6px}
@@ -831,7 +808,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
831
808
  .recall-origin.local-shared{background:rgba(59,130,246,.12);color:#3b82f6}
832
809
  .recall-origin.hub-memory{background:rgba(139,92,246,.12);color:#8b5cf6}
833
810
  .recall-origin.hub-remote{background:rgba(139,92,246,.12);color:#8b5cf6}
834
- .recall-origin.agent-tag{background:rgba(20,184,166,.12);color:#14b8a6}
835
811
  .recall-summary-short{flex:1;color:var(--text-sec);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
836
812
  .recall-expand-icon{flex-shrink:0;font-size:10px;color:var(--text-muted);transition:transform .15s}
837
813
  .recall-item.expanded .recall-expand-icon{transform:rotate(90deg)}
@@ -1249,8 +1225,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
1249
1225
  <div class="sidebar" id="sidebar">
1250
1226
  <div class="stats-grid" id="statsGrid">
1251
1227
  <div class="stat-card pri"><div class="stat-value" id="statTotal">-</div><div class="stat-label" data-i18n="stat.memories">Memories</div></div>
1252
- <div class="stat-card green"><div class="stat-value" id="statTasks">-</div><div class="stat-label" data-i18n="stat.tasks">Tasks</div></div>
1253
- <div class="stat-card amber"><div class="stat-value" id="statSkills">-</div><div class="stat-label" data-i18n="stat.skills">Skills</div></div>
1228
+ <div class="stat-card green"><div class="stat-value" id="statSessions">-</div><div class="stat-label" data-i18n="stat.sessions">Sessions</div></div>
1229
+ <div class="stat-card amber"><div class="stat-value" id="statEmbeddings">-</div><div class="stat-label" data-i18n="stat.embeddings">Embeddings</div></div>
1254
1230
  <div class="stat-card rose"><div class="stat-value" id="statAgents">-</div><div class="stat-label" data-i18n="stat.agents">Agents</div></div>
1255
1231
  </div>
1256
1232
  <div id="sidebarSharingSection" style="display:none">
@@ -1261,7 +1237,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
1261
1237
  </div>
1262
1238
  </div>
1263
1239
  <div id="embeddingStatus"></div>
1264
- <button class="btn btn-sm btn-ghost" style="width:100%;margin:20px 0 12px;justify-content:center;color:var(--text-muted);font-size:11px" onclick="clearAll()" data-i18n="sidebar.clear">\u{1F5D1} Clear All Data</button>
1240
+ <div class="session-list" id="sessionList" style="display:none"></div>
1241
+ <button class="btn btn-sm btn-ghost" style="width:100%;margin-top:20px;justify-content:center;color:var(--text-muted);font-size:11px" onclick="clearAll()" data-i18n="sidebar.clear">\u{1F5D1} Clear All Data</button>
1265
1242
  </div>
1266
1243
 
1267
1244
  <div class="view-container">
@@ -1274,13 +1251,14 @@ input,textarea,select{font-family:inherit;font-size:inherit}
1274
1251
  <option value="" data-i18n="filter.allagents">All agents</option>
1275
1252
  </select>
1276
1253
  <select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()" style="display:none">
1254
+ <option value="local" data-i18n="scope.thisAgent">This Agent</option>
1277
1255
  <option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
1278
1256
  <option value="hub" data-i18n="scope.hub">Team</option>
1279
1257
  </select>
1280
1258
  </div>
1281
- <div id="searchMeta" style="display:none"></div>
1282
- <div id="sharingSearchMeta" style="display:none"></div>
1283
- <div class="filter-bar compact-filter-row" id="filterBar" style="flex-wrap:nowrap">
1259
+ <div class="search-meta" id="searchMeta"></div>
1260
+ <div class="search-meta" id="sharingSearchMeta"></div>
1261
+ <div class="filter-bar" id="filterBar">
1284
1262
  <button class="filter-chip active" data-role="" onclick="setRoleFilter(this,'')" data-i18n="filter.all">All</button>
1285
1263
  <button class="filter-chip" data-role="user" onclick="setRoleFilter(this,'user')">User</button>
1286
1264
  <button class="filter-chip" data-role="assistant" onclick="setRoleFilter(this,'assistant')">Assistant</button>
@@ -1289,48 +1267,42 @@ input,textarea,select{font-family:inherit;font-size:inherit}
1289
1267
  <option value="newest" data-i18n="filter.newest">Newest first</option>
1290
1268
  <option value="oldest" data-i18n="filter.oldest">Oldest first</option>
1291
1269
  </select>
1292
- <span style="flex:1"></span>
1293
- <button class="filter-chip" id="memorySelectAllBtn" onclick="toggleSelectAllMemories()" data-i18n="skills.selectAll">Select All</button>
1294
- <button class="filter-chip" id="memoryBulkDeleteBtn" onclick="deleteSelectedMemories()" style="display:none;color:#ef4444;border-color:rgba(239,68,68,.3)" data-i18n="memory.deleteSelected">Delete Selected</button>
1270
+ <span class="filter-sep"></span>
1271
+ <select id="filterSession" class="filter-select" onchange="filterSession(this.value||null)">
1272
+ <option value="" data-i18n="filter.allsessions">All sessions</option>
1273
+ </select>
1295
1274
  </div>
1296
- <div class="filter-bar compact-filter-row" style="flex-wrap:nowrap;margin-bottom:12px">
1297
- <input type="datetime-local" id="dateFrom" step="1" onchange="applyFilters()" class="compact-date" data-i18n-ph="filter.from" placeholder="From">
1298
- <span style="color:var(--text-muted);font-size:12px">—</span>
1299
- <input type="datetime-local" id="dateTo" step="1" onchange="applyFilters()" class="compact-date" data-i18n-ph="filter.to" placeholder="To">
1300
- <button class="filter-chip" onclick="clearDateFilter()" data-i18n="filter.clear" style="font-size:11px;padding:4px 10px">Clear</button>
1275
+ <div class="date-filter">
1276
+ <label data-i18n="filter.from">From</label><input type="datetime-local" id="dateFrom" step="1" onchange="applyFilters()">
1277
+ <label data-i18n="filter.to">To</label><input type="datetime-local" id="dateTo" step="1" onchange="applyFilters()">
1278
+ <button class="btn btn-sm btn-text" onclick="clearDateFilter()" data-i18n="filter.clear">Clear</button>
1301
1279
  </div>
1302
1280
  <div class="memory-list" id="memoryList"><div class="spinner"></div></div>
1303
- <div class="pagination-row">
1304
- <div class="pagination" id="pagination"></div>
1305
- </div>
1281
+ <div class="pagination" id="pagination"></div>
1306
1282
  </div>
1307
1283
  </div>
1308
1284
  <div class="tasks-view vp" id="tasksView">
1309
- <div class="search-bar">
1310
- <span class="search-icon">\u{1F50D}</span>
1311
- <input type="text" id="taskSearchInput" data-i18n-ph="tasks.search.placeholder" placeholder="Search tasks..." oninput="debounceTaskSearch()">
1312
- <select id="taskFilterOwner" class="filter-select" onchange="onOwnerFilterChange()">
1313
- <option value="" data-i18n="filter.allagents">All agents</option>
1314
- </select>
1315
- <select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()" style="display:none">
1316
- <option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
1317
- <option value="hub" data-i18n="scope.hub">Team</option>
1318
- </select>
1319
- </div>
1320
- <div id="taskSearchMeta" style="display:none"></div>
1321
- <div class="filter-bar compact-filter-row" style="flex-wrap:nowrap">
1322
- <button class="filter-chip active" data-task-status="" onclick="setTaskStatusFilter(this,'')" data-i18n="filter.all">All</button>
1323
- <button class="filter-chip" data-task-status="active" onclick="setTaskStatusFilter(this,'active')" data-i18n="tasks.status.active">Active</button>
1324
- <button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
1325
- <button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
1326
- <span style="flex:1"></span>
1327
- <button class="filter-chip" id="taskSelectAllBtn" onclick="toggleSelectAllTasks()" data-i18n="skills.selectAll">Select All</button>
1328
- <button class="filter-chip" id="taskBulkDeleteBtn" onclick="deleteSelectedTasks()" style="display:none;color:#ef4444;border-color:rgba(239,68,68,.3)" data-i18n="task.deleteSelected">Delete Selected</button>
1285
+ <div class="tasks-header">
1286
+ <div class="tasks-stats">
1287
+ <div class="tasks-stat"><span class="tasks-stat-value" id="tasksTotalCount">-</span><span class="tasks-stat-label" data-i18n="tasks.total">Total Tasks</span></div>
1288
+ <div class="tasks-stat"><span class="tasks-stat-value" id="tasksActiveCount">-</span><span class="tasks-stat-label" data-i18n="tasks.active">Active</span></div>
1289
+ <div class="tasks-stat"><span class="tasks-stat-value" id="tasksCompletedCount">-</span><span class="tasks-stat-label" data-i18n="tasks.completed">Completed</span></div>
1290
+ <div class="tasks-stat"><span class="tasks-stat-value" id="tasksSkippedCount">-</span><span class="tasks-stat-label" data-i18n="tasks.status.skipped">Skipped</span></div>
1291
+ </div>
1292
+ <div class="tasks-filters">
1293
+ <button class="filter-chip active" data-task-status="" onclick="setTaskStatusFilter(this,'')" data-i18n="filter.all">All</button>
1294
+ <button class="filter-chip" data-task-status="active" onclick="setTaskStatusFilter(this,'active')" data-i18n="tasks.status.active">Active</button>
1295
+ <button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
1296
+ <button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
1297
+ <select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()" style="display:none">
1298
+ <option value="local" data-i18n="scope.thisAgent">This Agent</option>
1299
+ <option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
1300
+ <option value="hub" data-i18n="scope.hub">Team</option>
1301
+ </select>
1302
+ </div>
1329
1303
  </div>
1330
1304
  <div class="tasks-list" id="tasksList"><div class="spinner"></div></div>
1331
- <div class="pagination-row">
1332
- <div class="pagination" id="tasksPagination"></div>
1333
- </div>
1305
+ <div class="pagination" id="tasksPagination"></div>
1334
1306
  <div class="task-detail-overlay" id="taskDetailOverlay" onclick="closeTaskDetail(event)">
1335
1307
  <div class="task-detail-panel" onclick="event.stopPropagation()">
1336
1308
  <div class="task-detail-header">
@@ -1364,33 +1336,34 @@ input,textarea,select{font-family:inherit;font-size:inherit}
1364
1336
  <div class="search-bar">
1365
1337
  <span class="search-icon">🔍</span>
1366
1338
  <input type="text" id="skillSearchInput" placeholder="Search skills..." data-i18n-ph="skills.search.placeholder" oninput="debounceSkillSearch()">
1367
- <select id="skillFilterOwner" class="filter-select" onchange="onOwnerFilterChange()">
1368
- <option value="" data-i18n="filter.allagents">All agents</option>
1369
- </select>
1370
1339
  <select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()" style="display:none">
1340
+ <option value="local" data-i18n="scope.thisAgent">This Agent</option>
1371
1341
  <option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
1372
1342
  <option value="hub" data-i18n="scope.hub">Team</option>
1373
1343
  </select>
1374
1344
  </div>
1375
- <div id="skillSearchMeta" style="display:none"></div>
1376
- <div class="filter-bar compact-filter-row" style="flex-wrap:nowrap">
1377
- <button class="filter-chip active" data-skill-status="" onclick="setSkillStatusFilter(this,'')" data-i18n="filter.all">All</button>
1378
- <button class="filter-chip" data-skill-status="active" onclick="setSkillStatusFilter(this,'active')" data-i18n="skills.filter.active">Active</button>
1379
- <button class="filter-chip" data-skill-status="draft" onclick="setSkillStatusFilter(this,'draft')" data-i18n="skills.filter.draft">Draft</button>
1380
- <button class="filter-chip" data-skill-status="archived" onclick="setSkillStatusFilter(this,'archived')" data-i18n="skills.filter.archived">Archived</button>
1381
- <select id="skillVisibilityFilter" class="filter-select" onchange="loadSkills()" style="display:none">
1382
- <option value="" data-i18n="filter.allvisibility">All visibility</option>
1383
- <option value="public" data-i18n="filter.public">Public</option>
1384
- <option value="private" data-i18n="filter.private">Private</option>
1385
- </select>
1386
- <span style="flex:1"></span>
1387
- <button class="filter-chip" id="skillSelectAllBtn" onclick="toggleSelectAllSkills()" data-i18n="skills.selectAll">Select All</button>
1388
- <button class="filter-chip" id="skillBulkDeleteBtn" onclick="deleteSelectedSkills()" style="display:none;color:#ef4444;border-color:rgba(239,68,68,.3)" data-i18n="skills.deleteSelected">Delete Selected</button>
1345
+ <div class="search-meta" id="skillSearchMeta" style="display:none"></div>
1346
+ <div class="tasks-header">
1347
+ <div class="tasks-stats">
1348
+ <div class="tasks-stat"><span class="tasks-stat-value" id="skillsTotalCount">-</span><span class="tasks-stat-label" data-i18n="skills.total">Total Skills</span></div>
1349
+ <div class="tasks-stat" style="border-left:3px solid var(--green)"><span class="tasks-stat-value" id="skillsActiveCount">-</span><span class="tasks-stat-label" data-i18n="skills.active">Active</span></div>
1350
+ <div class="tasks-stat" style="border-left:3px solid var(--amber)"><span class="tasks-stat-value" id="skillsDraftCount">-</span><span class="tasks-stat-label" data-i18n="skills.draft">Draft</span></div>
1351
+ <div class="tasks-stat" style="border-left:3px solid var(--violet)"><span class="tasks-stat-value" id="skillsInstalledCount">-</span><span class="tasks-stat-label" data-i18n="skills.installed">Installed</span></div>
1352
+ <div class="tasks-stat" style="border-left:3px solid var(--cyan)"><span class="tasks-stat-value" id="skillsPublicCount">-</span><span class="tasks-stat-label" data-i18n="skills.public">Public</span></div>
1353
+ </div>
1354
+ <div class="tasks-filters">
1355
+ <button class="filter-chip active" data-skill-status="" onclick="setSkillStatusFilter(this,'')" data-i18n="filter.all">All</button>
1356
+ <button class="filter-chip" data-skill-status="active" onclick="setSkillStatusFilter(this,'active')" data-i18n="skills.filter.active">Active</button>
1357
+ <button class="filter-chip" data-skill-status="draft" onclick="setSkillStatusFilter(this,'draft')" data-i18n="skills.filter.draft">Draft</button>
1358
+ <button class="filter-chip" data-skill-status="archived" onclick="setSkillStatusFilter(this,'archived')" data-i18n="skills.filter.archived">Archived</button>
1359
+ <select id="skillVisibilityFilter" class="filter-select" onchange="loadSkills()" style="display:none">
1360
+ <option value="" data-i18n="filter.allvisibility">All visibility</option>
1361
+ <option value="public" data-i18n="filter.public">Public</option>
1362
+ <option value="private" data-i18n="filter.private">Private</option>
1363
+ </select>
1364
+ </div>
1389
1365
  </div>
1390
1366
  <div class="tasks-list" id="skillsList"><div class="spinner"></div></div>
1391
- <div class="pagination-row">
1392
- <div class="pagination" id="skillsPagination"></div>
1393
- </div>
1394
1367
  <div id="hubSkillsSection" style="display:none;margin-top:16px">
1395
1368
  <div class="section-title" style="margin-bottom:12px" data-i18n="skills.hub.title">\u{1F310} Team Skills</div>
1396
1369
  <div class="tasks-list" id="hubSkillsList"></div>
@@ -1818,11 +1791,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
1818
1791
  <input type="number" id="cfgViewerPort" placeholder="18799">
1819
1792
  <div class="field-hint" data-i18n="settings.viewerport.hint">Requires restart to take effect</div>
1820
1793
  </div>
1821
- <div class="settings-field">
1822
- <label data-i18n="settings.taskAutoFinalize">Task Auto-Finalize (hours)</label>
1823
- <input type="number" id="cfgTaskAutoFinalizeHours" placeholder="4" min="0" step="1" style="max-width:120px" onkeydown="if(['-','e','E','+'].includes(event.key))event.preventDefault()" oninput="this.value=this.value.replace(/[^0-9]/g,'')">
1824
- <div class="field-hint" data-i18n="settings.taskAutoFinalize.hint">Active tasks with no new messages beyond this duration will be automatically summarized and completed when the Tasks page is opened. Set to 0 to disable. Default: 4 hours.</div>
1825
- </div>
1826
1794
  </div>
1827
1795
  <div class="settings-card-divider"></div>
1828
1796
  <div class="settings-toggle">
@@ -1903,20 +1871,18 @@ input,textarea,select{font-family:inherit;font-size:inherit}
1903
1871
  </div>
1904
1872
  </div>
1905
1873
 
1906
- <div id="migrateActions" style="display:flex;gap:10px 16px;align-items:center;flex-wrap:wrap">
1874
+ <div id="migrateActions" style="display:flex;gap:12px;align-items:center;flex-wrap:wrap">
1907
1875
  <button class="btn" onclick="migrateScan(true)" id="migrateScanBtn" style="background:var(--bg);border:1px solid var(--border);color:var(--text);font-weight:600;padding:7px 18px;cursor:pointer" data-i18n="migrate.scan">Scan Data Sources</button>
1908
- <div id="migrateStartConcurrencyWrap" style="display:none;align-items:center;gap:12px;flex-wrap:wrap;flex-shrink:0">
1909
- <button class="btn btn-primary" onclick="migrateStart()" id="migrateStartBtn" style="display:inline-flex" data-i18n="migrate.start">Start Import</button>
1910
- <span id="migrateConcurrencyRow" style="display:flex;align-items:center;gap:8px;flex-shrink:0;min-width:max-content">
1911
- <span style="font-size:11px;color:var(--text-muted);white-space:nowrap" data-i18n="migrate.concurrency.label">Concurrent agents</span>
1912
- <select id="migrateConcurrency" class="filter-select" style="min-width:auto;padding:3px 28px 3px 10px;font-size:11px">
1913
- <option value="1" selected>1</option>
1914
- <option value="2">2</option>
1915
- <option value="4">4</option>
1916
- <option value="8">8</option>
1917
- </select>
1918
- </span>
1919
- </div>
1876
+ <button class="btn btn-primary" onclick="migrateStart()" id="migrateStartBtn" style="display:none" data-i18n="migrate.start">Start Import</button>
1877
+ <span id="migrateConcurrencyRow" style="display:none;align-items:center;gap:6px">
1878
+ <span style="font-size:11px;color:var(--text-muted)" data-i18n="migrate.concurrency.label">Concurrent agents</span>
1879
+ <select id="migrateConcurrency" class="filter-select" style="min-width:auto;padding:3px 10px;font-size:11px">
1880
+ <option value="1" selected>1</option>
1881
+ <option value="2">2</option>
1882
+ <option value="4">4</option>
1883
+ <option value="8">8</option>
1884
+ </select>
1885
+ </span>
1920
1886
  <span id="migrateStatus" style="font-size:11px;color:var(--text-muted)"></span>
1921
1887
  </div>
1922
1888
  <div id="migrateConcurrencyWarn" style="display:none;margin-top:8px;padding:8px 12px;background:rgba(245,158,11,.06);border:1px solid rgba(245,158,11,.2);border-radius:8px;font-size:11px;color:#f59e0b;line-height:1.5">
@@ -1949,7 +1915,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
1949
1915
  <button class="btn btn-sm" id="ppStopBtn" onclick="ppStop()" style="display:none;background:rgba(239,68,68,.12);color:#ef4444;border:1px solid rgba(239,68,68,.3);font-size:12px;padding:5px 16px;font-weight:600" data-i18n="migrate.stop">\u25A0 Stop</button>
1950
1916
  <span style="display:inline-flex;align-items:center;gap:6px">
1951
1917
  <span style="font-size:11px;color:var(--text-muted)" data-i18n="pp.concurrency.label">Concurrent agents</span>
1952
- <select id="ppConcurrency" class="filter-select" style="min-width:auto;padding:3px 28px 3px 10px;font-size:11px">
1918
+ <select id="ppConcurrency" class="filter-select" style="min-width:auto;padding:3px 10px;font-size:11px">
1953
1919
  <option value="1" selected>1</option>
1954
1920
  <option value="2">2</option>
1955
1921
  <option value="4">4</option>
@@ -2063,21 +2029,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
2063
2029
  <div class="toast-container" id="toasts"></div>
2064
2030
 
2065
2031
  <script>
2066
- let activeSession=null,activeRole='',editingId=null,searchTimer=null,memoryCache={},currentPage=1,totalPages=1,totalCount=0,PAGE_SIZE=20,metricsDays=30;
2067
- let memorySearchScope='allLocal',skillSearchScope='allLocal',taskSearchScope='allLocal';
2032
+ let activeSession=null,activeRole='',editingId=null,searchTimer=null,memoryCache={},currentPage=1,totalPages=1,totalCount=0,PAGE_SIZE=40,metricsDays=30;
2033
+ let memorySearchScope='local',skillSearchScope='local',taskSearchScope='local';
2068
2034
  let _lastMemoriesFingerprint='',_lastTasksFingerprint='',_lastSkillsFingerprint='';
2069
- let selectedMemoryIds=new Set(),currentMemoryIds=[];
2070
- let selectedTaskIds=new Set(),currentTaskIds=[];
2071
2035
  let _embeddingWarningShown=false;
2072
2036
  let _currentAgentOwner='agent:main';
2073
- try {
2074
- const urlParams = new URLSearchParams(window.location.search);
2075
- const agentId = urlParams.get('agentId');
2076
- if (agentId) {
2077
- _currentAgentOwner = 'agent:' + agentId;
2078
- }
2079
- } catch(e) {}
2080
-
2081
2037
 
2082
2038
  /* ─── i18n ─── */
2083
2039
  const I18N={
@@ -2142,8 +2098,6 @@ const I18N={
2142
2098
  'tasks.status.active':'Active',
2143
2099
  'tasks.status.completed':'Completed',
2144
2100
  'tasks.status.skipped':'Skipped',
2145
- 'tasks.search.placeholder':'Search tasks...',
2146
- 'tasks.search.meta':'Found {0} tasks',
2147
2101
  'tasks.empty':'No tasks yet. Tasks are automatically created as you converse.',
2148
2102
  'tasks.loading':'Loading...',
2149
2103
  'tasks.untitled':'Untitled Task',
@@ -2184,8 +2138,8 @@ const I18N={
2184
2138
  'notif.timeAgo.hour':'{n}h ago',
2185
2139
  'notif.timeAgo.day':'{n}d ago',
2186
2140
  'stat.memories':'Memories',
2187
- 'stat.tasks':'Tasks',
2188
- 'stat.skills':'Skills',
2141
+ 'stat.sessions':'Sessions',
2142
+ 'stat.embeddings':'Embeddings',
2189
2143
  'stat.agents':'Agents',
2190
2144
  'stat.active':'active',
2191
2145
  'stat.deduped':'deduped',
@@ -2225,7 +2179,6 @@ const I18N={
2225
2179
  'card.dedupTarget':'Target: ',
2226
2180
  'card.dedupReason':'Reason: ',
2227
2181
  'card.newSummary':'New',
2228
- 'pagination.pageSize':'Items per page',
2229
2182
  'pagination.total':' total',
2230
2183
  'range':'Range',
2231
2184
  'range.days':'days',
@@ -2325,8 +2278,6 @@ const I18N={
2325
2278
  'settings.telemetry.hint':'Only collects tool names, latencies and version info. No memory content or personal data.',
2326
2279
  'settings.viewerport':'Viewer Port',
2327
2280
  'settings.viewerport.hint':'Requires restart to take effect',
2328
- 'settings.taskAutoFinalize':'Task Auto-Finalize (hours)',
2329
- 'settings.taskAutoFinalize.hint':'Active tasks with no new messages beyond this duration will be automatically summarized and completed when the Tasks page is opened. Set to 0 to disable. Default: 4 hours.',
2330
2281
  'settings.test':'Test Connection',
2331
2282
  'settings.test.loading':'Testing...',
2332
2283
  'settings.test.ok':'Connected',
@@ -2434,18 +2385,9 @@ const I18N={
2434
2385
  'skills.nochangelog':'No changelog',
2435
2386
  'skills.status.active':'Active',
2436
2387
  'skills.status.draft':'Draft',
2437
- 'skills.status.archived':'Disabled',
2438
- 'skills.action.disable':'Disable',
2439
- 'skills.action.enable':'Enable',
2440
- 'skills.action.delete':'Delete',
2441
- 'skills.disable.confirm':'Are you sure you want to disable this skill? It will no longer be used in search or auto-recall, but can be re-enabled later.',
2442
- 'skills.disable.error':'Failed to disable skill: ',
2443
- 'skills.enable.error':'Failed to enable skill: ',
2388
+ 'skills.status.archived':'Archived',
2444
2389
  'skills.updated':'Updated: ',
2445
2390
  'skills.task.prefix':'Task: ',
2446
- 'skills.selectAll':'Select All',
2447
- 'skills.unselectAll':'Unselect All',
2448
- 'skills.deleteSelected':'Delete Selected',
2449
2391
  'tasks.chunks.label':'chunks',
2450
2392
  'tasks.taskid':'Task ID: ',
2451
2393
  'tasks.role.user':'You',
@@ -2786,10 +2728,6 @@ const I18N={
2786
2728
  'task.cancel':'Cancel',
2787
2729
  'task.delete.confirm':'Are you sure you want to delete this task? This cannot be undone.',
2788
2730
  'task.delete.error':'Failed to delete task: ',
2789
- 'task.deleteSelected':'Delete Selected',
2790
- 'task.delete.selected.confirm':'Delete {count} selected tasks? This action cannot be undone.',
2791
- 'task.delete.success':'Deleted {count} tasks.',
2792
- 'task.delete.partial':'Deleted {ok} tasks, failed {fail}.',
2793
2731
  'task.save.error':'Failed to save task: ',
2794
2732
  'task.retrySkill':'Retry Skill Generation',
2795
2733
  'task.retrySkill.short':'Retry Skill',
@@ -2800,14 +2738,7 @@ const I18N={
2800
2738
  'skill.save':'Save',
2801
2739
  'skill.cancel':'Cancel',
2802
2740
  'skill.delete.confirm':'Are you sure you want to delete this skill? This will also remove all associated files and cannot be undone.',
2803
- 'skill.delete.selected.confirm':'Delete {count} selected skills? This action cannot be undone.',
2804
2741
  'skill.delete.error':'Failed to delete skill: ',
2805
- 'skill.delete.partial':'Deleted {ok} skills, failed {fail}.',
2806
- 'skill.delete.success':'Deleted {count} skills.',
2807
- 'memory.deleteSelected':'Delete Selected',
2808
- 'memory.delete.selected.confirm':'Delete {count} selected memories? This action cannot be undone.',
2809
- 'memory.delete.success':'Deleted {count} memories.',
2810
- 'memory.delete.partial':'Deleted {ok} memories, failed {fail}.',
2811
2742
  'skill.save.error':'Failed to save skill: ',
2812
2743
  'update.available':'New version available',
2813
2744
  'update.run':'Run',
@@ -2911,8 +2842,6 @@ const I18N={
2911
2842
  'tasks.status.active':'进行中',
2912
2843
  'tasks.status.completed':'已完成',
2913
2844
  'tasks.status.skipped':'已跳过',
2914
- 'tasks.search.placeholder':'搜索任务...',
2915
- 'tasks.search.meta':'找到 {0} 个任务',
2916
2845
  'tasks.empty':'暂无任务。任务会随着对话自动创建。',
2917
2846
  'tasks.loading':'加载中...',
2918
2847
  'tasks.untitled':'未命名任务',
@@ -2953,8 +2882,8 @@ const I18N={
2953
2882
  'notif.timeAgo.hour':'{n}小时前',
2954
2883
  'notif.timeAgo.day':'{n}天前',
2955
2884
  'stat.memories':'记忆',
2956
- 'stat.tasks':'任务',
2957
- 'stat.skills':'技能',
2885
+ 'stat.sessions':'会话',
2886
+ 'stat.embeddings':'嵌入',
2958
2887
  'stat.agents':'智能体',
2959
2888
  'stat.active':'活跃',
2960
2889
  'stat.deduped':'已去重',
@@ -2994,7 +2923,6 @@ const I18N={
2994
2923
  'card.dedupTarget':'关联: ',
2995
2924
  'card.dedupReason':'原因: ',
2996
2925
  'card.newSummary':'新摘要',
2997
- 'pagination.pageSize':'每页数量',
2998
2926
  'pagination.total':' 条',
2999
2927
  'range':'范围',
3000
2928
  'range.days':'天',
@@ -3094,8 +3022,6 @@ const I18N={
3094
3022
  'settings.telemetry.hint':'仅收集工具名称、响应时间和版本号,不涉及任何记忆内容或个人数据。',
3095
3023
  'settings.viewerport':'Viewer 端口',
3096
3024
  'settings.viewerport.hint':'修改后需重启网关生效',
3097
- 'settings.taskAutoFinalize':'任务自动完结(小时)',
3098
- 'settings.taskAutoFinalize.hint':'处于进行中的任务如果超过设定时间没有新消息,打开任务页面时会自动生成总结并标记为已完成。设为 0 则关闭此功能。默认:4 小时。',
3099
3025
  'settings.test':'测试连接',
3100
3026
  'settings.test.loading':'测试中...',
3101
3027
  'settings.test.ok':'连接成功',
@@ -3203,18 +3129,9 @@ const I18N={
3203
3129
  'skills.nochangelog':'暂无变更记录',
3204
3130
  'skills.status.active':'生效中',
3205
3131
  'skills.status.draft':'草稿',
3206
- 'skills.status.archived':'已禁用',
3207
- 'skills.action.disable':'禁用',
3208
- 'skills.action.enable':'启用',
3209
- 'skills.action.delete':'删除',
3210
- 'skills.disable.confirm':'确定要禁用此技能吗?禁用后不再参与检索和自动召回,但可以随时重新启用。',
3211
- 'skills.disable.error':'禁用技能失败:',
3212
- 'skills.enable.error':'启用技能失败:',
3132
+ 'skills.status.archived':'已归档',
3213
3133
  'skills.updated':'更新于:',
3214
3134
  'skills.task.prefix':'任务:',
3215
- 'skills.selectAll':'全选',
3216
- 'skills.unselectAll':'取消全选',
3217
- 'skills.deleteSelected':'删除选中',
3218
3135
  'tasks.chunks.label':'条记忆',
3219
3136
  'tasks.taskid':'任务 ID:',
3220
3137
  'tasks.role.user':'你',
@@ -3555,10 +3472,6 @@ const I18N={
3555
3472
  'task.cancel':'取消',
3556
3473
  'task.delete.confirm':'确定要删除此任务吗?此操作不可撤销。',
3557
3474
  'task.delete.error':'删除任务失败:',
3558
- 'task.deleteSelected':'删除选中',
3559
- 'task.delete.selected.confirm':'确定删除选中的 {count} 个任务吗?此操作不可撤销。',
3560
- 'task.delete.success':'已删除 {count} 个任务。',
3561
- 'task.delete.partial':'已删除 {ok} 个任务,失败 {fail} 个。',
3562
3475
  'task.save.error':'保存任务失败:',
3563
3476
  'task.retrySkill':'重新生成技能',
3564
3477
  'task.retrySkill.short':'重试技能',
@@ -3569,14 +3482,7 @@ const I18N={
3569
3482
  'skill.save':'保存',
3570
3483
  'skill.cancel':'取消',
3571
3484
  'skill.delete.confirm':'确定要删除此技能吗?关联的文件也会被删除,此操作不可撤销。',
3572
- 'skill.delete.selected.confirm':'确定删除选中的 {count} 个技能吗?此操作不可撤销。',
3573
3485
  'skill.delete.error':'删除技能失败:',
3574
- 'skill.delete.partial':'已删除 {ok} 个技能,失败 {fail} 个。',
3575
- 'skill.delete.success':'已删除 {count} 个技能。',
3576
- 'memory.deleteSelected':'删除选中',
3577
- 'memory.delete.selected.confirm':'确定删除选中的 {count} 条记忆吗?此操作不可撤销。',
3578
- 'memory.delete.success':'已删除 {count} 条记忆。',
3579
- 'memory.delete.partial':'已删除 {ok} 条记忆,失败 {fail} 条。',
3580
3486
  'skill.save.error':'保存技能失败:',
3581
3487
  'update.available':'发现新版本',
3582
3488
  'update.run':'执行命令',
@@ -3861,12 +3767,9 @@ function switchView(view){
3861
3767
  }
3862
3768
  var sessionSection=document.getElementById('sidebarSessionSection');
3863
3769
  if(sessionSection){
3864
- if(view==='memories'||view==='tasks'||view==='skills'){sessionSection.style.visibility='';sessionSection.style.pointerEvents='';}
3770
+ if(view==='memories'){sessionSection.style.visibility='';sessionSection.style.pointerEvents='';}
3865
3771
  else{sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
3866
3772
  }
3867
- if(view==='memories'||view==='tasks'||view==='skills'){
3868
- loadStats();
3869
- }
3870
3773
  if(view==='tasks') loadTasks();
3871
3774
  else if(view==='skills') loadSkills();
3872
3775
  else if(view==='analytics') loadMetrics();
@@ -3883,84 +3786,36 @@ function switchView(view){
3883
3786
  }
3884
3787
 
3885
3788
  function onMemoryScopeChange(){
3886
- memorySearchScope=document.getElementById('memorySearchScope')?.value||'allLocal';
3789
+ memorySearchScope=document.getElementById('memorySearchScope')?.value||'local';
3887
3790
  try{localStorage.setItem('memos_memorySearchScope',memorySearchScope);}catch(e){}
3888
3791
  currentPage=1;
3889
3792
  activeSession=null;activeRole='';
3890
3793
  _lastMemoriesFingerprint='';
3891
- if(memorySearchScope==='hub') selectedMemoryIds.clear();
3892
3794
  var isHub=memorySearchScope==='hub';
3795
+ var isLocal=memorySearchScope==='local';
3893
3796
  var ownerSel=document.getElementById('filterOwner');
3894
3797
  var filterBar=document.getElementById('filterBar');
3895
3798
  var dateFilter=document.querySelector('.date-filter');
3896
- if(ownerSel){ownerSel.style.display=isHub?'none':'';if(isHub)ownerSel.value='';}
3799
+ if(ownerSel){ownerSel.style.display=(isHub||isLocal)?'none':'';if(isHub||isLocal)ownerSel.value='';}
3897
3800
  if(filterBar) filterBar.style.display=isHub?'none':'';
3898
3801
  if(dateFilter) dateFilter.style.display=isHub?'none':'';
3899
- updateMemorySelectionToolbar();
3900
3802
  if(document.getElementById('searchInput').value.trim()) doSearch(document.getElementById('searchInput').value);
3901
3803
  else if(isHub) { document.getElementById('sharingSearchMeta').textContent=''; loadHubMemories(); }
3902
3804
  else {
3903
3805
  document.getElementById('sharingSearchMeta').textContent='';
3904
- var ownerArg=undefined;
3806
+ var ownerArg=isLocal?_currentAgentOwner:undefined;
3905
3807
  loadStats(ownerArg); loadMemories();
3906
3808
  }
3907
3809
  }
3908
3810
 
3909
- function normalizePageSize(value,fallback){
3910
- const v=Number(value);
3911
- return v===10||v===20||v===40?v:fallback;
3912
- }
3913
-
3914
- function applyPageSizeFromSelect(selectId,storageKey,fallback,onApply){
3915
- const el=document.getElementById(selectId);
3916
- const next=normalizePageSize(el?.value,fallback);
3917
- onApply(next);
3918
- try{localStorage.setItem(storageKey,String(next));}catch(e){}
3919
- return next;
3920
- }
3921
-
3922
- function restorePageSizeSetting(storageKey,selectId,fallback,onApply){
3923
- let next=fallback;
3924
- try{
3925
- const raw=localStorage.getItem(storageKey);
3926
- next=normalizePageSize(raw||String(fallback),fallback);
3927
- }catch(e){}
3928
- onApply(next);
3929
- const el=document.getElementById(selectId);
3930
- if(el) el.value=String(next);
3931
- return next;
3932
- }
3933
-
3934
- function onMemoryPageSizeChange(){
3935
- applyPageSizeFromSelect('memoryPageSize','memos_memoryPageSize',20,function(next){PAGE_SIZE=next;});
3936
- currentPage=1;
3937
- if(memorySearchScope==='hub') loadHubMemories();
3938
- else loadMemories();
3939
- }
3940
-
3941
3811
  function onSkillScopeChange(){
3942
- skillSearchScope=document.getElementById('skillSearchScope')?.value||'allLocal';
3943
- skillsPage=0;
3944
- loadSkills();
3945
- }
3946
-
3947
- function onSkillsPageSizeChange(){
3948
- applyPageSizeFromSelect('skillsPageSize','memos_skillsPageSize',20,function(next){skillsPageSize=next;});
3949
- skillsPage=0;
3812
+ skillSearchScope=document.getElementById('skillSearchScope')?.value||'local';
3950
3813
  loadSkills();
3951
3814
  }
3952
3815
 
3953
- function onTasksPageSizeChange(){
3954
- applyPageSizeFromSelect('tasksPageSize','memos_tasksPageSize',20,function(next){tasksPageSize=next;});
3955
- tasksPage=0;
3956
- loadTasks();
3957
- }
3958
-
3959
3816
  function onTaskScopeChange(){
3960
- taskSearchScope=document.getElementById('taskSearchScope')?.value||'allLocal';
3961
- if(taskSearchScope==='hub') selectedTaskIds.clear();
3817
+ taskSearchScope=document.getElementById('taskSearchScope')?.value||'local';
3962
3818
  tasksPage=0;
3963
- updateTaskSelectionToolbar();
3964
3819
  loadTasks();
3965
3820
  }
3966
3821
 
@@ -3972,11 +3827,6 @@ function _updateScopeSelectorsVisibility(hubAvailable){
3972
3827
  var el=document.getElementById(ids[i]);
3973
3828
  if(el) el.style.display=hubAvailable?'':'none';
3974
3829
  }
3975
- if(!hubAvailable){
3976
- if(memorySearchScope==='hub'){memorySearchScope='allLocal';try{localStorage.setItem('memos_memorySearchScope','allLocal');}catch(e){}}
3977
- if(taskSearchScope==='hub'){taskSearchScope='allLocal';try{localStorage.setItem('memos_taskSearchScope','allLocal');}catch(e){}}
3978
- if(skillSearchScope==='hub'){skillSearchScope='allLocal';try{localStorage.setItem('memos_skillSearchScope','allLocal');}catch(e){}}
3979
- }
3980
3830
  }
3981
3831
  async function loadSharingStatus(forcePending){
3982
3832
  try{
@@ -5190,7 +5040,6 @@ function renderSharingMemorySearchResults(data,query){
5190
5040
  const list=document.getElementById('memoryList');
5191
5041
  const localHits=(data&&data.local&&Array.isArray(data.local.hits))?data.local.hits:[];
5192
5042
  const hubHits=(data&&data.hub&&Array.isArray(data.hub.hits))?data.hub.hits:[];
5193
- setPageSizeVisible('memoryPageSize',(localHits.length+hubHits.length)>0);
5194
5043
  document.getElementById('searchMeta').textContent='Search results for "'+query+'"';
5195
5044
  document.getElementById('sharingSearchMeta').textContent=t('scope.local')+' '+localHits.length+' · '+t('scope.hub')+' '+hubHits.length;
5196
5045
  document.getElementById('pagination').innerHTML='';
@@ -5198,13 +5047,11 @@ function renderSharingMemorySearchResults(data,query){
5198
5047
  '<div class="result-section">'+
5199
5048
  '<div class="result-section-header"><div class="result-section-title">'+t('search.localResults')+'</div><div class="result-section-sub">'+localHits.length+' hit(s)</div></div>'+
5200
5049
  '<div class="search-hit-list">'+(localHits.length?localHits.map(function(hit,idx){
5201
- var agentName='';if(hit.owner){var ap=(hit.owner||'').split(':');agentName=ap.length>=3?ap[ap.length-1]:(ap.length>=2?ap[1]:hit.owner);}
5202
5050
  return '<div class="search-hit-card">'+
5203
5051
  '<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
5204
5052
  '<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
5205
5053
  '<div class="search-hit-meta">'+
5206
5054
  '<span class="meta-chip">role: '+esc(hit.role||'unknown')+'</span>'+
5207
- (agentName?'<span class="meta-chip" style="background:rgba(20,184,166,.12);color:#14b8a6">'+esc(agentName)+'</span>':'')+
5208
5055
  (hit.score!=null?'<span class="meta-chip">score: '+Math.round(hit.score*100)+'%</span>':'')+
5209
5056
  (hit.taskId?'<span class="meta-chip">task: '+esc(hit.taskId)+'</span>':'')+
5210
5057
  '</div>'+
@@ -5214,13 +5061,11 @@ function renderSharingMemorySearchResults(data,query){
5214
5061
  '<div class="result-section">'+
5215
5062
  '<div class="result-section-header"><div class="result-section-title">'+t('search.hubResults')+'</div><div class="result-section-sub">'+hubHits.length+' hit(s)</div></div>'+
5216
5063
  '<div class="search-hit-list">'+(hubHits.length?hubHits.map(function(hit,idx){
5217
- var hubAgentName='';if(hit.sourceAgent){var hap=(hit.sourceAgent||'').split(':');hubAgentName=hap.length>=3?hap[hap.length-1]:(hap.length>=2?hap[1]:hit.sourceAgent);}
5218
5064
  return '<div class="hub-hit-card">'+
5219
5065
  '<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
5220
5066
  '<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
5221
5067
  '<div class="hub-hit-meta">'+
5222
5068
  '<span class="meta-chip">owner: '+fmtOwner(hit)+'</span>'+
5223
- (hubAgentName?'<span class="meta-chip" style="background:rgba(20,184,166,.12);color:#14b8a6">'+esc(hubAgentName)+'</span>':'')+
5224
5069
  (hit.groupName?'<span class="meta-chip">group: '+esc(hit.groupName)+'</span>':'')+
5225
5070
  '<span class="meta-chip">visibility: '+esc(hit.visibility||'hub')+'</span>'+
5226
5071
  '</div>'+
@@ -5356,42 +5201,6 @@ function openHubSkillDetailFromCache(cacheKey,idx){
5356
5201
 
5357
5202
  function escAttr(s){return String(s||'').replace(/&/g,'&amp;').replace(/'/g,'&#39;').replace(/"/g,'&quot;').replace(/</g,'&lt;').replace(/>/g,'&gt;');}
5358
5203
 
5359
- function fmtAgentName(owner){
5360
- if(!owner||owner==='public') return '';
5361
- var s=String(owner);
5362
- if(s.startsWith('agent:')) s=s.slice(6);
5363
- return s;
5364
- }
5365
-
5366
- function fmtSessionDisplay(sid){
5367
- if(!sid) return '';
5368
- if(sid.startsWith('agent:')){
5369
- var parts=sid.split(':');
5370
- // agent:{agentId}:import → "📥 import"
5371
- if(parts.length===3 && parts[2]==='import') return '\\u{1F4E5} import';
5372
- // agent:{agentId}:session:{sessionId} → shortened sessionId
5373
- if(parts.length>=4 && parts[2]==='session'){
5374
- var sessId=parts.slice(3).join(':');
5375
- return sessId.length>12?sessId.slice(0,6)+'..'+sessId.slice(-4):sessId;
5376
- }
5377
- // agent:{agentId}:{other} → show from second part (e.g. "work:main")
5378
- return parts.slice(1).join(':');
5379
- }
5380
- // Legacy formats
5381
- if(sid.startsWith('openclaw-import-')) return '\\u{1F4E5} '+sid.slice(16);
5382
- if(sid.startsWith('openclaw-session-')){
5383
- var id=sid.slice(17);
5384
- return id.length>12?id.slice(0,6)+'..'+id.slice(-4):id;
5385
- }
5386
- if(sid.length>20) return sid.slice(0,8)+'..'+sid.slice(-6);
5387
- return sid;
5388
- }
5389
-
5390
- function isImportedSession(sid){
5391
- if(!sid) return false;
5392
- return sid.startsWith('openclaw-import-')||sid.startsWith('openclaw-session-')||/^agent:[^:]+:(import|session:)/.test(sid);
5393
- }
5394
-
5395
5204
  /* ─── Unified Sharing Scope Selector ─── */
5396
5205
 
5397
5206
  function getScopeLabel(scope){
@@ -5534,9 +5343,9 @@ function openTaskScopeModal(){
5534
5343
  var isTeamShared=!!(task.sharingVisibility||task.hubTaskId);
5535
5344
  var cs=isTeamShared?'team':isLocalShared?'local':'private';
5536
5345
  openScopeSelectorModal('task',task.id,cs,function(s){
5537
- if(s==='team'){task.sharingVisibility='public';task.hubTaskId=true;}
5538
- else if(s==='local'){task.sharingVisibility=null;task.hubTaskId=false;task.owner='public';}
5539
- else{task.sharingVisibility=null;task.hubTaskId=false;task.owner=task._origOwner||'agent:main';}
5346
+ if(s==='team'){task.sharingVisibility='public';task.hubTaskId=task.hubTaskId||'shared';}
5347
+ else if(s==='local'){task.sharingVisibility=null;task.owner='public';}
5348
+ else{task.sharingVisibility=null;task.owner=task._origOwner||'agent:main';}
5540
5349
  renderTaskShareActions(task);
5541
5350
  updateTaskCardBadge(task.id,s);
5542
5351
  });
@@ -5553,7 +5362,7 @@ async function shareCurrentTask(){
5553
5362
  try{
5554
5363
  const r=await fetch('/api/sharing/tasks/share',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({taskId:currentTaskDetail.id,visibility:visibility})});
5555
5364
  const d=await r.json();
5556
- if(d.ok||d.shared){toast(t('toast.taskShared'),'success');currentTaskDetail.sharingVisibility=visibility;currentTaskDetail.hubTaskId=true;renderTaskShareActions(currentTaskDetail);} else {toast(d.error||t('toast.taskShareFail'),'error');}
5365
+ if(d.ok||d.shared){toast(t('toast.taskShared'),'success');currentTaskDetail.sharingVisibility=visibility;renderTaskShareActions(currentTaskDetail);} else {toast(d.error||t('toast.taskShareFail'),'error');}
5557
5366
  }catch(e){toast(t('toast.taskShareFail')+': '+e.message,'error');}
5558
5367
  }
5559
5368
 
@@ -5562,7 +5371,7 @@ async function unshareCurrentTask(){
5562
5371
  try{
5563
5372
  const r=await fetch('/api/sharing/tasks/unshare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({taskId:currentTaskDetail.id})});
5564
5373
  const d=await r.json();
5565
- if(d.ok||d.unshared){toast(t('toast.taskUnshared'),'success');currentTaskDetail.sharingVisibility=null;currentTaskDetail.hubTaskId=false;renderTaskShareActions(currentTaskDetail);} else {toast(d.error||t('toast.taskUnshareFail'),'error');}
5374
+ if(d.ok||d.unshared){toast(t('toast.taskUnshared'),'success');currentTaskDetail.sharingVisibility=null;renderTaskShareActions(currentTaskDetail);} else {toast(d.error||t('toast.taskUnshareFail'),'error');}
5566
5375
  }catch(e){toast(t('toast.taskUnshareFail')+': '+e.message,'error');}
5567
5376
  }
5568
5377
 
@@ -5650,7 +5459,6 @@ function localMemoryErrorMessage(err){
5650
5459
 
5651
5460
  function debounceSkillSearch(){
5652
5461
  clearTimeout(skillSearchTimer);
5653
- skillsPage=0;
5654
5462
  skillSearchTimer=setTimeout(function(){loadSkills();},300);
5655
5463
  }
5656
5464
 
@@ -5764,13 +5572,6 @@ function recallOriginBadge(origin){
5764
5572
  if(origin==='hub-remote') return '<span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>';
5765
5573
  return '';
5766
5574
  }
5767
- function agentBadge(owner){
5768
- if(!owner) return '';
5769
- var parts=(owner||'').split(':');
5770
- var name=parts.length>=3?parts[parts.length-1]:(parts.length>=2?parts[1]:owner);
5771
- if(!name) return '';
5772
- return '<span class="recall-origin agent-tag">\u{1F916} '+escapeHtml(name)+'</span>';
5773
- }
5774
5575
 
5775
5576
  function buildLogSummary(lg){
5776
5577
  let inputObj=null;
@@ -5797,9 +5598,8 @@ function buildLogSummary(lg){
5797
5598
  var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
5798
5599
  var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
5799
5600
  var oBadge=recallOriginBadge(c.origin);
5800
- var aBadge2=agentBadge(c.owner);
5801
5601
  html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5802
- 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+aBadge2+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
5602
+ 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>';
5803
5603
  html+='<div class="recall-summary-full">'+fullText+'</div>';
5804
5604
  html+='</div>';
5805
5605
  });
@@ -5814,9 +5614,8 @@ function buildLogSummary(lg){
5814
5614
  var shortText=escapeHtml(c.summary||c.original_excerpt||'');
5815
5615
  var fullText=escapeHtml(c.original_excerpt||c.summary||'');
5816
5616
  var owner=c.ownerName?' ['+escapeHtml(c.ownerName)+']':'';
5817
- var haBadge2=agentBadge(c.sourceAgent||'');
5818
5617
  html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5819
- 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+haBadge2+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
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>';
5820
5619
  html+='<div class="recall-summary-full">'+fullText+'</div>';
5821
5620
  html+='</div>';
5822
5621
  });
@@ -5832,9 +5631,8 @@ function buildLogSummary(lg){
5832
5631
  var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
5833
5632
  var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
5834
5633
  var oBadge=recallOriginBadge(f.origin);
5835
- var faBadge2=agentBadge(f.owner);
5836
5634
  html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5837
- 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+faBadge2+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
5635
+ 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>';
5838
5636
  html+='<div class="recall-summary-full">'+fullText+'</div>';
5839
5637
  html+='</div>';
5840
5638
  });
@@ -5900,9 +5698,8 @@ function buildRecallDetailHtml(rd){
5900
5698
  var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
5901
5699
  var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
5902
5700
  var oBadge=recallOriginBadge(c.origin);
5903
- var aBadge=agentBadge(c.owner);
5904
5701
  html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5905
- 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+aBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
5702
+ 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>';
5906
5703
  html+='<div class="recall-summary-full">'+fullText+'</div>';
5907
5704
  html+='</div>';
5908
5705
  });
@@ -5917,9 +5714,8 @@ function buildRecallDetailHtml(rd){
5917
5714
  var shortText=escapeHtml(c.summary||c.original_excerpt||'');
5918
5715
  var fullText=escapeHtml(c.original_excerpt||c.summary||'');
5919
5716
  var owner=c.ownerName?' ['+escapeHtml(c.ownerName)+']':'';
5920
- var haBadge=agentBadge(c.sourceAgent||'');
5921
5717
  html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5922
- 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+haBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
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>';
5923
5719
  html+='<div class="recall-summary-full">'+fullText+'</div>';
5924
5720
  html+='</div>';
5925
5721
  });
@@ -5935,9 +5731,8 @@ function buildRecallDetailHtml(rd){
5935
5731
  var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
5936
5732
  var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
5937
5733
  var oBadge=recallOriginBadge(f.origin);
5938
- var faBadge=agentBadge(f.owner);
5939
5734
  html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5940
- 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+faBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
5735
+ 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>';
5941
5736
  html+='<div class="recall-summary-full">'+fullText+'</div>';
5942
5737
  html+='</div>';
5943
5738
  });
@@ -6032,11 +5827,6 @@ function escapeHtml(s){
6032
5827
  return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
6033
5828
  }
6034
5829
 
6035
- function setPageSizeVisible(selectId,visible){
6036
- var sel=document.getElementById(selectId);
6037
- if(sel&&sel.parentElement){ sel.parentElement.style.display=visible?'inline-flex':'none'; }
6038
- }
6039
-
6040
5830
  function setMetricsDays(d){
6041
5831
  metricsDays=d;
6042
5832
  document.querySelectorAll('.metrics-toolbar .range-btn').forEach(btn=>btn.classList.toggle('active',Number(btn.dataset.days)===d));
@@ -6056,179 +5846,40 @@ async function loadMetrics(){
6056
5846
  }catch(e){console.error('loadMetrics',e)}
6057
5847
  }
6058
5848
 
6059
- function _st(id,v){var e=document.getElementById(id);if(e)e.textContent=v;}
6060
5849
  function formatNum(n){return n>=1e6?(n/1e6).toFixed(1)+'M':n>=1e3?(n/1e3).toFixed(1)+'k':String(n);}
6061
5850
  function dateLoc(){return curLang==='zh'?'zh-CN':'en-US';}
6062
5851
 
6063
5852
  /* ─── Tasks View Logic ─── */
6064
5853
  let tasksStatusFilter='';
6065
5854
  let tasksPage=0;
6066
- let tasksPageSize=20;
5855
+ const TASKS_PER_PAGE=20;
6067
5856
 
6068
5857
  function setTaskStatusFilter(btn,status){
6069
- document.querySelectorAll('.tasks-view .filter-bar .filter-chip[data-task-status]').forEach(c=>c.classList.remove('active'));
5858
+ document.querySelectorAll('.tasks-filters .filter-chip').forEach(c=>c.classList.remove('active'));
6070
5859
  btn.classList.add('active');
6071
5860
  tasksStatusFilter=status;
6072
5861
  tasksPage=0;
6073
5862
  loadTasks();
6074
5863
  }
6075
5864
 
6076
- function updateTaskSelectionToolbar(){
6077
- var toolbar=document.getElementById('taskSelectionToolbar');
6078
- var selectAllBtn=document.getElementById('taskSelectAllBtn');
6079
- var bulkDeleteBtn=document.getElementById('taskBulkDeleteBtn');
6080
- var isHub=taskSearchScope==='hub';
6081
- var total=document.querySelectorAll('#tasksList .task-select-check').length;
6082
- var selected=selectedTaskIds.size;
6083
- if(toolbar) toolbar.style.display=isHub?'none':'flex';
6084
- if(selectAllBtn){
6085
- selectAllBtn.textContent=t(selected>0&&selected===total&&total>0?'skills.unselectAll':'skills.selectAll');
6086
- selectAllBtn.disabled=total===0;
6087
- selectAllBtn.style.display=total===0?'none':'';
6088
- }
6089
- if(bulkDeleteBtn){
6090
- var base=t('task.deleteSelected');
6091
- bulkDeleteBtn.style.display=selected>0?'':'none';
6092
- bulkDeleteBtn.textContent=selected>0?(base+' ('+selected+')'):base;
6093
- }
6094
- }
6095
-
6096
- function toggleTaskSelection(taskId,checked){
6097
- if(checked) selectedTaskIds.add(taskId);
6098
- else selectedTaskIds.delete(taskId);
6099
- updateTaskSelectionToolbar();
6100
- }
6101
-
6102
- function toggleSelectAllTasks(){
6103
- var total=currentTaskIds.length;
6104
- if(total===0) return;
6105
- if(selectedTaskIds.size===total){
6106
- selectedTaskIds.clear();
6107
- }else{
6108
- selectedTaskIds=new Set(currentTaskIds);
6109
- }
6110
- var checks=document.querySelectorAll('#tasksList .task-select-check');
6111
- checks.forEach(function(cb){cb.checked=selectedTaskIds.has(cb.value);});
6112
- updateTaskSelectionToolbar();
6113
- }
6114
-
6115
- async function deleteSelectedTasks(){
6116
- var ids=Array.from(selectedTaskIds);
6117
- if(ids.length===0) return;
6118
- var msg=t('task.delete.selected.confirm').replace('{count}',String(ids.length));
6119
- if(!(await confirmModal(msg,{danger:true}))) return;
6120
- var ok=0;
6121
- var fail=0;
6122
- for(var i=0;i<ids.length;i++){
6123
- try{
6124
- var r=await fetch('/api/task/'+ids[i],{method:'DELETE'});
6125
- var d=await r.json();
6126
- if(!r.ok) throw new Error(d.error||'unknown');
6127
- ok++;
6128
- }catch(e){
6129
- fail++;
6130
- }
6131
- }
6132
- selectedTaskIds.clear();
6133
- updateTaskSelectionToolbar();
6134
- loadTasks();
6135
- if(fail>0) toast(t('task.delete.partial').replace('{ok}',String(ok)).replace('{fail}',String(fail)),'warn');
6136
- else toast(t('task.delete.success').replace('{count}',String(ok)),'success');
6137
- }
6138
-
6139
- var taskSearchQuery='';
6140
- var _taskSearchTimer=null;
6141
- function debounceTaskSearch(){
6142
- clearTimeout(_taskSearchTimer);
6143
- _taskSearchTimer=setTimeout(function(){
6144
- taskSearchQuery=(document.getElementById('taskSearchInput')||{}).value||'';
6145
- tasksPage=0;
6146
- loadTasks();
6147
- },350);
6148
- }
6149
-
6150
- function renderTaskCards(tasks,container){
6151
- currentTaskIds=tasks.map(function(task){return task.id;});
6152
- selectedTaskIds=new Set(Array.from(selectedTaskIds).filter(function(id){return currentTaskIds.includes(id);}));
6153
- if(!tasks||tasks.length===0){
6154
- container.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px" data-i18n="tasks.empty">'+t('tasks.empty')+'</div>';
6155
- updateTaskSelectionToolbar();
6156
- return;
6157
- }
6158
- container.innerHTML=tasks.map(function(task){
6159
- var timeStr=formatTime(task.startedAt);
6160
- var durationStr=task.endedAt?formatDuration(task.endedAt-task.startedAt):'';
6161
- var taskIsLocalShared=task.owner==='public';
6162
- var taskIsTeamShared=!!task.sharingVisibility;
6163
- var taskScope=taskIsTeamShared?'team':taskIsLocalShared?'local':'private';
6164
- var selectedAttr=selectedTaskIds.has(task.id)?' checked':'';
6165
- return '<div class="task-card status-'+task.status+'" onclick="openTaskDetail(\\''+task.id+'\\')">'+
6166
- '<div class="task-card-top">'+
6167
- '<div class="task-card-title"><label class="item-select-box" onclick="event.stopPropagation()"><input class="task-select-check" type="checkbox" value="'+escAttr(task.id)+'"'+selectedAttr+' onchange="event.stopPropagation();toggleTaskSelection(&quot;'+escAttr(task.id)+'&quot;,this.checked)"></label>'+esc(task.title)+'</div>'+
6168
- '<div class="task-card-badges">'+renderScopeBadge(taskScope)+'<span class="task-status-badge '+task.status+'">'+t('tasks.status.'+task.status)+'</span></div>'+
6169
- '</div>'+
6170
- (task.summary?'<div class="task-card-summary'+(task.status==='skipped'?' skipped-reason':'')+'">'+esc(task.summary)+'</div>':'')+
6171
- '<div class="task-card-bottom">'+
6172
- '<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>'+
6173
- (durationStr?'<span class="tag"><span class="icon">\\u23F1</span> '+durationStr+'</span>':'')+
6174
- '<span class="tag"><span class="icon">\\u{1F4DD}</span> '+(task.chunkCount||0)+' '+t('tasks.chunks.label')+'</span>'+
6175
- '<span class="tag"><span class="icon">\\u{1F4C2}</span> '+(task.sessionKey||'')+'</span>'+
6176
- '</div>'+
6177
- '<div class="card-actions" onclick="event.stopPropagation()">'+
6178
- '<button class="btn btn-sm btn-ghost" onclick="openTaskDetail(\\''+task.id+'\\')">'+t('card.expand')+'</button>'+
6179
- (task.status==='completed'&&(!task.skillStatus||task.skillStatus==='not_generated'||task.skillStatus==='skipped')?'<button class="btn btn-sm btn-ghost" onclick="retrySkillGen(\\''+task.id+'\\')">'+t('task.retrySkill.short')+'</button>':'')+
6180
- (task.status==='completed'
6181
- ?'<button class="btn btn-sm btn-ghost" onclick="openTaskScopeModalFromList(\\''+task.id+'\\',\\''+taskScope+'\\')">\\u270F '+t('share.shareBtn')+'</button>'
6182
- :'<button class="btn btn-sm btn-ghost" style="opacity:0.45;cursor:not-allowed" onclick="toast(t(\\x27share.scope.taskNotCompleted\\x27),\\x27warn\\x27)">\\u270F '+t('share.shareBtn')+'</button>')+
6183
- '<button class="btn btn-sm btn-ghost" style="color:var(--accent)" onclick="deleteTask(\\''+task.id+'\\')">'+t('task.delete')+'</button>'+
6184
- '</div>'+
6185
- '</div>';
6186
- }).join('');
6187
- updateTaskSelectionToolbar();
6188
- }
6189
-
6190
5865
  async function loadTasks(silent){
6191
5866
  const scope=document.getElementById('taskSearchScope')?document.getElementById('taskSearchScope').value:taskSearchScope;
6192
- taskSearchScope=scope||'allLocal';
5867
+ taskSearchScope=scope||'local';
6193
5868
  if(taskSearchScope==='hub'){ return loadHubTasks(); }
6194
5869
  const list=document.getElementById('tasksList');
6195
5870
  if(!silent) list.innerHTML='<div class="spinner"></div>';
6196
5871
  try{
6197
- var ownerSel=document.getElementById('taskFilterOwner')||document.getElementById('filterOwner');
6198
- var ownerVal=ownerSel?ownerSel.value:'';
6199
-
6200
- if(taskSearchQuery&&taskSearchQuery.trim()){
6201
- var sp=new URLSearchParams({q:taskSearchQuery.trim(),limit:String(tasksPageSize)});
6202
- if(ownerVal) sp.set('owner',ownerVal);
6203
- var sr=await fetch('/api/task-search?'+sp).then(function(r){return r.json()});
6204
- var tasks=sr.tasks||[];
6205
- document.getElementById('taskSearchMeta').style.display='block';
6206
- document.getElementById('taskSearchMeta').textContent=t('tasks.search.meta').replace('{0}',tasks.length);
6207
- _st('tasksTotalCount',tasks.length);
6208
- _st('tasksActiveCount',tasks.filter(function(tk){return tk.status==='active'}).length);
6209
- _st('tasksCompletedCount',tasks.filter(function(tk){return tk.status==='completed'}).length);
6210
- _st('tasksSkippedCount',tasks.filter(function(tk){return tk.status==='skipped'}).length);
6211
- if(tasksStatusFilter) tasks=tasks.filter(function(tk){return tk.status===tasksStatusFilter});
6212
- renderTaskCards(tasks,list);
6213
- document.getElementById('tasksPagination').innerHTML='';
6214
- return;
6215
- }
6216
- document.getElementById('taskSearchMeta').style.display='none';
6217
-
6218
- const params=new URLSearchParams({limit:String(tasksPageSize),offset:String(tasksPage*tasksPageSize)});
5872
+ const params=new URLSearchParams({limit:String(TASKS_PER_PAGE),offset:String(tasksPage*TASKS_PER_PAGE)});
6219
5873
  if(tasksStatusFilter) params.set('status',tasksStatusFilter);
6220
- if(activeSession) params.set('session',activeSession);
6221
- if(ownerVal) params.set('owner',ownerVal);
5874
+ if(taskSearchScope==='local') params.set('owner','agent:main');
6222
5875
  var baseP=new URLSearchParams();
6223
- if(activeSession) baseP.set('session',activeSession);
6224
- if(ownerVal) baseP.set('owner',ownerVal);
6225
- var baseQuery=baseP.toString();
5876
+ if(taskSearchScope==='local') baseP.set('owner','agent:main');
6226
5877
  const [data,allD,activeD,compD,skipD]=await Promise.all([
6227
5878
  fetch('/api/tasks?'+params).then(r=>r.json()),
6228
- fetch('/api/tasks?limit=1&offset=0'+(baseQuery?'&'+baseQuery:'')).then(r=>r.json()),
6229
- fetch('/api/tasks?status=active&limit=1&offset=0'+(baseQuery?'&'+baseQuery:'')).then(r=>r.json()),
6230
- fetch('/api/tasks?status=completed&limit=1&offset=0'+(baseQuery?'&'+baseQuery:'')).then(r=>r.json()),
6231
- fetch('/api/tasks?status=skipped&limit=1&offset=0'+(baseQuery?'&'+baseQuery:'')) .then(r=>r.json())
5879
+ fetch('/api/tasks?limit=1&offset=0&'+baseP).then(r=>r.json()),
5880
+ fetch('/api/tasks?status=active&limit=1&offset=0&'+baseP).then(r=>r.json()),
5881
+ fetch('/api/tasks?status=completed&limit=1&offset=0&'+baseP).then(r=>r.json()),
5882
+ fetch('/api/tasks?status=skipped&limit=1&offset=0&'+baseP).then(r=>r.json())
6232
5883
  ]);
6233
5884
  if(silent){
6234
5885
  var fp=JSON.stringify((data.tasks||[]).map(function(tk){return tk.id+'|'+tk.status+'|'+(tk.updatedAt||tk.startedAt)}));
@@ -6238,24 +5889,50 @@ async function loadTasks(silent){
6238
5889
  }else{
6239
5890
  _lastTasksFingerprint='';
6240
5891
  }
6241
- _st('tasksTotalCount',formatNum(allD.total));
6242
- _st('tasksActiveCount',formatNum(activeD.total));
6243
- _st('tasksCompletedCount',formatNum(compD.total));
6244
- _st('tasksSkippedCount',formatNum(skipD.total));
6245
-
6246
- renderTaskCards(data.tasks||[],list);
5892
+ document.getElementById('tasksTotalCount').textContent=formatNum(allD.total);
5893
+ document.getElementById('tasksActiveCount').textContent=formatNum(activeD.total);
5894
+ document.getElementById('tasksCompletedCount').textContent=formatNum(compD.total);
5895
+ document.getElementById('tasksSkippedCount').textContent=formatNum(skipD.total);
6247
5896
 
6248
5897
  if(!data.tasks||data.tasks.length===0){
5898
+ list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px" data-i18n="tasks.empty">'+t('tasks.empty')+'</div>';
6249
5899
  document.getElementById('tasksPagination').innerHTML='';
6250
- } else {
6251
- renderTasksPagination(data.total);
5900
+ return;
6252
5901
  }
5902
+
5903
+ list.innerHTML=data.tasks.map(task=>{
5904
+ const timeStr=formatTime(task.startedAt);
5905
+ const endStr=task.endedAt?formatTime(task.endedAt):'';
5906
+ const durationStr=task.endedAt?formatDuration(task.endedAt-task.startedAt):'';
5907
+ var taskIsLocalShared=task.owner==='public';
5908
+ var taskIsTeamShared=!!task.sharingVisibility;
5909
+ var taskScope=taskIsTeamShared?'team':taskIsLocalShared?'local':'private';
5910
+ return '<div class="task-card status-'+task.status+'" onclick="openTaskDetail(\\''+task.id+'\\')">'+
5911
+ '<div class="task-card-top">'+
5912
+ '<div class="task-card-title">'+esc(task.title)+'</div>'+
5913
+ '<div class="task-card-badges">'+renderScopeBadge(taskScope)+'<span class="task-status-badge '+task.status+'">'+t('tasks.status.'+task.status)+'</span></div>'+
5914
+ '</div>'+
5915
+ (task.summary?'<div class="task-card-summary'+(task.status==='skipped'?' skipped-reason':'')+'">'+esc(task.summary)+'</div>':'')+
5916
+ '<div class="task-card-bottom">'+
5917
+ '<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>'+
5918
+ (durationStr?'<span class="tag"><span class="icon">\\u23F1</span> '+durationStr+'</span>':'')+
5919
+ '<span class="tag"><span class="icon">\\u{1F4DD}</span> '+task.chunkCount+' '+t('tasks.chunks.label')+'</span>'+
5920
+ '<span class="tag"><span class="icon">\\u{1F4C2}</span> '+(task.sessionKey||'').slice(0,12)+'</span>'+
5921
+ '</div>'+
5922
+ '<div class="card-actions" onclick="event.stopPropagation()">'+
5923
+ '<button class="btn btn-sm btn-ghost" onclick="openTaskDetail(\\''+task.id+'\\')">'+t('card.expand')+'</button>'+
5924
+ (task.status==='completed'&&(!task.skillStatus||task.skillStatus==='not_generated'||task.skillStatus==='skipped')?'<button class="btn btn-sm btn-ghost" onclick="retrySkillGen(\\''+task.id+'\\')">'+t('task.retrySkill.short')+'</button>':'')+
5925
+ (task.status==='completed'
5926
+ ?'<button class="btn btn-sm btn-ghost" onclick="openTaskScopeModalFromList(\\''+task.id+'\\',\\''+taskScope+'\\')">\\u270F '+t('share.shareBtn')+'</button>'
5927
+ :'<button class="btn btn-sm btn-ghost" style="opacity:0.45;cursor:not-allowed" onclick="toast(t(\\x27share.scope.taskNotCompleted\\x27),\\x27warn\\x27)">\\u270F '+t('share.shareBtn')+'</button>')+
5928
+ '<button class="btn btn-sm btn-ghost" style="color:var(--accent)" onclick="deleteTask(\\''+task.id+'\\')">'+t('task.delete')+'</button>'+
5929
+ '</div>'+
5930
+ '</div>';
5931
+ }).join('');
5932
+
5933
+ renderTasksPagination(data.total);
6253
5934
  }catch(e){
6254
5935
  console.error('loadTasks error:',e);
6255
- currentTaskIds=[];
6256
- selectedTaskIds.clear();
6257
- setPageSizeVisible('tasksPageSize',false);
6258
- updateTaskSelectionToolbar();
6259
5936
  list.innerHTML='<div style="text-align:center;padding:24px;color:var(--rose)">Failed to load tasks: '+String(e)+'</div>';
6260
5937
  }
6261
5938
  }
@@ -6276,7 +5953,7 @@ function updateTaskCardBadge(taskId,newScope){
6276
5953
 
6277
5954
  function renderTasksPagination(total){
6278
5955
  const el=document.getElementById('tasksPagination');
6279
- const pages=Math.ceil(total/tasksPageSize);
5956
+ const pages=Math.ceil(total/TASKS_PER_PAGE);
6280
5957
  if(pages<=1){el.innerHTML='';return;}
6281
5958
  let html='<button class="pg-btn'+(tasksPage===0?' disabled':'')+'" onclick="tasksPage=Math.max(0,tasksPage-1);loadTasks()">\\u2190</button>';
6282
5959
  const start=Math.max(0,tasksPage-2),end=Math.min(pages,tasksPage+3);
@@ -6464,8 +6141,6 @@ async function deleteTask(taskId){
6464
6141
  const r=await fetch('/api/task/'+taskId,{method:'DELETE'});
6465
6142
  const d=await r.json();
6466
6143
  if(!r.ok) throw new Error(d.error||'unknown');
6467
- selectedTaskIds.delete(taskId);
6468
- updateTaskSelectionToolbar();
6469
6144
  closeTaskDetail();
6470
6145
  document.getElementById('taskDetailOverlay').classList.remove('show');
6471
6146
  loadTasks();
@@ -6475,55 +6150,14 @@ async function deleteTask(taskId){
6475
6150
 
6476
6151
  /* ─── Skills View Logic ─── */
6477
6152
  let skillsStatusFilter='';
6478
- let skillsPage=0;
6479
- let skillsPageSize=20;
6480
- let selectedSkillIds=new Set();
6481
- let currentLocalSkills=[];
6482
- let skillsFilterSignature='';
6483
6153
 
6484
6154
  function setSkillStatusFilter(btn,status){
6485
- document.querySelectorAll('.skills-view .filter-bar .filter-chip[data-skill-status]').forEach(c=>c.classList.remove('active'));
6155
+ document.querySelectorAll('.skills-view .tasks-filters .filter-chip').forEach(c=>c.classList.remove('active'));
6486
6156
  btn.classList.add('active');
6487
6157
  skillsStatusFilter=status;
6488
- skillsPage=0;
6489
6158
  loadSkills();
6490
6159
  }
6491
6160
 
6492
- function updateSkillSelectionToolbar(){
6493
- var selectAllBtn=document.getElementById('skillSelectAllBtn');
6494
- var bulkDeleteBtn=document.getElementById('skillBulkDeleteBtn');
6495
- var total=document.querySelectorAll('#skillsList .skill-select-check').length;
6496
- var selected=selectedSkillIds.size;
6497
- if(selectAllBtn){
6498
- selectAllBtn.textContent=t(selected>0&&selected===total&&total>0?'skills.unselectAll':'skills.selectAll');
6499
- selectAllBtn.style.display=total===0?'none':'';
6500
- }
6501
- if(bulkDeleteBtn){
6502
- var base=t('skills.deleteSelected');
6503
- bulkDeleteBtn.style.display=selected>0?'':'none';
6504
- bulkDeleteBtn.textContent=selected>0?(base+' ('+selected+')'):base;
6505
- }
6506
- }
6507
-
6508
- function toggleSkillSelection(skillId,checked){
6509
- if(checked) selectedSkillIds.add(skillId);
6510
- else selectedSkillIds.delete(skillId);
6511
- updateSkillSelectionToolbar();
6512
- }
6513
-
6514
- function toggleSelectAllSkills(){
6515
- var total=currentLocalSkills.length;
6516
- if(total===0) return;
6517
- if(selectedSkillIds.size===total){
6518
- selectedSkillIds.clear();
6519
- }else{
6520
- selectedSkillIds=new Set(currentLocalSkills.map(function(s){return s.id;}));
6521
- }
6522
- var checks=document.querySelectorAll('#skillsList .skill-select-check');
6523
- checks.forEach(function(cb){cb.checked=selectedSkillIds.has(cb.value);});
6524
- updateSkillSelectionToolbar();
6525
- }
6526
-
6527
6161
  function updateSkillCardBadge(skillId,newScope){
6528
6162
  var cards=document.querySelectorAll('.skill-card');
6529
6163
  for(var i=0;i<cards.length;i++){
@@ -6540,28 +6174,13 @@ function updateSkillCardBadge(skillId,newScope){
6540
6174
  }
6541
6175
  }
6542
6176
 
6543
- function renderSkillsPagination(total){
6544
- const el=document.getElementById('skillsPagination');
6545
- if(!el) return;
6546
- const pages=Math.ceil(total/skillsPageSize);
6547
- if(pages<=1){el.innerHTML='';return;}
6548
- let html='<button class="pg-btn'+(skillsPage===0?' disabled':'')+'" onclick="skillsPage=Math.max(0,skillsPage-1);loadSkills()">\\u2190</button>';
6549
- const start=Math.max(0,skillsPage-2),end=Math.min(pages,skillsPage+3);
6550
- for(let i=start;i<end;i++){
6551
- html+='<button class="pg-btn'+(i===skillsPage?' active':'')+'" onclick="skillsPage='+i+';loadSkills()">'+(i+1)+'</button>';
6552
- }
6553
- html+='<button class="pg-btn'+(skillsPage>=pages-1?' disabled':'')+'" onclick="skillsPage=Math.min('+(pages-1)+',skillsPage+1);loadSkills()">\\u2192</button>';
6554
- html+='<span class="pg-info">'+total+' '+t('pagination.total')+'</span>';
6555
- el.innerHTML=html;
6556
- }
6557
-
6558
6177
  async function loadSkills(silent){
6559
6178
  const list=document.getElementById('skillsList');
6560
6179
  const hubList=document.getElementById('hubSkillsList');
6561
6180
  if(!silent) list.innerHTML='<div class="spinner"></div>';
6562
6181
  var hubSection=document.getElementById('hubSkillsSection');
6563
6182
  if(hubList){
6564
- if(skillSearchScope==='allLocal'){
6183
+ if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
6565
6184
  if(hubSection) hubSection.style.display='none';
6566
6185
  }else{
6567
6186
  if(hubSection) hubSection.style.display='block';
@@ -6571,37 +6190,24 @@ async function loadSkills(silent){
6571
6190
 
6572
6191
  const query=(document.getElementById('skillSearchInput')?.value||'').trim();
6573
6192
  const scope=document.getElementById('skillSearchScope') ? document.getElementById('skillSearchScope').value : skillSearchScope;
6574
- skillSearchScope=scope||'allLocal';
6193
+ skillSearchScope=scope||'local';
6575
6194
 
6576
6195
  try{
6577
6196
  const params=new URLSearchParams();
6578
6197
  if(skillsStatusFilter) params.set('status',skillsStatusFilter);
6579
- if(activeSession) params.set('session',activeSession);
6580
- var skillOwnerSel=document.getElementById('skillFilterOwner')||document.getElementById('filterOwner');
6581
- var skillOwnerVal=skillOwnerSel?skillOwnerSel.value:'';
6582
- if(skillOwnerVal) params.set('owner',skillOwnerVal);
6583
6198
  const visFilter=document.getElementById('skillVisibilityFilter')?.value;
6584
6199
  if(visFilter) params.set('visibility',visFilter);
6585
- const filterSignature=[query,skillSearchScope,skillsStatusFilter,visFilter||'',skillOwnerVal].join('|');
6586
- if(!silent&&filterSignature!==skillsFilterSignature){
6587
- skillsPage=0;
6588
- }
6589
- skillsFilterSignature=filterSignature;
6590
6200
 
6591
6201
  const localRes=await fetch('/api/skills?'+params.toString());
6592
6202
  const localData=await localRes.json();
6593
6203
  let localSkills=Array.isArray(localData.skills)?localData.skills:[];
6594
- currentLocalSkills=localSkills.slice();
6595
6204
  if(query){
6596
6205
  const q=query.toLowerCase();
6597
6206
  localSkills=localSkills.filter(skill=>{
6598
6207
  const haystack=[skill.name,skill.description,skill.tags].filter(Boolean).join(' ').toLowerCase();
6599
6208
  return haystack.includes(q);
6600
6209
  });
6601
- currentLocalSkills=localSkills.slice();
6602
6210
  }
6603
- var localIdSet=new Set(localSkills.map(function(s){return s.id;}));
6604
- selectedSkillIds=new Set(Array.from(selectedSkillIds).filter(function(id){return localIdSet.has(id);}));
6605
6211
  if(silent){
6606
6212
  var fp=JSON.stringify(localSkills.map(function(s){return s.id+'|'+s.status+'|'+s.version+'|'+(s.visibility||'')}));
6607
6213
  if(fp===_lastSkillsFingerprint) return;
@@ -6625,10 +6231,9 @@ async function loadSkills(silent){
6625
6231
  const skillIsLocalShared=skill.visibility==='public';
6626
6232
  const skillIsTeamShared=!!skill.sharingVisibility;
6627
6233
  const skillScope=skillIsTeamShared?'team':skillIsLocalShared?'local':'private';
6628
- const selectedAttr=selectedSkillIds.has(skill.id)?' checked':'';
6629
6234
  return '<div class="skill-card '+installedClass+' '+statusClass+'" onclick="openSkillDetail(&quot;'+escAttr(skill.id)+'&quot;)">'+
6630
6235
  '<div class="skill-card-top">'+
6631
- '<div class="skill-card-name"><label class="item-select-box" onclick="event.stopPropagation()"><input class="skill-select-check" type="checkbox" value="'+escAttr(skill.id)+'"'+selectedAttr+' onchange="event.stopPropagation();toggleSkillSelection(&quot;'+escAttr(skill.id)+'&quot;,this.checked)"></label>🧠 '+esc(skill.name)+'</div>'+
6236
+ '<div class="skill-card-name">🧠 '+esc(skill.name)+'</div>'+
6632
6237
  '<div class="skill-card-badges">'+
6633
6238
  qsBadge+
6634
6239
  '<span class="skill-badge version">v'+skill.version+'</span>'+
@@ -6644,40 +6249,25 @@ async function loadSkills(silent){
6644
6249
  (tags.length>0?'<div class="skill-card-tags">'+tags.map(tg=>'<span class="skill-tag">'+esc(tg)+'</span>').join('')+'</div>':'')+
6645
6250
  '<span class="card-actions-inline" onclick="event.stopPropagation()">'+
6646
6251
  '<button class="btn btn-sm btn-ghost" onclick="openSkillDetail(&quot;'+escAttr(skill.id)+'&quot;)">'+t('card.expand')+'</button>'+
6647
- '<button class="btn btn-sm btn-danger" onclick="deleteSkill(&quot;'+escAttr(skill.id)+'&quot;)">'+t('skill.delete')+'</button>'+
6648
6252
  (skill.status==='active'
6649
6253
  ?'<button class="btn btn-sm btn-ghost" onclick="openSkillScopeModalFromList(&quot;'+escAttr(skill.id)+'&quot;,&quot;'+skillScope+'&quot;)">\\u270F '+t('share.shareBtn')+'</button>'
6650
6254
  :'<button class="btn btn-sm btn-ghost" style="opacity:0.45;cursor:not-allowed" onclick="toast(t(\\x27share.scope.skillNotActive\\x27),\\x27warn\\x27)">\\u270F '+t('share.shareBtn')+'</button>')+
6651
- (skill.status==='active'
6652
- ?'<button class="btn btn-sm btn-ghost btn-warn" onclick="disableSkill(&quot;'+escAttr(skill.id)+'&quot;)">'+t('skills.action.disable')+'</button>'
6653
- :'')+
6654
- (skill.status==='archived'
6655
- ?'<button class="btn btn-sm btn-ghost btn-success" onclick="enableSkill(&quot;'+escAttr(skill.id)+'&quot;)">'+t('skills.action.enable')+'</button>'
6656
- :'')+
6657
- '<button class="btn btn-sm btn-ghost btn-danger" onclick="deleteSkill(&quot;'+escAttr(skill.id)+'&quot;)">'+t('skills.action.delete')+'</button>'+
6658
6255
  '</span>'+
6659
6256
  '</div>'+
6660
6257
  '</div>';
6661
6258
  }).join('');
6662
6259
  };
6663
6260
 
6664
- const totalLocalSkills=localSkills.length;
6665
- const localPages=Math.ceil(totalLocalSkills/skillsPageSize)||1;
6666
- if(skillsPage>=localPages) skillsPage=Math.max(0,localPages-1);
6667
- const startIndex=skillsPage*skillsPageSize;
6668
- const pageSkills=localSkills.slice(startIndex,startIndex+skillsPageSize);
6669
- list.innerHTML=renderLocalCards(pageSkills);
6670
- renderSkillsPagination(totalLocalSkills);
6671
- setPageSizeVisible('skillsPageSize',totalLocalSkills>0);
6672
- updateSkillSelectionToolbar();
6673
-
6674
- if(skillSearchScope==='allLocal'){
6261
+ list.innerHTML=renderLocalCards(localSkills);
6262
+
6263
+ if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
6675
6264
  if(hubSection) hubSection.style.display='none';
6676
- _st('skillsTotalCount',formatNum(localSkills.length));
6677
- _st('skillsActiveCount',formatNum(localSkills.filter(s=>s.status==='active').length));
6678
- _st('skillsDraftCount',formatNum(localSkills.filter(s=>s.status==='draft').length));
6679
- _st('skillsInstalledCount',formatNum(localSkills.filter(s=>s.installed).length));
6680
- _st('skillsPublicCount',formatNum(localSkills.filter(s=>s.visibility==='public').length));
6265
+ document.getElementById('skillSearchMeta').textContent=query?(t('skills.search.local')+' '+localSkills.length):'';
6266
+ document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
6267
+ document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
6268
+ document.getElementById('skillsDraftCount').textContent=formatNum(localSkills.filter(s=>s.status==='draft').length);
6269
+ document.getElementById('skillsInstalledCount').textContent=formatNum(localSkills.filter(s=>s.installed).length);
6270
+ document.getElementById('skillsPublicCount').textContent=formatNum(localSkills.filter(s=>s.visibility==='public').length);
6681
6271
  return;
6682
6272
  }
6683
6273
 
@@ -6685,11 +6275,12 @@ async function loadSkills(silent){
6685
6275
  if(hubSection) hubSection.style.display='block';
6686
6276
  var localIds=new Set(localSkills.map(function(s){return s.id;}));
6687
6277
  if(hubList){ loadHubSkills(hubList, localIds); }
6688
- _st('skillsTotalCount',formatNum(localSkills.length));
6689
- _st('skillsActiveCount',formatNum(localSkills.filter(s=>s.status==='active').length));
6690
- _st('skillsDraftCount',formatNum(localSkills.filter(s=>s.status==='draft').length));
6691
- _st('skillsInstalledCount',formatNum(localSkills.filter(s=>s.installed).length));
6692
- _st('skillsPublicCount',formatNum(localSkills.filter(s=>s.visibility==='public').length));
6278
+ document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localSkills.length;
6279
+ document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
6280
+ document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
6281
+ document.getElementById('skillsDraftCount').textContent=formatNum(localSkills.filter(s=>s.status==='draft').length);
6282
+ document.getElementById('skillsInstalledCount').textContent=formatNum(localSkills.filter(s=>s.installed).length);
6283
+ document.getElementById('skillsPublicCount').textContent=formatNum(localSkills.filter(s=>s.visibility==='public').length);
6693
6284
  return;
6694
6285
  }
6695
6286
 
@@ -6699,13 +6290,9 @@ async function loadSkills(silent){
6699
6290
  sharingParams.set('maxResults','20');
6700
6291
  const r=await fetch('/api/sharing/search/skills?'+sharingParams.toString());
6701
6292
  const data=await r.json();
6702
- const localSkillIdSet=new Set(currentLocalSkills.map(function(skill){return skill.id;}));
6703
- const localHitsRaw=(data.local&&Array.isArray(data.local.hits))?data.local.hits:[];
6704
- const localHits=localHitsRaw.filter(function(skill){return localSkillIdSet.has(skill.skillId);});
6293
+ const localHits=(data.local&&Array.isArray(data.local.hits))?data.local.hits:[];
6705
6294
  const hubHits=(data.hub&&Array.isArray(data.hub.hits))?data.hub.hits:[];
6706
6295
 
6707
- const sp=document.getElementById('skillsPagination');
6708
- if(sp) sp.innerHTML='';
6709
6296
  list.innerHTML=localHits.length?localHits.map(function(skill){
6710
6297
  return '<div class="hub-skill-card" onclick="openSkillDetail(&quot;'+escAttr(skill.skillId)+'&quot;)">'+
6711
6298
  '<div class="summary">'+esc(skill.name)+'</div>'+
@@ -6731,18 +6318,14 @@ async function loadSkills(silent){
6731
6318
  }).join(''):'';
6732
6319
  }
6733
6320
 
6734
- _st('skillsTotalCount',formatNum(localHits.length+hubHits.length));
6735
- _st('skillsActiveCount',formatNum(localHits.length));
6736
- _st('skillsDraftCount','0');
6737
- _st('skillsInstalledCount','-');
6738
- _st('skillsPublicCount',formatNum(hubHits.filter(function(s){return s.visibility==='public';}).length));
6739
- setPageSizeVisible('skillsPageSize',(localHits.length+hubHits.length)>0);
6740
- updateSkillSelectionToolbar();
6321
+ document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localHits.length+(hubHits.length?' · '+t('scope.hub')+' '+hubHits.length:'');
6322
+ document.getElementById('skillsTotalCount').textContent=formatNum(localHits.length+hubHits.length);
6323
+ document.getElementById('skillsActiveCount').textContent=formatNum(localHits.length);
6324
+ document.getElementById('skillsDraftCount').textContent='0';
6325
+ document.getElementById('skillsInstalledCount').textContent='-';
6326
+ document.getElementById('skillsPublicCount').textContent=formatNum(hubHits.filter(function(s){return s.visibility==='public';}).length);
6741
6327
  }catch(e){
6742
6328
  list.innerHTML='<div style="text-align:center;padding:24px;color:var(--rose)">'+t('skills.load.error')+': '+esc(String(e))+'</div>';
6743
- const sp=document.getElementById('skillsPagination');
6744
- if(sp) sp.innerHTML='';
6745
- setPageSizeVisible('skillsPageSize',false);
6746
6329
  if(hubList){
6747
6330
  hubList.innerHTML='<div style="text-align:center;padding:24px;color:var(--rose)">'+t('skills.load.error')+'</div>';
6748
6331
  }
@@ -6752,28 +6335,19 @@ async function loadSkills(silent){
6752
6335
  async function loadHubTasks(){
6753
6336
  var list=document.getElementById('tasksList');
6754
6337
  if(!list) return;
6755
- currentTaskIds=[];
6756
- selectedTaskIds.clear();
6757
- updateTaskSelectionToolbar();
6758
6338
  list.innerHTML='<div class="spinner"></div>';
6759
6339
  try{
6760
- var r=await fetch('/api/sharing/tasks/list?limit='+tasksPageSize);
6340
+ var r=await fetch('/api/sharing/tasks/list?limit=40');
6761
6341
  var d=await r.json();
6762
6342
  var tasks=Array.isArray(d.tasks)?d.tasks:[];
6763
- if(activeSession){
6764
- tasks=tasks.filter(function(task){
6765
- return (task.sessionKey||task.session_key||'')===activeSession;
6766
- });
6767
- }
6768
6343
  hubTasksCache=tasks;
6769
- _st('tasksTotalCount',formatNum(tasks.length));
6770
- _st('tasksActiveCount','-');
6771
- _st('tasksCompletedCount','-');
6772
- _st('tasksSkippedCount','-');
6344
+ document.getElementById('tasksTotalCount').textContent=formatNum(tasks.length);
6345
+ document.getElementById('tasksActiveCount').textContent='-';
6346
+ document.getElementById('tasksCompletedCount').textContent='-';
6347
+ document.getElementById('tasksSkippedCount').textContent='-';
6773
6348
  if(!tasks.length){
6774
6349
  list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('tasks.empty')+'</div>';
6775
6350
  document.getElementById('tasksPagination').innerHTML='';
6776
- setPageSizeVisible('tasksPageSize',false);
6777
6351
  return;
6778
6352
  }
6779
6353
  list.innerHTML=tasks.map(function(task,idx){
@@ -6792,11 +6366,9 @@ async function loadHubTasks(){
6792
6366
  '</div>';
6793
6367
  }).join('');
6794
6368
  document.getElementById('tasksPagination').innerHTML='';
6795
- setPageSizeVisible('tasksPageSize',true);
6796
6369
  }catch(e){
6797
6370
  list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('tasks.empty')+'</div>';
6798
6371
  document.getElementById('tasksPagination').innerHTML='';
6799
- setPageSizeVisible('tasksPageSize',false);
6800
6372
  }
6801
6373
  }
6802
6374
 
@@ -6952,14 +6524,7 @@ async function openSkillDetail(skillId){
6952
6524
  }
6953
6525
 
6954
6526
  window._currentSkillData=skill;
6955
- var detailActionsHtml='';
6956
- if(skill.status==='active'){
6957
- detailActionsHtml+='<button class="btn btn-sm btn-warn" onclick="disableSkill(&quot;'+escAttr(skill.id)+'&quot;)">'+t('skills.action.disable')+'</button>';
6958
- }else if(skill.status==='archived'){
6959
- detailActionsHtml+='<button class="btn btn-sm btn-success" onclick="enableSkill(&quot;'+escAttr(skill.id)+'&quot;)">'+t('skills.action.enable')+'</button>';
6960
- }
6961
- detailActionsHtml+='<button class="btn btn-sm btn-danger" onclick="deleteSkill(&quot;'+escAttr(skill.id)+'&quot;)">'+t('skills.action.delete')+'</button>';
6962
- document.getElementById('skillDetailActions').innerHTML=detailActionsHtml;
6527
+ document.getElementById('skillDetailActions').innerHTML='';
6963
6528
 
6964
6529
  }catch(e){
6965
6530
  document.getElementById('skillDetailTitle').textContent=t('skills.error');
@@ -7148,7 +6713,6 @@ async function loadConfig(){
7148
6713
  document.getElementById('cfgSkillApiKey').value=skSum.apiKey||'';
7149
6714
 
7150
6715
  document.getElementById('cfgViewerPort').value=cfg.viewerPort||'';
7151
- document.getElementById('cfgTaskAutoFinalizeHours').value=cfg.taskAutoFinalizeHours!=null?cfg.taskAutoFinalizeHours:'';
7152
6716
 
7153
6717
  const tel=cfg.telemetry||{};
7154
6718
  document.getElementById('cfgTelemetryEnabled').checked=tel.enabled!==false;
@@ -7453,8 +7017,6 @@ async function saveGeneralConfig(){
7453
7017
  const cfg={};
7454
7018
  const vp=document.getElementById('cfgViewerPort').value.trim();
7455
7019
  if(vp) cfg.viewerPort=Number(vp);
7456
- const tafh=document.getElementById('cfgTaskAutoFinalizeHours').value.trim();
7457
- cfg.taskAutoFinalizeHours=tafh!==''?Math.max(0,Number(tafh)):4;
7458
7020
  cfg.telemetry={enabled:document.getElementById('cfgTelemetryEnabled').checked};
7459
7021
 
7460
7022
  await doSaveConfig(cfg, saveBtn, 'generalSaved');
@@ -7544,60 +7106,11 @@ async function deleteSkill(skillId){
7544
7106
  const r=await fetch('/api/skill/'+skillId,{method:'DELETE'});
7545
7107
  const d=await r.json();
7546
7108
  if(!r.ok) throw new Error(d.error||'unknown');
7547
- selectedSkillIds.delete(skillId);
7548
- updateSkillSelectionToolbar();
7549
7109
  closeSkillDetail();
7550
7110
  document.getElementById('skillDetailOverlay').classList.remove('show');
7551
7111
  loadSkills();
7552
7112
  }catch(e){ alert(t('skill.delete.error')+e.message); }
7553
7113
  }
7554
- async function disableSkill(skillId){
7555
- if(!(await confirmModal(t('skills.disable.confirm')))) return;
7556
- try{
7557
- const r=await fetch('/api/skill/'+skillId+'/disable',{method:'PUT'});
7558
- const d=await r.json();
7559
- if(!r.ok) throw new Error(d.error||'unknown');
7560
- toast(t('skills.action.disable')+' ✓','ok');
7561
- closeSkillDetail();
7562
- document.getElementById('skillDetailOverlay').classList.remove('show');
7563
- loadSkills();
7564
- }catch(e){ alert(t('skills.disable.error')+e.message); }
7565
- }
7566
- async function enableSkill(skillId){
7567
- try{
7568
- const r=await fetch('/api/skill/'+skillId+'/enable',{method:'PUT'});
7569
- const d=await r.json();
7570
- if(!r.ok) throw new Error(d.error||'unknown');
7571
- toast(t('skills.action.enable')+' ✓','ok');
7572
- closeSkillDetail();
7573
- document.getElementById('skillDetailOverlay').classList.remove('show');
7574
- loadSkills();
7575
- }catch(e){ alert(t('skills.enable.error')+e.message); }
7576
- }
7577
-
7578
- async function deleteSelectedSkills(){
7579
- var ids=Array.from(selectedSkillIds);
7580
- if(ids.length===0) return;
7581
- var msg=t('skill.delete.selected.confirm').replace('{count}',String(ids.length));
7582
- if(!(await confirmModal(msg,{danger:true}))) return;
7583
- var ok=0;
7584
- var fail=0;
7585
- for(var i=0;i<ids.length;i++){
7586
- try{
7587
- var r=await fetch('/api/skill/'+ids[i],{method:'DELETE'});
7588
- var d=await r.json();
7589
- if(!r.ok) throw new Error(d.error||'unknown');
7590
- ok++;
7591
- }catch(e){
7592
- fail++;
7593
- }
7594
- }
7595
- selectedSkillIds.clear();
7596
- updateSkillSelectionToolbar();
7597
- loadSkills();
7598
- if(fail>0) toast(t('skill.delete.partial').replace('{ok}',String(ok)).replace('{fail}',String(fail)),'warn');
7599
- else toast(t('skill.delete.success').replace('{count}',String(ok)),'success');
7600
- }
7601
7114
 
7602
7115
 
7603
7116
  function formatDuration(ms){
@@ -7932,7 +7445,7 @@ async function _livePollTick(){
7932
7445
  var _searchVal=(document.getElementById('searchInput')||{}).value||'';
7933
7446
  if(!_searchVal.trim()){
7934
7447
  if(memorySearchScope==='hub') await loadHubMemories(true);
7935
- else{var _pollOwner=undefined;await loadStats(_pollOwner);await loadMemories(null,true);}
7448
+ else{var _pollOwner=memorySearchScope==='local'?_currentAgentOwner:undefined;await loadStats(_pollOwner);await loadMemories(null,true);}
7936
7449
  }
7937
7450
  }
7938
7451
  else if(_activeView==='tasks') await loadTasks(true);
@@ -8205,7 +7718,7 @@ function stopNotifPoll(){ }
8205
7718
  /* ─── Data loading ─── */
8206
7719
  async function loadAll(){
8207
7720
  await loadStats();
8208
- var initOwner=undefined;
7721
+ var initOwner=memorySearchScope==='local'?_currentAgentOwner:undefined;
8209
7722
  if(initOwner) await loadStats(initOwner);
8210
7723
  await Promise.all([loadMemories(),loadSharingStatus(false)]);
8211
7724
  checkMigrateStatus();
@@ -8225,23 +7738,21 @@ async function loadStats(ownerFilter){
8225
7738
  d=await r.json();
8226
7739
  }catch(e){ d={}; }
8227
7740
  if(!d||typeof d!=='object') d={};
8228
- if(d.currentAgentOwner && !new URLSearchParams(window.location.search).get('agentId')) _currentAgentOwner=d.currentAgentOwner;
7741
+ if(d.currentAgentOwner) _currentAgentOwner=d.currentAgentOwner;
8229
7742
  const tm=d.totalMemories||0;
8230
7743
  const dedupB=d.dedupBreakdown||{};
8231
7744
  const activeCount=dedupB.active||tm;
8232
7745
  const inactiveCount=(dedupB.duplicate||0)+(dedupB.merged||0);
8233
7746
  var agentCount=(d.owners&&d.owners.length)?d.owners.length:1;
8234
- var tvc=(d.taskSessions||[]).length;
8235
- var svc=(d.skillSessions||[]).length;
8236
- var sfp=tm+':'+(d.totalSessions||0)+':'+(d.totalEmbeddings||0)+':'+agentCount+':'+(d.embeddingProvider||'none')+':'+(ownerFilter||'')+':'+(_activeView||'memories')+':'+tvc+':'+svc;
7747
+ var sfp=tm+':'+(d.totalSessions||0)+':'+(d.totalEmbeddings||0)+':'+agentCount+':'+(d.embeddingProvider||'none')+':'+(ownerFilter||'');
8237
7748
  if(sfp===_lastStatsFp) return;
8238
7749
  _lastStatsFp=sfp;
8239
7750
  document.getElementById('statTotal').textContent=tm;
8240
7751
  if(inactiveCount>0){
8241
7752
  document.getElementById('statTotal').title=activeCount+' '+t('stat.active')+', '+inactiveCount+' '+t('stat.deduped');
8242
7753
  }
8243
- document.getElementById('statTasks').textContent=d.totalTasks||0;
8244
- document.getElementById('statSkills').textContent=d.totalSkills||0;
7754
+ document.getElementById('statSessions').textContent=d.totalSessions||0;
7755
+ document.getElementById('statEmbeddings').textContent=d.totalEmbeddings||0;
8245
7756
  document.getElementById('statAgents').textContent=agentCount;
8246
7757
 
8247
7758
  const provEl=document.getElementById('embeddingStatus');
@@ -8265,67 +7776,45 @@ async function loadStats(ownerFilter){
8265
7776
  }).catch(()=>{});
8266
7777
  }
8267
7778
 
8268
- const memorySessions=d.sessions||[];
8269
- const taskSessions=d.taskSessions||[];
8270
- const skillSessions=d.skillSessions||[];
8271
- const sessionMap={memories:memorySessions,tasks:taskSessions,skills:skillSessions};
8272
- function getSessionsForView(view){
8273
- return sessionMap[view]||memorySessions;
8274
- }
8275
- function countBadgeHtml(cnt){
8276
- return cnt&&cnt>0?'<span class="count">'+cnt+'</span>':'';
8277
- }
8278
-
8279
- const sidebarSessions=getSessionsForView(_activeView);
7779
+ const sl=document.getElementById('sessionList');
7780
+ sl.innerHTML='<div class="session-item'+(activeSession===null?' active':'')+'" onclick="filterSession(null)"><span>'+t('sidebar.allsessions')+'</span><span class="count">'+tm+'</span></div>';
7781
+ (d.sessions||[]).forEach(s=>{
7782
+ const isActive=activeSession===s.session_key;
7783
+ const name=s.session_key.length>20?s.session_key.slice(0,8)+'...'+s.session_key.slice(-8):s.session_key;
7784
+ sl.innerHTML+='<div class="session-item'+(isActive?' active':'')+'" onclick="filterSession(\\''+s.session_key.replace(/'/g,"\\\\'")+'\\')"><span title="'+s.session_key+'">'+name+'</span><span class="count">'+s.count+'</span></div>';
7785
+ });
8280
7786
 
8281
- [['filterSession','memories'],['taskFilterSession','tasks'],['skillFilterSession','skills']].forEach(function(pair){
8282
- var selId=pair[0];
8283
- var viewKey=pair[1];
8284
- var viewSessions=getSessionsForView(viewKey);
8285
- const fSel=document.getElementById(selId);
8286
- if(!fSel) return;
7787
+ const fSel=document.getElementById('filterSession');
7788
+ if(fSel){
8287
7789
  const curVal=activeSession||'';
8288
- var sessionCount=viewSessions.length;
8289
- fSel.style.display=sessionCount>0?'':'none';
7790
+ var sessionCount=(d.sessions||[]).length;
8290
7791
  fSel.innerHTML='<option value="">'+t('filter.allsessions')+' ('+sessionCount+')</option>';
8291
- viewSessions.forEach(s=>{
7792
+ (d.sessions||[]).forEach(s=>{
8292
7793
  const sName=s.session_key.length>30?s.session_key.slice(0,12)+'...'+s.session_key.slice(-10):s.session_key;
8293
- const countLabel=(s.count&&s.count>0)?' ('+s.count+')':'';
8294
- fSel.innerHTML+='<option value="'+s.session_key.replace(/"/g,'&quot;')+'"'+(s.session_key===curVal?' selected':'')+'>'+sName+countLabel+'</option>';
7794
+ fSel.innerHTML+='<option value="'+s.session_key.replace(/"/g,'&quot;')+'"'+(s.session_key===curVal?' selected':'')+'>'+sName+' ('+s.count+')</option>';
8295
7795
  });
8296
- });
7796
+ }
8297
7797
 
8298
- if(d.owners && d.owners.length>0){
7798
+ const ownerSel=document.getElementById('filterOwner');
7799
+ if(ownerSel && d.owners && d.owners.length>0){
7800
+ const curVal=ownerSel.value;
8299
7801
  var agents=d.owners.filter(function(o){return o && o.indexOf('agent:')===0;});
8300
- ['filterOwner','taskFilterOwner','skillFilterOwner'].forEach(function(selId){
8301
- var sel=document.getElementById(selId);
8302
- if(!sel) return;
8303
- var curVal=sel.value;
8304
- sel.innerHTML='<option value="">'+t('filter.allagents')+'</option>';
8305
- agents.forEach(function(o){
8306
- var label=o.replace('agent:','');
8307
- sel.innerHTML+='<option value="'+o+'"'+(o===curVal?' selected':'')+'>'+label+'</option>';
8308
- });
8309
- sel.style.display='';
7802
+ ownerSel.innerHTML='<option value="">'+t('filter.allagents')+'</option>';
7803
+ agents.forEach(function(o){
7804
+ var label=o.replace('agent:','');
7805
+ ownerSel.innerHTML+='<option value="'+o+'"'+(o===curVal?' selected':'')+'>'+label+'</option>';
8310
7806
  });
7807
+ if(agents.length<=1) ownerSel.style.display='none';
7808
+ else ownerSel.style.display='';
8311
7809
  }
8312
7810
  }
8313
7811
 
8314
7812
  function onOwnerFilterChange(){
8315
- var src=event&&event.target?event.target:document.getElementById('filterOwner');
8316
- var owner=src.value;
8317
- ['filterOwner','taskFilterOwner','skillFilterOwner'].forEach(function(id){
8318
- var el=document.getElementById(id);
8319
- if(el&&el!==src) el.value=owner;
8320
- });
7813
+ var owner=document.getElementById('filterOwner').value;
8321
7814
  activeSession=null;
8322
7815
  currentPage=1;
8323
- taskSearchQuery='';
8324
- var tsi=document.getElementById('taskSearchInput');if(tsi)tsi.value='';
8325
7816
  refreshSessionDropdown(owner);
8326
7817
  applyFilters();
8327
- loadTasks();
8328
- loadSkills();
8329
7818
  }
8330
7819
 
8331
7820
  async function refreshSessionDropdown(ownerFilter){
@@ -8356,13 +7845,12 @@ function getFilterParams(){
8356
7845
  if(dt) p.set('dateTo',dt);
8357
7846
  const sort=document.getElementById('filterSort').value;
8358
7847
  if(sort==='oldest') p.set('sort','oldest');
8359
- const scope=memorySearchScope||'allLocal';
8360
- if(scope==='allLocal'){
8361
- const owner=document.getElementById('filterOwner').value;
8362
- if(owner) {
8363
- p.set('owner',owner);
8364
- _currentAgentOwner = owner;
8365
- }
7848
+ const scope=memorySearchScope||'local';
7849
+ if(scope==='local'){
7850
+ p.set('owner',_currentAgentOwner);
7851
+ }else if(scope==='allLocal'){
7852
+ const owner=document.getElementById('filterOwner').value;
7853
+ if(owner) p.set('owner',owner);
8366
7854
  }
8367
7855
  return p;
8368
7856
  }
@@ -8423,8 +7911,6 @@ async function loadMemories(page,silent){
8423
7911
 
8424
7912
  async function loadHubMemories(silent){
8425
7913
  const list=document.getElementById('memoryList');
8426
- selectedMemoryIds.clear();
8427
- updateMemorySelectionToolbar();
8428
7914
  if(!silent) list.innerHTML='<div class="spinner"></div>';
8429
7915
  try{
8430
7916
  const r=await fetch('/api/sharing/memories/list?limit='+PAGE_SIZE);
@@ -8461,7 +7947,7 @@ async function doSearch(query){
8461
7947
  return;
8462
7948
  }
8463
7949
  currentPage=1;
8464
- var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'allLocal';
7950
+ var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'local';
8465
7951
  var list=document.getElementById('memoryList');
8466
7952
  list.innerHTML='<div class="spinner"></div>';
8467
7953
  if(scope==='hub'){
@@ -8513,22 +7999,12 @@ function debounceSearch(){
8513
7999
  function filterSession(key){
8514
8000
  activeSession=key;
8515
8001
  currentPage=1;
8516
- tasksPage=0;
8517
- skillsPage=0;
8518
- ['filterSession','taskFilterSession','skillFilterSession'].forEach(function(selId){
8519
- var fSel=document.getElementById(selId);
8520
- if(fSel) fSel.value=key||'';
8002
+ var fSel=document.getElementById('filterSession');
8003
+ if(fSel) fSel.value=key||'';
8004
+ document.querySelectorAll('#sessionList .session-item').forEach(function(el,i){
8005
+ if(i===0) el.classList.toggle('active',!key);
8006
+ else el.classList.toggle('active',el.querySelector('span')?.title===key);
8521
8007
  });
8522
- if(_activeView==='tasks'){
8523
- loadStats();
8524
- loadTasks();
8525
- return;
8526
- }
8527
- if(_activeView==='skills'){
8528
- loadStats();
8529
- loadSkills();
8530
- return;
8531
- }
8532
8008
  loadAll();
8533
8009
  }
8534
8010
 
@@ -8555,88 +8031,14 @@ function clearDateFilter(){
8555
8031
  applyFilters();
8556
8032
  }
8557
8033
 
8558
- function updateMemorySelectionToolbar(){
8559
- var toolbar=document.getElementById('memorySelectionToolbar');
8560
- var selectAllBtn=document.getElementById('memorySelectAllBtn');
8561
- var bulkDeleteBtn=document.getElementById('memoryBulkDeleteBtn');
8562
- var isHub=memorySearchScope==='hub';
8563
- var total=document.querySelectorAll('#memoryList .memory-select-check').length;
8564
- var selected=selectedMemoryIds.size;
8565
- if(toolbar) toolbar.style.display=isHub?'none':'flex';
8566
- if(selectAllBtn){
8567
- selectAllBtn.textContent=t(selected>0&&selected===total&&total>0?'skills.unselectAll':'skills.selectAll');
8568
- selectAllBtn.disabled=total===0;
8569
- selectAllBtn.style.display=total===0?'none':'';
8570
- }
8571
- if(bulkDeleteBtn){
8572
- var base=t('memory.deleteSelected');
8573
- bulkDeleteBtn.style.display=selected>0?'':'none';
8574
- bulkDeleteBtn.textContent=selected>0?(base+' ('+selected+')'):base;
8575
- }
8576
- }
8577
-
8578
- function toggleMemorySelection(memoryId,checked){
8579
- if(checked) selectedMemoryIds.add(memoryId);
8580
- else selectedMemoryIds.delete(memoryId);
8581
- updateMemorySelectionToolbar();
8582
- }
8583
-
8584
- function toggleSelectAllMemories(){
8585
- var total=currentMemoryIds.length;
8586
- if(total===0) return;
8587
- if(selectedMemoryIds.size===total){
8588
- selectedMemoryIds.clear();
8589
- }else{
8590
- selectedMemoryIds=new Set(currentMemoryIds);
8591
- }
8592
- var checks=document.querySelectorAll('#memoryList .memory-select-check');
8593
- checks.forEach(function(cb){cb.checked=selectedMemoryIds.has(cb.value);});
8594
- updateMemorySelectionToolbar();
8595
- }
8596
-
8597
- async function deleteSelectedMemories(){
8598
- var ids=Array.from(selectedMemoryIds);
8599
- if(ids.length===0) return;
8600
- var msg=t('memory.delete.selected.confirm').replace('{count}',String(ids.length));
8601
- if(!(await confirmModal(msg,{danger:true}))) return;
8602
- var ok=0;
8603
- var fail=0;
8604
- for(var i=0;i<ids.length;i++){
8605
- try{
8606
- var r=await fetch('/api/memory/'+ids[i],{method:'DELETE'});
8607
- var d=await r.json();
8608
- if(!d.ok) throw new Error(d.error||'unknown');
8609
- ok++;
8610
- }catch(e){
8611
- fail++;
8612
- }
8613
- }
8614
- selectedMemoryIds.clear();
8615
- updateMemorySelectionToolbar();
8616
- if(document.getElementById('searchInput').value.trim()){
8617
- doSearch(document.getElementById('searchInput').value);
8618
- }else if(memorySearchScope==='hub'){
8619
- loadHubMemories();
8620
- }else{
8621
- loadMemories();
8622
- }
8623
- if(fail>0) toast(t('memory.delete.partial').replace('{ok}',String(ok)).replace('{fail}',String(fail)),'warn');
8624
- else toast(t('memory.delete.success').replace('{count}',String(ok)),'success');
8625
- }
8626
-
8627
8034
  /* ─── Rendering ─── */
8628
8035
  function renderMemories(items){
8629
8036
  const list=document.getElementById('memoryList');
8630
- setPageSizeVisible('memoryPageSize',items.length>0);
8631
8037
  if(!items.length){
8632
8038
  list.innerHTML='<div class="empty"><div class="icon">\\u{1F4ED}</div><p>'+t('empty.text')+'</p></div>';
8633
- currentMemoryIds=[];
8634
- updateMemorySelectionToolbar();
8635
8039
  return;
8636
8040
  }
8637
8041
  items.forEach(m=>{memoryCache[m.id]=m});
8638
- currentMemoryIds=items.map(function(m){return m.id;});
8639
- selectedMemoryIds=new Set(Array.from(selectedMemoryIds).filter(function(id){return currentMemoryIds.includes(id);}));
8640
8042
  list.innerHTML=items.map(m=>{
8641
8043
  const time=m.created_at?new Date(typeof m.created_at==='number'?m.created_at:m.created_at).toLocaleString(dateLoc()):'';
8642
8044
  const role=m.role||'user';
@@ -8646,7 +8048,7 @@ function renderMemories(items){
8646
8048
  const id=m.id;
8647
8049
  const vscore=m._vscore?'<span class="vscore-badge">'+Math.round(m._vscore*100)+'%</span>':'';
8648
8050
  const sid=m.session_key||'';
8649
- const sidShort=fmtSessionDisplay(sid);
8051
+ const sidShort=sid.length>18?sid.slice(0,6)+'..'+sid.slice(-6):sid;
8650
8052
  const mc=m.merge_count||0;
8651
8053
  const cardTitle=esc(rawSummary||rawContent||'');
8652
8054
  const mergeBadge=mc>0?'<span class="merge-badge">\\u{1F504} '+t('card.evolved')+' '+mc+t('card.times')+'</span>':'';
@@ -8654,7 +8056,7 @@ function renderMemories(items){
8654
8056
  const ds=m.dedup_status||'active';
8655
8057
  const isInactive=ds==='merged'||ds==='duplicate';
8656
8058
  const dedupBadge=ds==='duplicate'?'<span class="dedup-badge duplicate">'+t('card.dedupDuplicate')+'</span>':ds==='merged'?'<span class="dedup-badge merged">'+t('card.dedupMerged')+'</span>':'';
8657
- const isImported=isImportedSession(sid);
8059
+ const isImported=sid.startsWith('openclaw-import-')||sid.startsWith('openclaw-session-');
8658
8060
  const importBadge=isImported?'<span class="import-badge">\u{1F990} '+t('card.imported')+'</span>':'';
8659
8061
  const ownerVal=m.owner||'agent:main';
8660
8062
  const isPublicMem=ownerVal==='public';
@@ -8663,8 +8065,6 @@ function renderMemories(items){
8663
8065
  const isHubScope=memorySearchScope==='hub';
8664
8066
  const memScope=memShared?'team':isPublicMem?'local':'private';
8665
8067
  const memScopeBadge=isHubScope?renderScopeBadge('team'):renderScopeBadge(memScope);
8666
- const selectedAttr=selectedMemoryIds.has(id)?' checked':'';
8667
- const selectBoxHtml=isHubScope?'':'<label class="item-select-box" onclick="event.stopPropagation()"><input class="memory-select-check" type="checkbox" value="'+escAttr(id)+'"'+selectedAttr+' onchange="event.stopPropagation();toggleMemorySelection(&quot;'+escAttr(id)+'&quot;,this.checked)"></label>';
8668
8068
  let dedupInfo='';
8669
8069
  if(ds==='duplicate'||ds==='merged'){
8670
8070
  const reason=m.dedup_reason?'<span style="font-size:11px;color:var(--text-muted)">'+t('card.dedupReason')+esc(m.dedup_reason)+'</span>':'';
@@ -8688,11 +8088,9 @@ function renderMemories(items){
8688
8088
  }
8689
8089
  }catch(e){}
8690
8090
  }
8691
- var ownerName=fmtAgentName(m.owner);
8692
- var ownerBadge=ownerName?'<span class="owner-tag" title="'+esc(m.owner||'')+'">\\u{1F916} '+esc(ownerName)+'</span>':'';
8693
8091
  return '<div class="memory-card'+(isInactive?' dedup-inactive':'')+'">'+
8694
- '<div class="card-header"><div class="meta"><span class="role-tag '+role+'">'+role+'</span>'+ownerBadge+memScopeBadge+importBadge+dedupBadge+mergeBadge+'</div><span class="card-time"><span class="session-tag" title="'+esc(sid)+'">'+esc(sidShort)+'</span> '+time+updatedAt+'</span></div>'+
8695
- '<div class="card-summary">'+selectBoxHtml+cardTitle+'</div>'+
8092
+ '<div class="card-header"><div class="meta"><span class="role-tag '+role+'">'+role+'</span>'+memScopeBadge+importBadge+dedupBadge+mergeBadge+'</div><span class="card-time"><span class="session-tag" title="'+esc(sid)+'">'+esc(sidShort)+'</span> '+time+updatedAt+'</span></div>'+
8093
+ '<div class="card-summary">'+cardTitle+'</div>'+
8696
8094
  (function(){
8697
8095
  if(mc<=0) return '';
8698
8096
  var mergeHtml='<div class="card-merged-info">';
@@ -8722,7 +8120,6 @@ function renderMemories(items){
8722
8120
  vscore+
8723
8121
  '</div></div>';
8724
8122
  }).join('');
8725
- updateMemorySelectionToolbar();
8726
8123
  }
8727
8124
 
8728
8125
  function updateMemoryCardBadge(chunkId,newScope){
@@ -8831,8 +8228,7 @@ async function showMemoryModal(chunkId){
8831
8228
  h+='<div class="mm-section"><div class="mm-section-label">'+t('admin.content')+'</div><pre class="mm-content">'+esc(m.content)+'</pre></div>';
8832
8229
  }
8833
8230
  h+='<div class="mm-meta">';
8834
- if(m.owner) h+='<div class="mm-meta-chip"><strong>'+t('admin.owner')+'</strong><span>\\u{1F916} '+esc(m.owner)+'</span></div>';
8835
- if(m.session_key) h+='<div class="mm-meta-chip"><strong>'+t('admin.session')+'</strong><span>'+esc(m.session_key)+'</span></div>';
8231
+ if(m.session_key) h+='<div class="mm-meta-chip"><strong>'+t('admin.session')+'</strong><span>'+esc(m.session_key.slice(0,12))+'</span></div>';
8836
8232
  h+='<div class="mm-meta-chip"><strong>'+t('memory.detail.created')+'</strong><span>'+fmtModalDate(m.created_at)+'</span></div>';
8837
8233
  if(m.updated_at) h+='<div class="mm-meta-chip"><strong>'+t('memory.detail.updated')+'</strong><span>'+fmtModalDate(m.updated_at)+'</span></div>';
8838
8234
  if(m.kind) h+='<div class="mm-meta-chip"><strong>'+t('admin.kind')+'</strong><span>'+esc(m.kind)+'</span></div>';
@@ -8926,18 +8322,7 @@ async function deleteMemory(id){
8926
8322
  if(!(await confirmModal(t('confirm.delete'),{danger:true})))return;
8927
8323
  const r=await fetch('/api/memory/'+id,{method:'DELETE'});
8928
8324
  const d=await r.json();
8929
- if(d.ok){
8930
- selectedMemoryIds.delete(id);
8931
- updateMemorySelectionToolbar();
8932
- toast(t('toast.deleted'),'success');
8933
- if(document.getElementById('searchInput').value.trim()){
8934
- doSearch(document.getElementById('searchInput').value);
8935
- }else if(memorySearchScope==='hub'){
8936
- loadHubMemories();
8937
- }else{
8938
- loadMemories();
8939
- }
8940
- }
8325
+ if(d.ok){toast(t('toast.deleted'),'success');loadAll();}
8941
8326
  else{toast(t('toast.delfail'),'error')}
8942
8327
  }
8943
8328
 
@@ -8977,13 +8362,7 @@ async function clearAll(){
8977
8362
  const r=await fetch('/api/memories',{method:'DELETE'});
8978
8363
  if(r.status===401){toast(t('settings.session.expired'),'error');return;}
8979
8364
  const d=await r.json();
8980
- if(d.ok){
8981
- toast(t('toast.cleared'),'success');
8982
- selectedMemoryIds.clear();selectedTaskIds.clear();selectedSkillIds.clear();
8983
- _lastMemoriesFingerprint='';_lastTasksFingerprint='';_lastSkillsFingerprint='';_lastStatsFp='';
8984
- await loadStats();
8985
- await Promise.all([loadMemories(),loadTasks(),loadSkills(),loadSharingStatus(false)]);
8986
- }
8365
+ if(d.ok){toast(t('toast.cleared'),'success');loadAll();}
8987
8366
  else{toast(t('toast.clearfail'),'error')}
8988
8367
  }catch(e){toast('Error: '+e.message,'error')}
8989
8368
  }
@@ -9009,7 +8388,7 @@ async function migrateScan(showToast){
9009
8388
  const btn=document.getElementById('migrateScanBtn');
9010
8389
  btn.disabled=true;
9011
8390
  btn.textContent=t('migrate.scanning');
9012
- document.getElementById('migrateStartConcurrencyWrap').style.display='none';
8391
+ document.getElementById('migrateStartBtn').style.display='none';
9013
8392
  document.getElementById('migrateScanResult').style.display='none';
9014
8393
  document.getElementById('migrateConfigWarn').style.display='none';
9015
8394
  document.getElementById('migrateProgress').style.display='none';
@@ -9042,7 +8421,8 @@ async function migrateScan(showToast){
9042
8421
  const remaining=Math.max(0,(d.totalItems||0)-imported);
9043
8422
 
9044
8423
  if(d.totalItems>0 && d.configReady){
9045
- document.getElementById('migrateStartConcurrencyWrap').style.display='flex';
8424
+ document.getElementById('migrateStartBtn').style.display='inline-flex';
8425
+ document.getElementById('migrateConcurrencyRow').style.display='inline-flex';
9046
8426
  if(d.hasImportedData){
9047
8427
  document.getElementById('migrateStartBtn').textContent=t('migrate.resume');
9048
8428
  }else{
@@ -9095,10 +8475,11 @@ async function migrateStart(){
9095
8475
 
9096
8476
  window._migrateRunning=true;
9097
8477
  _migrateStatusChecked=true;
9098
- document.getElementById('migrateStartConcurrencyWrap').style.display='none';
8478
+ document.getElementById('migrateStartBtn').style.display='none';
9099
8479
  document.getElementById('migrateScanBtn').disabled=true;
9100
8480
  var hintEl=document.getElementById('migrateImportedHint');
9101
8481
  if(hintEl) hintEl.style.display='none';
8482
+ document.getElementById('migrateConcurrencyRow').style.display='none';
9102
8483
  document.getElementById('migrateConcurrencyWarn').style.display='none';
9103
8484
  document.getElementById('migrateProgress').style.display='block';
9104
8485
  document.getElementById('migrateLiveLog').innerHTML='';
@@ -9183,7 +8564,7 @@ async function checkMigrateStatus(){
9183
8564
  const progEl=document.getElementById('migrateProgress');
9184
8565
  if(!progEl)return;
9185
8566
  progEl.style.display='block';
9186
- document.getElementById('migrateStartConcurrencyWrap').style.display='none';
8567
+ document.getElementById('migrateStartBtn').style.display='none';
9187
8568
  document.getElementById('migrateScanBtn').disabled=true;
9188
8569
  document.getElementById('migrateStopBtn').disabled=false;
9189
8570
  const pct=s.total>0?Math.round((s.processed/s.total)*100):0;
@@ -9303,7 +8684,7 @@ function onMigrateDone(wasStopped,skipReload){
9303
8684
  document.getElementById('migrateStopBtn').style.display='none';
9304
8685
  if(wasStopped){
9305
8686
  document.getElementById('migrateBar').style.background='linear-gradient(90deg,#f59e0b,#fbbf24)';
9306
- document.getElementById('migrateStartConcurrencyWrap').style.display='flex';
8687
+ document.getElementById('migrateStartBtn').style.display='inline-flex';
9307
8688
  document.getElementById('migrateStartBtn').textContent=t('migrate.resume');
9308
8689
  document.getElementById('migratePhaseLabel').textContent=t('migrate.phase.stopped');
9309
8690
  }else{
@@ -9695,10 +9076,7 @@ function doUpdateInstall(packageSpec,btnEl,statusEl,targetVersion){
9695
9076
  btnEl.disabled=false;
9696
9077
  });
9697
9078
  }
9698
- var _updateChecked=false;
9699
9079
  async function checkForUpdate(){
9700
- if(_updateChecked) return;
9701
- _updateChecked=true;
9702
9080
  try{
9703
9081
  const r=await fetch('/api/update-check?_t='+Date.now(),{cache:'no-store'});
9704
9082
  if(!r.ok)return;
@@ -9748,16 +9126,12 @@ async function checkForUpdate(){
9748
9126
  /* ─── Init ─── */
9749
9127
  try{
9750
9128
  var savedScope=localStorage.getItem('memos_memorySearchScope');
9751
- if(savedScope==='local') savedScope='allLocal';
9752
- if(savedScope&&(savedScope==='allLocal'||savedScope==='hub')){
9129
+ if(savedScope&&(savedScope==='local'||savedScope==='allLocal'||savedScope==='hub')){
9753
9130
  memorySearchScope=savedScope;
9754
9131
  var scopeEl=document.getElementById('memorySearchScope');
9755
9132
  if(scopeEl) scopeEl.value=savedScope;
9756
9133
  }
9757
9134
  }catch(e){}
9758
- restorePageSizeSetting('memos_memoryPageSize','memoryPageSize',20,function(next){PAGE_SIZE=next;});
9759
- restorePageSizeSetting('memos_skillsPageSize','skillsPageSize',20,function(next){skillsPageSize=next;});
9760
- restorePageSizeSetting('memos_tasksPageSize','tasksPageSize',20,function(next){tasksPageSize=next;});
9761
9135
  document.getElementById('modalOverlay').addEventListener('click',e=>{if(e.target.id==='modalOverlay')closeModal()});
9762
9136
  document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';currentPage=1;if(memorySearchScope==='hub')loadHubMemories();else loadMemories();}});
9763
9137
  applyI18n();