@memtensor/memos-local-openclaw-plugin 0.3.18 → 0.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -11
- package/dist/capture/index.d.ts +1 -1
- package/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +7 -2
- package/dist/capture/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/ingest/dedup.d.ts +2 -2
- package/dist/ingest/dedup.d.ts.map +1 -1
- package/dist/ingest/dedup.js +4 -4
- package/dist/ingest/dedup.js.map +1 -1
- package/dist/ingest/task-processor.d.ts +1 -1
- package/dist/ingest/task-processor.d.ts.map +1 -1
- package/dist/ingest/task-processor.js +14 -13
- package/dist/ingest/task-processor.js.map +1 -1
- package/dist/ingest/worker.d.ts.map +1 -1
- package/dist/ingest/worker.js +7 -3
- package/dist/ingest/worker.js.map +1 -1
- package/dist/recall/engine.d.ts +5 -1
- package/dist/recall/engine.d.ts.map +1 -1
- package/dist/recall/engine.js +77 -2
- package/dist/recall/engine.js.map +1 -1
- package/dist/skill/evolver.d.ts +2 -1
- package/dist/skill/evolver.d.ts.map +1 -1
- package/dist/skill/evolver.js +2 -2
- package/dist/skill/evolver.js.map +1 -1
- package/dist/skill/generator.d.ts +3 -1
- package/dist/skill/generator.d.ts.map +1 -1
- package/dist/skill/generator.js +15 -1
- package/dist/skill/generator.js.map +1 -1
- package/dist/storage/sqlite.d.ts +24 -8
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +233 -28
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/storage/vector.d.ts +1 -1
- package/dist/storage/vector.d.ts.map +1 -1
- package/dist/storage/vector.js +3 -3
- package/dist/storage/vector.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +107 -1
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +1 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +52 -3
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +171 -7
- package/package.json +1 -1
- package/skill/browserwing-admin/SKILL.md +521 -0
- package/skill/browserwing-executor/SKILL.md +510 -0
- package/skill/memos-memory-guide/SKILL.md +62 -36
- package/src/capture/index.ts +7 -1
- package/src/index.ts +3 -2
- package/src/ingest/dedup.ts +4 -2
- package/src/ingest/task-processor.ts +14 -13
- package/src/ingest/worker.ts +7 -3
- package/src/recall/engine.ts +94 -4
- package/src/skill/evolver.ts +3 -1
- package/src/skill/generator.ts +15 -0
- package/src/storage/sqlite.ts +262 -34
- package/src/storage/vector.ts +3 -2
- package/src/types.ts +18 -0
- package/src/viewer/html.ts +107 -1
- package/src/viewer/server.ts +48 -3
package/src/viewer/html.ts
CHANGED
|
@@ -182,6 +182,13 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
182
182
|
.dedup-badge.merged{background:rgba(59,130,246,.12);color:#60a5fa}
|
|
183
183
|
.import-badge{display:inline-flex;align-items:center;gap:4px;background:rgba(236,72,153,.1);color:#ec4899;font-size:10px;font-weight:600;padding:3px 10px;border-radius:8px}
|
|
184
184
|
[data-theme="light"] .import-badge{background:rgba(219,39,119,.08);color:#db2777}
|
|
185
|
+
.owner-badge{display:inline-flex;align-items:center;gap:3px;font-size:10px;font-weight:600;padding:3px 10px;border-radius:8px}
|
|
186
|
+
.owner-badge.public{background:rgba(52,211,153,.12);color:#34d399}
|
|
187
|
+
.owner-badge.agent{background:rgba(255,255,255,.06);color:var(--text-sec)}
|
|
188
|
+
[data-theme="light"] .owner-badge.public{background:rgba(16,185,129,.08);color:#059669}
|
|
189
|
+
[data-theme="light"] .owner-badge.agent{background:rgba(0,0,0,.04);color:var(--text-sec)}
|
|
190
|
+
.skill-badge.visibility-public{background:rgba(0,229,255,.12);color:#00bcd4}
|
|
191
|
+
[data-theme="light"] .skill-badge.visibility-public{background:rgba(0,172,193,.08);color:#00838f}
|
|
185
192
|
.memory-card.dedup-inactive{opacity:.55;border-style:dashed}
|
|
186
193
|
.memory-card.dedup-inactive:hover{opacity:.85}
|
|
187
194
|
.dedup-target-link{font-size:11px;color:var(--pri);cursor:pointer;text-decoration:underline;margin-left:4px}
|
|
@@ -385,6 +392,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
385
392
|
.skill-file-size{font-size:10px;color:var(--text-muted)}
|
|
386
393
|
.skill-download-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;border-radius:8px;background:var(--pri-grad);color:#fff;font-size:12px;font-weight:600;border:none;cursor:pointer;transition:all .2s}
|
|
387
394
|
.skill-download-btn:hover{opacity:.85;transform:translateY(-1px)}
|
|
395
|
+
.skill-vis-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:600;border:none;cursor:pointer;transition:all .2s}
|
|
396
|
+
.skill-vis-btn:hover{opacity:.85;transform:translateY(-1px)}
|
|
397
|
+
.skill-vis-btn.is-public{background:linear-gradient(135deg,#34d399,#10b981);color:#fff}
|
|
398
|
+
.skill-vis-btn.is-private{background:var(--pri-grad);color:#fff}
|
|
399
|
+
.mem-public-btn{color:var(--pri)!important}
|
|
388
400
|
.task-skill-section{margin-bottom:16px;padding:14px 16px;border-radius:var(--radius);border:1px solid var(--border)}
|
|
389
401
|
.task-skill-section.status-generated{border-color:var(--green);background:var(--green-bg)}
|
|
390
402
|
.task-skill-section.status-generating{border-color:var(--amber);background:var(--amber-bg)}
|
|
@@ -760,6 +772,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
760
772
|
<option value="newest" data-i18n="filter.newest">Newest first</option>
|
|
761
773
|
<option value="oldest" data-i18n="filter.oldest">Oldest first</option>
|
|
762
774
|
</select>
|
|
775
|
+
<span class="filter-sep"></span>
|
|
776
|
+
<select id="filterOwner" class="filter-select" onchange="applyFilters()">
|
|
777
|
+
<option value="" data-i18n="filter.allowners">All owners</option>
|
|
778
|
+
<option value="public" data-i18n="filter.public">Public</option>
|
|
779
|
+
</select>
|
|
763
780
|
</div>
|
|
764
781
|
<div class="date-filter">
|
|
765
782
|
<label data-i18n="filter.from">From</label><input type="datetime-local" id="dateFrom" step="1" onchange="applyFilters()">
|
|
@@ -809,12 +826,19 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
809
826
|
<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>
|
|
810
827
|
<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>
|
|
811
828
|
<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>
|
|
829
|
+
<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>
|
|
812
830
|
</div>
|
|
813
831
|
<div class="tasks-filters">
|
|
814
832
|
<button class="filter-chip active" data-skill-status="" onclick="setSkillStatusFilter(this,'')" data-i18n="filter.all">All</button>
|
|
815
833
|
<button class="filter-chip" data-skill-status="active" onclick="setSkillStatusFilter(this,'active')" data-i18n="skills.filter.active">Active</button>
|
|
816
834
|
<button class="filter-chip" data-skill-status="draft" onclick="setSkillStatusFilter(this,'draft')" data-i18n="skills.filter.draft">Draft</button>
|
|
817
835
|
<button class="filter-chip" data-skill-status="archived" onclick="setSkillStatusFilter(this,'archived')" data-i18n="skills.filter.archived">Archived</button>
|
|
836
|
+
<span class="filter-sep"></span>
|
|
837
|
+
<select id="skillVisibilityFilter" class="filter-select" onchange="loadSkills()">
|
|
838
|
+
<option value="" data-i18n="filter.allvisibility">All visibility</option>
|
|
839
|
+
<option value="public" data-i18n="filter.public">Public</option>
|
|
840
|
+
<option value="private" data-i18n="filter.private">Private</option>
|
|
841
|
+
</select>
|
|
818
842
|
<button class="btn btn-sm btn-ghost" onclick="loadSkills()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
819
843
|
</div>
|
|
820
844
|
</div>
|
|
@@ -825,6 +849,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
825
849
|
<div class="task-detail-header">
|
|
826
850
|
<h2 id="skillDetailTitle"></h2>
|
|
827
851
|
<div style="display:flex;gap:8px;align-items:center">
|
|
852
|
+
<button class="skill-vis-btn" id="skillVisibilityBtn" onclick="toggleSkillVisibility()"></button>
|
|
828
853
|
<button class="skill-download-btn" id="skillDownloadBtn" onclick="downloadSkill()" data-i18n="skills.download">\u2B07 Download</button>
|
|
829
854
|
<button class="btn btn-icon" onclick="closeSkillDetail()" title="Close">\u2715</button>
|
|
830
855
|
</div>
|
|
@@ -1269,6 +1294,11 @@ const I18N={
|
|
|
1269
1294
|
'skills.total':'Total Skills',
|
|
1270
1295
|
'skills.active':'Active',
|
|
1271
1296
|
'skills.installed':'Installed',
|
|
1297
|
+
'skills.public':'Public',
|
|
1298
|
+
'skills.visibility.public':'Public',
|
|
1299
|
+
'skills.visibility.private':'Private',
|
|
1300
|
+
'skills.setPublic':'Set Public',
|
|
1301
|
+
'skills.setPrivate':'Set Private',
|
|
1272
1302
|
'tasks.total':'Total Tasks',
|
|
1273
1303
|
'tasks.active':'Active',
|
|
1274
1304
|
'tasks.completed':'Completed',
|
|
@@ -1307,6 +1337,10 @@ const I18N={
|
|
|
1307
1337
|
'filter.command':'Command',
|
|
1308
1338
|
'filter.newest':'Newest first',
|
|
1309
1339
|
'filter.oldest':'Oldest first',
|
|
1340
|
+
'filter.allowners':'All owners',
|
|
1341
|
+
'filter.public':'Public',
|
|
1342
|
+
'filter.private':'Private',
|
|
1343
|
+
'filter.allvisibility':'All visibility',
|
|
1310
1344
|
'filter.from':'From',
|
|
1311
1345
|
'filter.to':'To',
|
|
1312
1346
|
'filter.clear':'Clear',
|
|
@@ -1358,6 +1392,8 @@ const I18N={
|
|
|
1358
1392
|
'toast.deleted':'Memory deleted',
|
|
1359
1393
|
'toast.opfail':'Operation failed',
|
|
1360
1394
|
'toast.delfail':'Delete failed',
|
|
1395
|
+
'toast.setPublic':'Set to public',
|
|
1396
|
+
'toast.setPrivate':'Set to private',
|
|
1361
1397
|
'toast.cleared':'All memories cleared',
|
|
1362
1398
|
'toast.clearfail':'Clear failed',
|
|
1363
1399
|
'toast.notfound':'Memory not found in cache',
|
|
@@ -1529,6 +1565,11 @@ const I18N={
|
|
|
1529
1565
|
'skills.total':'技能总数',
|
|
1530
1566
|
'skills.active':'生效中',
|
|
1531
1567
|
'skills.installed':'已安装',
|
|
1568
|
+
'skills.public':'公开',
|
|
1569
|
+
'skills.visibility.public':'公开',
|
|
1570
|
+
'skills.visibility.private':'私有',
|
|
1571
|
+
'skills.setPublic':'设为公开',
|
|
1572
|
+
'skills.setPrivate':'设为私有',
|
|
1532
1573
|
'tasks.total':'任务总数',
|
|
1533
1574
|
'tasks.active':'进行中',
|
|
1534
1575
|
'tasks.completed':'已完成',
|
|
@@ -1567,6 +1608,10 @@ const I18N={
|
|
|
1567
1608
|
'filter.command':'命令',
|
|
1568
1609
|
'filter.newest':'最新优先',
|
|
1569
1610
|
'filter.oldest':'最早优先',
|
|
1611
|
+
'filter.allowners':'所有归属',
|
|
1612
|
+
'filter.public':'公开',
|
|
1613
|
+
'filter.private':'私有',
|
|
1614
|
+
'filter.allvisibility':'所有可见性',
|
|
1570
1615
|
'filter.from':'起始',
|
|
1571
1616
|
'filter.to':'截止',
|
|
1572
1617
|
'filter.clear':'清除',
|
|
@@ -1618,6 +1663,8 @@ const I18N={
|
|
|
1618
1663
|
'toast.deleted':'记忆已删除',
|
|
1619
1664
|
'toast.opfail':'操作失败',
|
|
1620
1665
|
'toast.delfail':'删除失败',
|
|
1666
|
+
'toast.setPublic':'已设为公开',
|
|
1667
|
+
'toast.setPrivate':'已设为私有',
|
|
1621
1668
|
'toast.cleared':'所有记忆已清除',
|
|
1622
1669
|
'toast.clearfail':'清除失败',
|
|
1623
1670
|
'toast.notfound':'缓存中未找到此记忆',
|
|
@@ -2309,6 +2356,8 @@ async function loadSkills(){
|
|
|
2309
2356
|
try{
|
|
2310
2357
|
const params=new URLSearchParams();
|
|
2311
2358
|
if(skillsStatusFilter) params.set('status',skillsStatusFilter);
|
|
2359
|
+
const visFilter=document.getElementById('skillVisibilityFilter')?.value;
|
|
2360
|
+
if(visFilter) params.set('visibility',visFilter);
|
|
2312
2361
|
const r=await fetch('/api/skills?'+params);
|
|
2313
2362
|
const data=await r.json();
|
|
2314
2363
|
|
|
@@ -2316,6 +2365,7 @@ async function loadSkills(){
|
|
|
2316
2365
|
document.getElementById('skillsActiveCount').textContent=formatNum(data.skills.filter(s=>s.status==='active').length);
|
|
2317
2366
|
document.getElementById('skillsDraftCount').textContent=formatNum(data.skills.filter(s=>s.status==='draft').length);
|
|
2318
2367
|
document.getElementById('skillsInstalledCount').textContent=formatNum(data.skills.filter(s=>s.installed).length);
|
|
2368
|
+
document.getElementById('skillsPublicCount').textContent=formatNum(data.skills.filter(s=>s.visibility==='public').length);
|
|
2319
2369
|
|
|
2320
2370
|
if(!data.skills||data.skills.length===0){
|
|
2321
2371
|
list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('skills.empty')+'</div>';
|
|
@@ -2329,12 +2379,14 @@ async function loadSkills(){
|
|
|
2329
2379
|
const statusClass=skill.status==='archived'?'archived':(skill.status==='draft'?'draft':'');
|
|
2330
2380
|
const qs=skill.qualityScore;
|
|
2331
2381
|
const qsBadge=qs!==null&&qs!==undefined?'<span class="skill-badge quality '+(qs>=7?'high':qs>=5?'mid':'low')+'">\\u2605 '+qs.toFixed(1)+'</span>':'';
|
|
2382
|
+
const visBadge=skill.visibility==='public'?'<span class="skill-badge visibility-public">\\u{1F310} '+t('skills.visibility.public')+'</span>':'';
|
|
2332
2383
|
return '<div class="skill-card '+installedClass+' '+statusClass+'" onclick="openSkillDetail(\\''+skill.id+'\\')">'+
|
|
2333
2384
|
'<div class="skill-card-top">'+
|
|
2334
2385
|
'<div class="skill-card-name">\\u{1F9E0} '+esc(skill.name)+'</div>'+
|
|
2335
2386
|
'<div class="skill-card-badges">'+
|
|
2336
2387
|
qsBadge+
|
|
2337
2388
|
'<span class="skill-badge version">v'+skill.version+'</span>'+
|
|
2389
|
+
visBadge+
|
|
2338
2390
|
(skill.installed?'<span class="skill-badge installed">'+t('skills.installed.badge')+'</span>':'')+
|
|
2339
2391
|
'<span class="skill-badge status-'+skill.status+'">'+t('skills.status.'+skill.status)+'</span>'+
|
|
2340
2392
|
'</div>'+
|
|
@@ -2389,15 +2441,29 @@ async function openSkillDetail(skillId){
|
|
|
2389
2441
|
|
|
2390
2442
|
const qs=skill.qualityScore;
|
|
2391
2443
|
const qsBadge=qs!==null&&qs!==undefined?'<span class="meta-item"><span class="skill-badge quality '+(qs>=7?'high':qs>=5?'mid':'low')+'">\\u2605 '+qs.toFixed(1)+'/10</span></span>':'';
|
|
2444
|
+
const visMeta=skill.visibility==='public'?'<span class="meta-item"><span class="skill-badge visibility-public">\\u{1F310} '+t('skills.visibility.public')+'</span></span>':'<span class="meta-item"><span class="skill-badge">\\u{1F512} '+t('skills.visibility.private')+'</span></span>';
|
|
2392
2445
|
document.getElementById('skillDetailMeta').innerHTML=[
|
|
2393
2446
|
'<span class="meta-item"><span class="skill-badge version">v'+skill.version+'</span></span>',
|
|
2394
2447
|
'<span class="meta-item"><span class="skill-badge status-'+skill.status+'">'+t('skills.status.'+skill.status)+'</span></span>',
|
|
2448
|
+
visMeta,
|
|
2395
2449
|
qsBadge,
|
|
2396
2450
|
skill.installed?'<span class="meta-item"><span class="skill-badge installed">'+t('skills.installed.badge')+'</span></span>':'',
|
|
2397
2451
|
'<span class="meta-item">\\u{1F4C5} '+formatTime(skill.createdAt)+'</span>',
|
|
2398
2452
|
'<span class="meta-item">\\u270F '+t('skills.updated')+formatTime(skill.updatedAt)+'</span>',
|
|
2399
2453
|
].filter(Boolean).join('');
|
|
2400
2454
|
|
|
2455
|
+
const visBtn=document.getElementById('skillVisibilityBtn');
|
|
2456
|
+
visBtn.className='skill-vis-btn';
|
|
2457
|
+
if(skill.visibility==='public'){
|
|
2458
|
+
visBtn.textContent='\\u{1F512} '+t('skills.setPrivate');
|
|
2459
|
+
visBtn.classList.add('is-public');
|
|
2460
|
+
visBtn.dataset.vis='public';
|
|
2461
|
+
} else {
|
|
2462
|
+
visBtn.textContent='\\u{1F310} '+t('skills.setPublic');
|
|
2463
|
+
visBtn.classList.add('is-private');
|
|
2464
|
+
visBtn.dataset.vis='private';
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2401
2467
|
document.getElementById('skillDetailDesc').textContent=skill.description;
|
|
2402
2468
|
|
|
2403
2469
|
if(files.length>0){
|
|
@@ -2464,6 +2530,20 @@ function downloadSkill(){
|
|
|
2464
2530
|
window.open('/api/skill/'+currentSkillId+'/download','_blank');
|
|
2465
2531
|
}
|
|
2466
2532
|
|
|
2533
|
+
async function toggleSkillVisibility(){
|
|
2534
|
+
if(!currentSkillId) return;
|
|
2535
|
+
const btn=document.getElementById('skillVisibilityBtn');
|
|
2536
|
+
const newVis=btn.dataset.vis==='public'?'private':'public';
|
|
2537
|
+
try{
|
|
2538
|
+
const r=await fetch('/api/skill/'+currentSkillId+'/visibility',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify({visibility:newVis})});
|
|
2539
|
+
if(!r.ok) throw new Error('Failed: '+r.status);
|
|
2540
|
+
openSkillDetail(currentSkillId);
|
|
2541
|
+
loadSkills();
|
|
2542
|
+
}catch(e){
|
|
2543
|
+
alert('Error: '+e.message);
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2467
2547
|
/* ─── Settings / Config ─── */
|
|
2468
2548
|
async function loadConfig(){
|
|
2469
2549
|
try{
|
|
@@ -2911,6 +2991,16 @@ async function loadStats(){
|
|
|
2911
2991
|
const name=s.session_key.length>20?s.session_key.slice(0,8)+'...'+s.session_key.slice(-8):s.session_key;
|
|
2912
2992
|
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>';
|
|
2913
2993
|
});
|
|
2994
|
+
|
|
2995
|
+
const ownerSel=document.getElementById('filterOwner');
|
|
2996
|
+
if(ownerSel && d.owners && d.owners.length>0){
|
|
2997
|
+
const curVal=ownerSel.value;
|
|
2998
|
+
ownerSel.innerHTML='<option value="">'+t('filter.allowners')+'</option>'+'<option value="public">'+t('filter.public')+'</option>';
|
|
2999
|
+
d.owners.filter(o=>o && o!=='public').forEach(o=>{
|
|
3000
|
+
ownerSel.innerHTML+='<option value="'+o+'">'+o+'</option>';
|
|
3001
|
+
});
|
|
3002
|
+
ownerSel.value=curVal;
|
|
3003
|
+
}
|
|
2914
3004
|
}
|
|
2915
3005
|
|
|
2916
3006
|
function getFilterParams(){
|
|
@@ -2925,6 +3015,8 @@ function getFilterParams(){
|
|
|
2925
3015
|
if(dt) p.set('dateTo',dt);
|
|
2926
3016
|
const sort=document.getElementById('filterSort').value;
|
|
2927
3017
|
if(sort==='oldest') p.set('sort','oldest');
|
|
3018
|
+
const owner=document.getElementById('filterOwner').value;
|
|
3019
|
+
if(owner) p.set('owner',owner);
|
|
2928
3020
|
return p;
|
|
2929
3021
|
}
|
|
2930
3022
|
|
|
@@ -3028,6 +3120,9 @@ function renderMemories(items){
|
|
|
3028
3120
|
const dedupBadge=ds==='duplicate'?'<span class="dedup-badge duplicate">'+t('card.dedupDuplicate')+'</span>':ds==='merged'?'<span class="dedup-badge merged">'+t('card.dedupMerged')+'</span>':'';
|
|
3029
3121
|
const isImported=sid.startsWith('openclaw-import-')||sid.startsWith('openclaw-session-');
|
|
3030
3122
|
const importBadge=isImported?'<span class="import-badge">\u{1F990} '+t('card.imported')+'</span>':'';
|
|
3123
|
+
const ownerVal=m.owner||'agent:main';
|
|
3124
|
+
const isPublicMem=ownerVal==='public';
|
|
3125
|
+
const ownerBadge=isPublicMem?'<span class="owner-badge public">\\u{1F310} '+t('filter.public')+'</span>':'<span class="owner-badge agent">\\u{1F512} '+t('filter.private')+'</span>';
|
|
3031
3126
|
let dedupInfo='';
|
|
3032
3127
|
if(isInactive){
|
|
3033
3128
|
const reason=m.dedup_reason?'<span style="font-size:11px;color:var(--text-muted)">'+t('card.dedupReason')+esc(m.dedup_reason)+'</span>':'';
|
|
@@ -3052,7 +3147,7 @@ function renderMemories(items){
|
|
|
3052
3147
|
}catch(e){}
|
|
3053
3148
|
}
|
|
3054
3149
|
return '<div class="memory-card'+(isInactive?' dedup-inactive':'')+'">'+
|
|
3055
|
-
'<div class="card-header"><div class="meta"><span class="role-tag '+role+'">'+role+'</span><span class="kind-tag">'+kind+'</span>'+importBadge+dedupBadge+mergeBadge+'</div><span class="card-time"><span class="session-tag" title="'+esc(sid)+'">'+esc(sidShort)+'</span> '+time+updatedAt+'</span></div>'+
|
|
3150
|
+
'<div class="card-header"><div class="meta"><span class="role-tag '+role+'">'+role+'</span><span class="kind-tag">'+kind+'</span>'+ownerBadge+importBadge+dedupBadge+mergeBadge+'</div><span class="card-time"><span class="session-tag" title="'+esc(sid)+'">'+esc(sidShort)+'</span> '+time+updatedAt+'</span></div>'+
|
|
3056
3151
|
'<div class="card-summary">'+summary+'</div>'+
|
|
3057
3152
|
dedupInfo+
|
|
3058
3153
|
'<div class="card-content" id="content-'+id+'"><pre>'+content+'</pre></div>'+
|
|
@@ -3061,6 +3156,7 @@ function renderMemories(items){
|
|
|
3061
3156
|
'<button class="btn btn-sm btn-ghost" onclick="toggleContent(\\''+id+'\\')">'+t('card.expand')+'</button>'+
|
|
3062
3157
|
(mc>0?'<button class="btn btn-sm btn-ghost" onclick="toggleHistory(\\''+id+'\\')">'+t('card.evolveHistory')+'</button>':'')+
|
|
3063
3158
|
'<button class="btn btn-sm btn-ghost" onclick="openEditModal(\\''+id+'\\')">'+t('card.edit')+'</button>'+
|
|
3159
|
+
(isPublicMem?'<button class="btn btn-sm btn-ghost" onclick="toggleMemoryPublic(\\''+id+'\\',false)">\\u{1F512} '+t('skills.setPrivate')+'</button>':'<button class="btn btn-sm btn-ghost mem-public-btn" onclick="toggleMemoryPublic(\\''+id+'\\',true)">\\u{1F310} '+t('skills.setPublic')+'</button>')+
|
|
3064
3160
|
'<button class="btn btn-sm btn-ghost" style="color:var(--accent)" onclick="deleteMemory(\\''+id+'\\')">'+t('card.delete')+'</button>'+
|
|
3065
3161
|
vscore+
|
|
3066
3162
|
'</div></div>';
|
|
@@ -3249,6 +3345,16 @@ async function deleteMemory(id){
|
|
|
3249
3345
|
else{toast(t('toast.delfail'),'error')}
|
|
3250
3346
|
}
|
|
3251
3347
|
|
|
3348
|
+
async function toggleMemoryPublic(id,setPublic){
|
|
3349
|
+
const newOwner=setPublic?'public':'agent:main';
|
|
3350
|
+
try{
|
|
3351
|
+
const r=await fetch('/api/memory/'+id,{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify({owner:newOwner})});
|
|
3352
|
+
const d=await r.json();
|
|
3353
|
+
if(d.ok){toast(setPublic?t('toast.setPublic'):t('toast.setPrivate'),'success');loadAll();}
|
|
3354
|
+
else{toast(d.error||t('toast.opfail'),'error')}
|
|
3355
|
+
}catch(e){toast('Error: '+e.message,'error')}
|
|
3356
|
+
}
|
|
3357
|
+
|
|
3252
3358
|
async function clearAll(){
|
|
3253
3359
|
if(!confirm(t('confirm.clearall')))return;
|
|
3254
3360
|
if(!confirm(t('confirm.clearall2')))return;
|
package/src/viewer/server.ts
CHANGED
|
@@ -198,6 +198,7 @@ export class ViewerServer {
|
|
|
198
198
|
else if (p === "/api/skills" && req.method === "GET") this.serveSkills(res, url);
|
|
199
199
|
else if (p.match(/^\/api\/skill\/[^/]+\/download$/) && req.method === "GET") this.serveSkillDownload(res, p);
|
|
200
200
|
else if (p.match(/^\/api\/skill\/[^/]+\/files$/) && req.method === "GET") this.serveSkillFiles(res, p);
|
|
201
|
+
else if (p.match(/^\/api\/skill\/[^/]+\/visibility$/) && req.method === "PUT") this.handleSkillVisibility(req, res, p);
|
|
201
202
|
else if (p.startsWith("/api/skill/") && req.method === "GET") this.serveSkillDetail(res, p);
|
|
202
203
|
else if (p === "/api/memory" && req.method === "POST") this.handleCreate(req, res);
|
|
203
204
|
else if (p.startsWith("/api/memory/") && req.method === "GET") this.serveMemoryDetail(res, p);
|
|
@@ -344,6 +345,7 @@ export class ViewerServer {
|
|
|
344
345
|
const kind = url.searchParams.get("kind") ?? undefined;
|
|
345
346
|
const dateFrom = url.searchParams.get("dateFrom") ?? undefined;
|
|
346
347
|
const dateTo = url.searchParams.get("dateTo") ?? undefined;
|
|
348
|
+
const owner = url.searchParams.get("owner") ?? undefined;
|
|
347
349
|
const sortBy = url.searchParams.get("sort") === "oldest" ? "ASC" : "DESC";
|
|
348
350
|
|
|
349
351
|
const db = (this.store as any).db;
|
|
@@ -352,6 +354,7 @@ export class ViewerServer {
|
|
|
352
354
|
if (session) { conditions.push("session_key = ?"); params.push(session); }
|
|
353
355
|
if (role) { conditions.push("role = ?"); params.push(role); }
|
|
354
356
|
if (kind) { conditions.push("kind = ?"); params.push(kind); }
|
|
357
|
+
if (owner) { conditions.push("owner = ?"); params.push(owner); }
|
|
355
358
|
if (dateFrom) { conditions.push("created_at >= ?"); params.push(new Date(dateFrom).getTime()); }
|
|
356
359
|
if (dateTo) { conditions.push("created_at <= ?"); params.push(new Date(dateTo).getTime()); }
|
|
357
360
|
|
|
@@ -486,6 +489,12 @@ export class ViewerServer {
|
|
|
486
489
|
dedupBreakdown = Object.fromEntries(dedupRows.map((d: any) => [d.dedup_status ?? "active", d.count]));
|
|
487
490
|
} catch { /* column may not exist yet */ }
|
|
488
491
|
|
|
492
|
+
let owners: string[] = [];
|
|
493
|
+
try {
|
|
494
|
+
const ownerRows = db.prepare("SELECT DISTINCT owner FROM chunks WHERE owner IS NOT NULL ORDER BY owner").all() as any[];
|
|
495
|
+
owners = ownerRows.map((o: any) => o.owner);
|
|
496
|
+
} catch { /* column may not exist yet */ }
|
|
497
|
+
|
|
489
498
|
this.jsonResponse(res, {
|
|
490
499
|
totalMemories: total.count, totalSessions: sessions.count, totalEmbeddings: embCount,
|
|
491
500
|
totalSkills: skillCount,
|
|
@@ -495,6 +504,7 @@ export class ViewerServer {
|
|
|
495
504
|
dedupBreakdown,
|
|
496
505
|
timeRange: { earliest: timeRange.earliest, latest: timeRange.latest },
|
|
497
506
|
sessions: sessionList,
|
|
507
|
+
owners,
|
|
498
508
|
});
|
|
499
509
|
} catch (e) {
|
|
500
510
|
this.log.warn(`stats error: ${e}`);
|
|
@@ -571,7 +581,11 @@ export class ViewerServer {
|
|
|
571
581
|
|
|
572
582
|
private serveSkills(res: http.ServerResponse, url: URL): void {
|
|
573
583
|
const status = url.searchParams.get("status") ?? undefined;
|
|
574
|
-
const
|
|
584
|
+
const visibility = url.searchParams.get("visibility") ?? undefined;
|
|
585
|
+
let skills = this.store.listSkills({ status });
|
|
586
|
+
if (visibility) {
|
|
587
|
+
skills = skills.filter(s => s.visibility === visibility);
|
|
588
|
+
}
|
|
575
589
|
this.jsonResponse(res, { skills });
|
|
576
590
|
}
|
|
577
591
|
|
|
@@ -697,6 +711,34 @@ export class ViewerServer {
|
|
|
697
711
|
}
|
|
698
712
|
}
|
|
699
713
|
|
|
714
|
+
private handleSkillVisibility(req: http.IncomingMessage, res: http.ServerResponse, urlPath: string): void {
|
|
715
|
+
const segments = urlPath.split("/");
|
|
716
|
+
const skillId = segments[segments.length - 2];
|
|
717
|
+
this.readBody(req, (body) => {
|
|
718
|
+
try {
|
|
719
|
+
const parsed = JSON.parse(body);
|
|
720
|
+
const visibility = parsed.visibility;
|
|
721
|
+
if (visibility !== "public" && visibility !== "private") {
|
|
722
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
723
|
+
res.end(JSON.stringify({ error: `visibility must be 'public' or 'private', got: '${visibility}'` }));
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
const skill = this.store.getSkill(skillId);
|
|
727
|
+
if (!skill) {
|
|
728
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
729
|
+
res.end(JSON.stringify({ error: `Skill not found: ${skillId}` }));
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
this.store.setSkillVisibility(skillId, visibility);
|
|
733
|
+
this.jsonResponse(res, { ok: true, skillId, visibility });
|
|
734
|
+
} catch (err) {
|
|
735
|
+
this.log.error(`handleSkillVisibility error: skillId=${skillId}, body=${body}, err=${err}`);
|
|
736
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
737
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
|
|
700
742
|
// ─── CRUD ───
|
|
701
743
|
|
|
702
744
|
private handleCreate(req: http.IncomingMessage, res: http.ServerResponse): void {
|
|
@@ -710,7 +752,8 @@ export class ViewerServer {
|
|
|
710
752
|
id, sessionKey: data.session_key || "manual", turnId: `manual-${now}`, seq: 0,
|
|
711
753
|
role: data.role || "user", content: data.content || "", kind: data.kind || "paragraph",
|
|
712
754
|
summary: data.summary || data.content?.slice(0, 100) || "",
|
|
713
|
-
taskId: null, skillId: null,
|
|
755
|
+
taskId: null, skillId: null, owner: data.owner || "agent:main",
|
|
756
|
+
dedupStatus: "active", dedupTarget: null, dedupReason: null,
|
|
714
757
|
mergeCount: 0, lastHitAt: null, mergeHistory: "[]",
|
|
715
758
|
createdAt: now, updatedAt: now, embedding: null,
|
|
716
759
|
});
|
|
@@ -741,7 +784,7 @@ export class ViewerServer {
|
|
|
741
784
|
this.readBody(req, (body) => {
|
|
742
785
|
try {
|
|
743
786
|
const data = JSON.parse(body);
|
|
744
|
-
const ok = this.store.updateChunk(chunkId, { summary: data.summary, content: data.content, role: data.role, kind: data.kind });
|
|
787
|
+
const ok = this.store.updateChunk(chunkId, { summary: data.summary, content: data.content, role: data.role, kind: data.kind, owner: data.owner });
|
|
745
788
|
if (ok) this.jsonResponse(res, { ok: true, message: "Memory updated" });
|
|
746
789
|
else { res.writeHead(404, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Not found" })); }
|
|
747
790
|
} catch (err) {
|
|
@@ -1227,6 +1270,7 @@ export class ViewerServer {
|
|
|
1227
1270
|
embedding: null,
|
|
1228
1271
|
taskId: null,
|
|
1229
1272
|
skillId: null,
|
|
1273
|
+
owner: `agent:${agentId}`,
|
|
1230
1274
|
dedupStatus,
|
|
1231
1275
|
dedupTarget,
|
|
1232
1276
|
dedupReason,
|
|
@@ -1420,6 +1464,7 @@ export class ViewerServer {
|
|
|
1420
1464
|
embedding: null,
|
|
1421
1465
|
taskId: null,
|
|
1422
1466
|
skillId: null,
|
|
1467
|
+
owner: "agent:main",
|
|
1423
1468
|
dedupStatus,
|
|
1424
1469
|
dedupTarget,
|
|
1425
1470
|
dedupReason,
|