mcp-memory-bucket 0.8.5 → 0.8.7
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.
|
@@ -1745,7 +1745,7 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1745
1745
|
cursor: pointer;
|
|
1746
1746
|
}
|
|
1747
1747
|
.bulk-bar button.danger { border-color: var(--danger); color: var(--danger); }
|
|
1748
|
-
`}#e=Ui();#t=new u(this.#e.query??"");#s=new u(this.#e.typeFilter??"all");#n=new u(this.#e.activeTags??[]);#r=new u(this.#e.activeFolders??[]);#g=new u([]);#a=new u(Oi);#i=new u(null);#l=new u(Di);#u=new u(!1);#h=new u("");#d=new u(!1);#o=new u(Mi());#f=new u("");#b=new u(!1);#k=new u(this.#e.sort??"mtime_desc");#x=new u(this.#e.deprecatedFilter??"all");#y=new u(this.#e.pausedFilter??"all");#v=new u(this.#e.dateFrom??"");#m=new u(this.#e.dateTo??"");#p=new u(new Set);#$=new u(qi());#w=new u(!1);#_=new u("entries");#P=new u([]);#A=new u(null);#R=new u(null);#T=new u(!1);#z=e=>this.#N(e);#L=()=>this.#q();constructor(){super(),new ce(this),pt(this.#$.value)}#F(e){this.#$.set(e),localStorage.setItem(Dt,e),pt(e)}#I(){const e=ge[(ge.indexOf(this.#$.value)+1)%ge.length];this.#F(e)}async#O(){if(!this.#w.value){this.#w.set(!0);try{await fetch("/api/rebuild-cache",{method:"POST"}),await Promise.all([this.#C(),this.#S(),this.#c()])}finally{this.#w.set(!1)}}}#D(e){e.preventDefault(),this.#b.set(!0),document.addEventListener("pointermove",this.#z),document.addEventListener("pointerup",this.#L)}#N(e){const t=this.renderRoot.querySelector(".body-region");if(!t)return;const s=t.getBoundingClientRect(),i=(e.clientX-s.left)/s.width*100;this.#o.set(Math.min(Ot,Math.max(It,i)))}#q(){this.#b.set(!1),document.removeEventListener("pointermove",this.#z),document.removeEventListener("pointerup",this.#L),localStorage.setItem(Lt,String(this.#o.value))}#U=new us(()=>{const e=new URLSearchParams;this.#s.value!=="all"&&e.set("type",this.#s.value),this.#t.value.trim()&&e.set("q",this.#t.value.trim());for(const t of this.#n.value)e.append("tag",t);for(const t of this.#r.value)e.append("folder",t);return this.#k.value!=="mtime_desc"&&e.set("sort",this.#k.value),this.#x.value==="hide"?e.set("deprecated","0"):this.#x.value==="only"&&e.set("deprecated","1"),this.#y.value==="hide"?e.set("paused","0"):this.#y.value==="only"&&e.set("paused","1"),this.#v.value&&e.set("date_from",this.#v.value),this.#m.value&&e.set("date_to",this.#m.value),e.toString()});#E=()=>this.#
|
|
1748
|
+
`}#e=Ui();#t=new u(this.#e.query??"");#s=new u(this.#e.typeFilter??"all");#n=new u(this.#e.activeTags??[]);#r=new u(this.#e.activeFolders??[]);#g=new u([]);#a=new u(Oi);#i=new u(null);#l=new u(Di);#u=new u(!1);#h=new u("");#d=new u(!1);#o=new u(Mi());#f=new u("");#b=new u(!1);#k=new u(this.#e.sort??"mtime_desc");#x=new u(this.#e.deprecatedFilter??"all");#y=new u(this.#e.pausedFilter??"all");#v=new u(this.#e.dateFrom??"");#m=new u(this.#e.dateTo??"");#p=new u(new Set);#$=new u(qi());#w=new u(!1);#_=new u("entries");#P=new u([]);#A=new u(null);#R=new u(null);#T=new u(!1);#z=e=>this.#N(e);#L=()=>this.#q();constructor(){super(),new ce(this),pt(this.#$.value)}#F(e){this.#$.set(e),localStorage.setItem(Dt,e),pt(e)}#I(){const e=ge[(ge.indexOf(this.#$.value)+1)%ge.length];this.#F(e)}async#O(){if(!this.#w.value){this.#w.set(!0);try{await fetch("/api/rebuild-cache",{method:"POST"}),await Promise.all([this.#C(),this.#S(),this.#c()])}finally{this.#w.set(!1)}}}#D(e){e.preventDefault(),this.#b.set(!0),document.addEventListener("pointermove",this.#z),document.addEventListener("pointerup",this.#L)}#N(e){const t=this.renderRoot.querySelector(".body-region");if(!t)return;const s=t.getBoundingClientRect(),i=(e.clientX-s.left)/s.width*100;this.#o.set(Math.min(Ot,Math.max(It,i)))}#q(){this.#b.set(!1),document.removeEventListener("pointermove",this.#z),document.removeEventListener("pointerup",this.#L),localStorage.setItem(Lt,String(this.#o.value))}#U=new us(()=>{const e=new URLSearchParams;this.#s.value!=="all"&&e.set("type",this.#s.value),this.#t.value.trim()&&e.set("q",this.#t.value.trim());for(const t of this.#n.value)e.append("tag",t);for(const t of this.#r.value)e.append("folder",t);return this.#k.value!=="mtime_desc"&&e.set("sort",this.#k.value),this.#x.value==="hide"?e.set("deprecated","0"):this.#x.value==="only"&&e.set("deprecated","1"),this.#y.value==="hide"?e.set("paused","0"):this.#y.value==="only"&&e.set("paused","1"),this.#v.value&&e.set("date_from",this.#v.value),this.#m.value&&e.set("date_to",this.#m.value),e.toString()});#E=()=>this.#Q();#M=e=>this.#ie(e);#K=e=>this.#re(e);#Z=()=>this.#V();#W;connectedCallback(){super.connectedCallback(),this.#c(),this.#S(),this.#C().then(()=>this.#Q()),window.addEventListener("focus",this.#E),document.addEventListener("visibilitychange",this.#E),document.addEventListener("folderfoo-file-open",this.#M),document.addEventListener("folderfoo-folder-changed",this.#K),window.addEventListener("folderfoo-auth-change",this.#Z),this.#ne(),this.#V(),Li(),this.#W=zt.subscribe(()=>this.#C())}async#ie(e){const t=e.detail?.name;if(!t)return;const s=zi(t);if(s.owner){this.#f.set(`"${s.name}" is from a shared folder — opening shared files here isn't supported yet.`);return}const{folderfooMode:i,folderfooHost:n}=await W();if(!(i==="off"||!n))try{const o=await fetch("/api/folderfoo/resolve-open",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({server:n,tenantId:oe,folderPath:s.folderPath,name:s.name})}),a=await o.json();if(!o.ok){this.#f.set(a.error??`couldn't open "${s.name}"`);return}this.#f.set(""),this.#i.set({table:a.table,id:a.id})}catch(o){this.#f.set(o.message)}}async#re(e){const{path:t,action:s,newPath:i}=e.detail??{};if(!(t===void 0||!s)){if((s==="rename"||s==="move")&&i){const{folderfooHost:n}=await W();if(!n)return;try{await fetch("/api/folders/renamed",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({server:n,oldPath:t,newPath:i})})}catch{}}this.#C()}}async#ne(){if(this.shadowRoot?.querySelector("folderfoo-profile-circle"))return;const{folderfooMode:e,folderfooHost:t}=await W();e==="off"||!t||ut(()=>import(`${t}/elements/folderfoo-profile-circle.js`),[]).then(async()=>{await this.updateComplete;const s=document.createElement("folderfoo-profile-circle");s.setAttribute("app-name","Memory Bucket"),s.setAttribute("tenant-id",oe),s.style.zoom="0.875",this.shadowRoot?.querySelector(".folderfoo-slot")?.appendChild(s)}).catch(s=>{console.warn("folderfoo-profile-circle unavailable:",s.message)})}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("focus",this.#E),document.removeEventListener("visibilitychange",this.#E),document.removeEventListener("folderfoo-file-open",this.#M),document.removeEventListener("folderfoo-folder-changed",this.#K),window.removeEventListener("folderfoo-auth-change",this.#Z),this.#W?.()}async#V(){let e=null;try{e=localStorage.getItem("folderfoo_token")}catch{return}if(!e){fetch("/api/folderfoo/logout",{method:"POST"}).catch(()=>{});return}const{folderfooMode:t,folderfooHost:s}=await W();t==="off"||!s||fetch("/api/folderfoo/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({server:s,token:e})}).catch(()=>{})}#j=!1;async#Q(){if(document.visibilityState==="visible"){if(this.#X().some(e=>e.remote)&&!this.#j){this.#j=!0;try{await fetch("/api/remote-folders/resync-all",{method:"POST"})}catch{}finally{this.#j=!1}}this.#c(),this.#S(),this.#C(),this.renderRoot.querySelector("detail-panel")?.refresh?.()}}async#c(){const e=this.#U.value;history.replaceState(null,"",e?`#${e}`:location.pathname+location.search);const t=await fetch(`/api/entries?${e}`);this.#g.set(await t.json()),this.renderRoot.querySelector("result-list")?.scrollTo(0,0)}async#S(){const e=this.#s.value==="all"?"":`?type=${this.#s.value}`,t=await fetch(`/api/facets${e}`);this.#a.set(await t.json())}async#C(){const t=await(await fetch("/api/folders")).json();this.#l.set(t),this.#d.set(!0);const s=new Set([...t.skill,...t.memory].map(n=>n.name)),i=this.#r.value.filter(n=>s.has(n));i.length!==this.#r.value.length&&(this.#r.set(i),this.#c())}#oe(e){this.#_.set(e),e==="channels"&&this.#J()}async#J(){const e=await fetch("/api/channels");this.#P.set(await e.json()),this.#A.value&&this.#Y(this.#A.value)}async#Y(e){this.#A.set(e),this.#T.set(!0);try{const t=await fetch(`/api/channels/${encodeURIComponent(e)}`);this.#R.set(t.ok?await t.json():null)}finally{this.#T.set(!1)}}#ae(e){const t=this.#r.value;this.#r.set(t.includes(e)?t.filter(s=>s!==e):[...t,e]),this.#c()}async#le(e,t){if(t.stopPropagation(),window.prompt(`Type "${e.name}" to remove this ${e.kind} folder (files on disk are untouched):`)===e.name){this.#h.set(e.name);try{await fetch(`/api/folders/${e.kind}/${encodeURIComponent(e.name)}`,{method:"DELETE"}),this.#r.set(this.#r.value.filter(i=>i!==e.name)),await Promise.all([this.#C(),this.#S(),this.#c()])}finally{this.#h.set("")}}}#G(){this.#u.set(!1),this.#C(),this.#S(),this.#c()}#X(){return[...this.#l.value.skill,...this.#l.value.memory].sort((e,t)=>Number(e.remote)-Number(t.remote))}#ce(e){this.#s.set(e),this.#n.set([]),this.#S(),this.#c()}#he(e){const t=this.#n.value;this.#n.set(t.includes(e)?t.filter(s=>s!==e):[...t,e]),this.#c()}#de(e){this.#n.value.includes(e)||this.#n.set([...this.#n.value,e]),this.#c()}#pe(e){this.#r.value.includes(e)||this.#r.set([...this.#r.value,e]),this.#c()}#ue(e){this.#v.set(e),this.#m.set(e),this.#c()}#fe(e){this.#t.set(e.target.value),this.#c()}#ee(e){this.#t.set(e),this.#c()}#ge(){this.#t.set(""),this.#c()}#be(e){this.#i.set({table:e._table,id:e.id})}#me(e){this.#k.set(e.target.value),this.#c()}#xe(e){this.#x.set(e.target.value),this.#c()}#ve(e){this.#y.set(e.target.value),this.#c()}#ye(e){this.#v.set(e.target.value),this.#c()}#ke(e){this.#m.set(e.target.value),this.#c()}#$e(){this.#v.set(""),this.#m.set(""),this.#c()}#we(e){const t=new Set(this.#p.value);t.has(e.id)?t.delete(e.id):t.add(e.id),this.#p.set(t)}#_e(){return new Map(this.#g.value.map(e=>[e.id,e]))}#H(){const e=new Map,t=this.#_e();for(const s of this.#p.value){const i=t.get(s);if(!i)continue;const n=e.get(i._table)??[];n.push(s),e.set(i._table,n)}return e}async#te(e){const t=this.#H();await Promise.all([...t.entries()].map(([s,i])=>fetch(`/api/entries/${s}/bulk/deprecated`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({ids:i,deprecated:e})}))),this.#p.set(new Set),await this.#c()}async#se(e){const t=this.#H();await Promise.all([...t.entries()].map(([s,i])=>fetch(`/api/entries/${s}/bulk/paused`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({ids:i,paused:e})}))),this.#p.set(new Set),await this.#c()}async#Se(){if(!window.confirm(`Delete ${this.#p.value.size} doc(s)? This can't be undone.`))return;const e=this.#H();await Promise.all([...e.entries()].map(([t,s])=>fetch(`/api/entries/${t}/bulk/delete`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({ids:s})}))),this.#p.set(new Set),await this.#c()}#Ce(){const e=this.#$.value;return c`
|
|
1749
1749
|
<button
|
|
1750
1750
|
class="theme-toggle"
|
|
1751
1751
|
title=${`Theme: ${Ni[e]} (click to change)`}
|
|
@@ -1779,15 +1779,15 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1779
1779
|
${this.#Ce()}
|
|
1780
1780
|
<div class="folderfoo-slot"></div>
|
|
1781
1781
|
</div>
|
|
1782
|
-
`}render(){const e=this.#a.value,t=this.#
|
|
1782
|
+
`}render(){const e=this.#a.value,t=this.#X();return this.#_.value==="channels"?c`
|
|
1783
1783
|
<div class="toolbar-bar">${this.#B(!1)}</div>
|
|
1784
1784
|
<channel-view
|
|
1785
1785
|
.channels=${this.#P.value}
|
|
1786
1786
|
.selected=${this.#A.value}
|
|
1787
1787
|
.detail=${this.#R.value}
|
|
1788
1788
|
.loading=${this.#T.value}
|
|
1789
|
-
.onSelect=${s=>this.#
|
|
1790
|
-
.onRefresh=${()=>this.#
|
|
1789
|
+
.onSelect=${s=>this.#Y(s)}
|
|
1790
|
+
.onRefresh=${()=>this.#J()}
|
|
1791
1791
|
></channel-view>
|
|
1792
1792
|
`:this.#d.value&&t.length===0&&!this.#u.value?c`
|
|
1793
1793
|
<div class="toolbar-bar">${this.#B(!1)}</div>
|
|
@@ -1802,7 +1802,7 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1802
1802
|
${this.#u.value?c`<add-folder-modal
|
|
1803
1803
|
.defaultKind=${"skill"}
|
|
1804
1804
|
.lockKind=${!1}
|
|
1805
|
-
.onAdded=${()=>this.#
|
|
1805
|
+
.onAdded=${()=>this.#G()}
|
|
1806
1806
|
.onCancel=${()=>this.#u.set(!1)}
|
|
1807
1807
|
></add-folder-modal>`:""}
|
|
1808
1808
|
`:c`
|
|
@@ -1919,10 +1919,10 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1919
1919
|
${this.#p.value.size>0?c`
|
|
1920
1920
|
<div class="bulk-bar">
|
|
1921
1921
|
<span>${this.#p.value.size} selected</span>
|
|
1922
|
-
<button @click=${()=>this.#
|
|
1923
|
-
<button @click=${()=>this.#
|
|
1924
|
-
<button @click=${()=>this.#
|
|
1925
|
-
<button @click=${()=>this.#
|
|
1922
|
+
<button @click=${()=>this.#te(!0)}>Mark deprecated</button>
|
|
1923
|
+
<button @click=${()=>this.#te(!1)}>Un-deprecate</button>
|
|
1924
|
+
<button @click=${()=>this.#se(!0)}>Pause</button>
|
|
1925
|
+
<button @click=${()=>this.#se(!1)}>Resume</button>
|
|
1926
1926
|
<button class="danger" @click=${()=>this.#Se()}>Delete</button>
|
|
1927
1927
|
<button @click=${()=>this.#p.set(new Set)}>Clear</button>
|
|
1928
1928
|
</div>
|
|
@@ -1935,7 +1935,7 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1935
1935
|
.onSelect=${s=>this.#be(s)}
|
|
1936
1936
|
.selectedIds=${this.#p.value}
|
|
1937
1937
|
.onToggleSelect=${s=>this.#we(s)}
|
|
1938
|
-
.onKeyClick=${s=>this.#
|
|
1938
|
+
.onKeyClick=${s=>this.#ee(s)}
|
|
1939
1939
|
></result-list>
|
|
1940
1940
|
<div
|
|
1941
1941
|
class="splitter ${this.#b.value?"dragging":""}"
|
|
@@ -1948,13 +1948,13 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1948
1948
|
.onTagClick=${s=>this.#de(s)}
|
|
1949
1949
|
.onFolderClick=${s=>this.#pe(s)}
|
|
1950
1950
|
.onDateClick=${s=>this.#ue(s)}
|
|
1951
|
-
.onKeyClick=${s=>this.#
|
|
1951
|
+
.onKeyClick=${s=>this.#ee(s)}
|
|
1952
1952
|
></detail-panel>
|
|
1953
1953
|
</div>
|
|
1954
1954
|
${this.#u.value?c`<add-folder-modal
|
|
1955
1955
|
.defaultKind=${"skill"}
|
|
1956
1956
|
.lockKind=${!1}
|
|
1957
|
-
.onAdded=${()=>this.#
|
|
1957
|
+
.onAdded=${()=>this.#G()}
|
|
1958
1958
|
.onCancel=${()=>this.#u.set(!1)}
|
|
1959
1959
|
></add-folder-modal>`:""}
|
|
1960
1960
|
`}}customElements.define("mem-bucket-app",ji);
|
package/dist/client/index.html
CHANGED
package/dist/src/server.js
CHANGED
|
@@ -64,6 +64,14 @@ const attachmentRepo = new AttachmentRepository(memoryRepo, skillRepo);
|
|
|
64
64
|
// same upsertFile/removeFile path a local file-watch event would.
|
|
65
65
|
const remoteSkillPoller = config.remoteSkillFolders.length > 0 ? startRemotePolling(db, skillSpec, config.remoteSkillFolders, config.baseDir) : undefined;
|
|
66
66
|
const remoteMemoryPoller = config.remoteMemoryFolders.length > 0 ? startRemotePolling(db, memorySpec, config.remoteMemoryFolders, config.baseDir) : undefined;
|
|
67
|
+
// Forces one immediate poll of every remote source at process start, instead
|
|
68
|
+
// of leaving the cache to show whatever was last synced until the first
|
|
69
|
+
// fixed interval tick (up to POLL_INTERVAL_MS later) - this is effectively
|
|
70
|
+
// "login" for a background server: a fresh process (laptop wake, editor
|
|
71
|
+
// reopened) is exactly when another device's writes are most likely to be
|
|
72
|
+
// unseen locally yet.
|
|
73
|
+
remoteSkillPoller?.resyncAll().catch((err) => console.error('[memory-bucket] initial remote skill resync failed:', err));
|
|
74
|
+
remoteMemoryPoller?.resyncAll().catch((err) => console.error('[memory-bucket] initial remote memory resync failed:', err));
|
|
67
75
|
if (config.skillFolders.length === 0 && config.memoryFolders.length === 0) {
|
|
68
76
|
console.error(`[memory-bucket] no folders configured — open http://localhost:${PORT} to add one`);
|
|
69
77
|
}
|
package/dist/src/web/routes.js
CHANGED
|
@@ -840,6 +840,12 @@ export function buildWebRouter(db, config, skillRepo, memoryRepo, skillSpec, mem
|
|
|
840
840
|
// already-stamped entries become visible.
|
|
841
841
|
identity.setUsername(decodeUsername(token));
|
|
842
842
|
res.json({ connected: true, server });
|
|
843
|
+
// Force-resyncs every remote source now that this identity's folders are
|
|
844
|
+
// visible again, rather than leaving them showing whatever was last
|
|
845
|
+
// synced until the next fixed poll tick or tab-focus resync. Fired after
|
|
846
|
+
// responding (best-effort, same posture as the rest of this route) so
|
|
847
|
+
// login doesn't wait on a round trip to every remote source.
|
|
848
|
+
Promise.all([remotePollers?.skill?.resyncAll(), remotePollers?.memory?.resyncAll()]).catch(() => { });
|
|
843
849
|
});
|
|
844
850
|
// Signals that the browser's folderfoo login session just ended (the page
|
|
845
851
|
// detects folderfoo's own auth-change event going to logged-out) - clears
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-memory-bucket",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server exposing skill_* (reusable coding patterns) and memory_* (point-in-time working context) tools over a markdown+frontmatter source, cached into SQLite at runtime.",
|
|
6
6
|
"repository": {
|