mcp-memory-bucket 0.5.5 → 0.6.0
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/dist/client/assets/{index-DEOIrixV.js → index-PIigsGBG.js} +139 -67
- package/dist/client/index.html +1 -1
- package/dist/src/attachments/repository.js +78 -0
- package/dist/src/attachments/storage.js +67 -0
- package/dist/src/attachments/tools.js +85 -0
- package/dist/src/attachments/types.js +1 -0
- package/dist/src/config.js +3 -0
- package/dist/src/memory/repository.js +6 -0
- package/dist/src/server.js +4 -0
- package/dist/src/skills/repository.js +1 -0
- package/dist/src/store/db.js +4 -0
- package/dist/src/store/sync.js +8 -4
- package/dist/src/web/routes.js +46 -2
- package/package.json +1 -1
|
@@ -6,18 +6,18 @@
|
|
|
6
6
|
* @license
|
|
7
7
|
* Copyright 2017 Google LLC
|
|
8
8
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
9
|
-
*/const{is:Lt,defineProperty:Dt,getOwnPropertyDescriptor:It,getOwnPropertyNames:Ot,getOwnPropertySymbols:Mt,getPrototypeOf:Nt}=Object,ne=globalThis,Me=ne.trustedTypes,Ft=Me?Me.emptyScript:"",qt=ne.reactiveElementPolyfillSupport,
|
|
9
|
+
*/const{is:Lt,defineProperty:Dt,getOwnPropertyDescriptor:It,getOwnPropertyNames:Ot,getOwnPropertySymbols:Mt,getPrototypeOf:Nt}=Object,ne=globalThis,Me=ne.trustedTypes,Ft=Me?Me.emptyScript:"",qt=ne.reactiveElementPolyfillSupport,W=(r,e)=>r,ue={toAttribute(r,e){switch(e){case Boolean:r=r?Ft:null;break;case Object:case Array:r=r==null?r:JSON.stringify(r)}return r},fromAttribute(r,e){let t=r;switch(e){case Boolean:t=r!==null;break;case Number:t=r===null?null:Number(r);break;case Object:case Array:try{t=JSON.parse(r)}catch{t=null}}return t}},lt=(r,e)=>!Lt(r,e),Ne={attribute:!0,type:String,converter:ue,reflect:!1,useDefault:!1,hasChanged:lt};Symbol.metadata??=Symbol("metadata"),ne.litPropertyMetadata??=new WeakMap;let F=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=Ne){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const s=Symbol(),i=this.getPropertyDescriptor(e,s,t);i!==void 0&&Dt(this.prototype,e,i)}}static getPropertyDescriptor(e,t,s){const{get:i,set:n}=It(this.prototype,e)??{get(){return this[t]},set(a){this[t]=a}};return{get:i,set(a){const o=i?.call(this);n?.call(this,a),this.requestUpdate(e,o,s)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??Ne}static _$Ei(){if(this.hasOwnProperty(W("elementProperties")))return;const e=Nt(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(W("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(W("properties"))){const t=this.properties,s=[...Ot(t),...Mt(t)];for(const i of s)this.createProperty(i,t[i])}const e=this[Symbol.metadata];if(e!==null){const t=litPropertyMetadata.get(e);if(t!==void 0)for(const[s,i]of t)this.elementProperties.set(s,i)}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);i!==void 0&&this._$Eh.set(i,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const s=new Set(e.flat(1/0).reverse());for(const i of s)t.unshift(Oe(i))}else e!==void 0&&t.push(Oe(e));return t}static _$Eu(e,t){const s=t.attribute;return s===!1?void 0:typeof s=="string"?s:typeof e=="string"?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const s of t.keys())this.hasOwnProperty(s)&&(e.set(s,this[s]),delete this[s]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return Pt(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,s){this._$AK(e,s)}_$ET(e,t){const s=this.constructor.elementProperties.get(e),i=this.constructor._$Eu(e,s);if(i!==void 0&&s.reflect===!0){const n=(s.converter?.toAttribute!==void 0?s.converter:ue).toAttribute(t,s.type);this._$Em=e,n==null?this.removeAttribute(i):this.setAttribute(i,n),this._$Em=null}}_$AK(e,t){const s=this.constructor,i=s._$Eh.get(e);if(i!==void 0&&this._$Em!==i){const n=s.getPropertyOptions(i),a=typeof n.converter=="function"?{fromAttribute:n.converter}:n.converter?.fromAttribute!==void 0?n.converter:ue;this._$Em=i;const o=a.fromAttribute(t,n.type);this[i]=o??this._$Ej?.get(i)??o,this._$Em=null}}requestUpdate(e,t,s,i=!1,n){if(e!==void 0){const a=this.constructor;if(i===!1&&(n=this[e]),s??=a.getPropertyOptions(e),!((s.hasChanged??lt)(n,t)||s.useDefault&&s.reflect&&n===this._$Ej?.get(e)&&!this.hasAttribute(a._$Eu(e,s))))return;this.C(e,t,s)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(e,t,{useDefault:s,reflect:i,wrapped:n},a){s&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,a??t??this[e]),n!==!0||a!==void 0)||(this._$AL.has(e)||(this.hasUpdated||s||(t=void 0),this._$AL.set(e,t)),i===!0&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const e=this.scheduleUpdate();return e!=null&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[i,n]of this._$Ep)this[i]=n;this._$Ep=void 0}const s=this.constructor.elementProperties;if(s.size>0)for(const[i,n]of s){const{wrapped:a}=n,o=this[i];a!==!0||this._$AL.has(i)||o===void 0||this.C(i,void 0,n,o)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(s=>s.hostUpdate?.()),this.update(t)):this._$EM()}catch(s){throw e=!1,this._$EM(),s}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(e){}firstUpdated(e){}};F.elementStyles=[],F.shadowRootOptions={mode:"open"},F[W("elementProperties")]=new Map,F[W("finalized")]=new Map,qt?.({ReactiveElement:F}),(ne.reactiveElementVersions??=[]).push("2.1.2");/**
|
|
10
10
|
* @license
|
|
11
11
|
* Copyright 2017 Google LLC
|
|
12
12
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
13
|
-
*/const $e=globalThis,Fe=r=>r,te=$e.trustedTypes,qe=te?te.createPolicy("lit-html",{createHTML:r=>r}):void 0,ct="$lit$",E=`lit$${Math.random().toFixed(9).slice(2)}$`,ht="?"+E,Ut=`<${ht}>`,L=document,
|
|
13
|
+
*/const $e=globalThis,Fe=r=>r,te=$e.trustedTypes,qe=te?te.createPolicy("lit-html",{createHTML:r=>r}):void 0,ct="$lit$",E=`lit$${Math.random().toFixed(9).slice(2)}$`,ht="?"+E,Ut=`<${ht}>`,L=document,Q=()=>L.createComment(""),V=r=>r===null||typeof r!="object"&&typeof r!="function",ye=Array.isArray,Ht=r=>ye(r)||typeof r?.[Symbol.iterator]=="function",he=`[
|
|
14
14
|
\f\r]`,j=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Ue=/-->/g,He=/>/g,R=RegExp(`>|${he}(?:([^\\s"'>=/]+)(${he}*=${he}*(?:[^
|
|
15
|
-
\f\r"'\`<>=]|("|')|))|$)`,"g"),Be=/'/g,je=/"/g,pt=/^(?:script|style|textarea|title)$/i,Bt=r=>(e,...t)=>({_$litType$:r,strings:e,values:t}),h=Bt(1),D=Symbol.for("lit-noChange"),
|
|
15
|
+
\f\r"'\`<>=]|("|')|))|$)`,"g"),Be=/'/g,je=/"/g,pt=/^(?:script|style|textarea|title)$/i,Bt=r=>(e,...t)=>({_$litType$:r,strings:e,values:t}),h=Bt(1),D=Symbol.for("lit-noChange"),b=Symbol.for("lit-nothing"),Ke=new WeakMap,P=L.createTreeWalker(L,129);function dt(r,e){if(!ye(r)||!r.hasOwnProperty("raw"))throw Error("invalid template strings array");return qe!==void 0?qe.createHTML(e):e}const jt=(r,e)=>{const t=r.length-1,s=[];let i,n=e===2?"<svg>":e===3?"<math>":"",a=j;for(let o=0;o<t;o++){const l=r[o];let c,d,p=-1,g=0;for(;g<l.length&&(a.lastIndex=g,d=a.exec(l),d!==null);)g=a.lastIndex,a===j?d[1]==="!--"?a=Ue:d[1]!==void 0?a=He:d[2]!==void 0?(pt.test(d[2])&&(i=RegExp("</"+d[2],"g")),a=R):d[3]!==void 0&&(a=R):a===R?d[0]===">"?(a=i??j,p=-1):d[1]===void 0?p=-2:(p=a.lastIndex-d[2].length,c=d[1],a=d[3]===void 0?R:d[3]==='"'?je:Be):a===je||a===Be?a=R:a===Ue||a===He?a=j:(a=R,i=void 0);const k=a===R&&r[o+1].startsWith("/>")?" ":"";n+=a===j?l+Ut:p>=0?(s.push(c),l.slice(0,p)+ct+l.slice(p)+E+k):l+E+(p===-2?o:k)}return[dt(r,n+(r[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),s]};let ge=class ut{constructor({strings:e,_$litType$:t},s){let i;this.parts=[];let n=0,a=0;const o=e.length-1,l=this.parts,[c,d]=jt(e,t);if(this.el=ut.createElement(c,s),P.currentNode=this.el.content,t===2||t===3){const p=this.el.content.firstChild;p.replaceWith(...p.childNodes)}for(;(i=P.nextNode())!==null&&l.length<o;){if(i.nodeType===1){if(i.hasAttributes())for(const p of i.getAttributeNames())if(p.endsWith(ct)){const g=d[a++],k=i.getAttribute(p).split(E),m=/([.?@])?(.*)/.exec(g);l.push({type:1,index:n,name:m[2],strings:k,ctor:m[1]==="."?Zt:m[1]==="?"?Wt:m[1]==="@"?Qt:ae}),i.removeAttribute(p)}else p.startsWith(E)&&(l.push({type:6,index:n}),i.removeAttribute(p));if(pt.test(i.tagName)){const p=i.textContent.split(E),g=p.length-1;if(g>0){i.textContent=te?te.emptyScript:"";for(let k=0;k<g;k++)i.append(p[k],Q()),P.nextNode(),l.push({type:2,index:++n});i.append(p[g],Q())}}}else if(i.nodeType===8)if(i.data===ht)l.push({type:2,index:n});else{let p=-1;for(;(p=i.data.indexOf(E,p+1))!==-1;)l.push({type:7,index:n}),p+=E.length-1}n++}}static createElement(e,t){const s=L.createElement("template");return s.innerHTML=e,s}};function q(r,e,t=r,s){if(e===D)return e;let i=s!==void 0?t._$Co?.[s]:t._$Cl;const n=V(e)?void 0:e._$litDirective$;return i?.constructor!==n&&(i?._$AO?.(!1),n===void 0?i=void 0:(i=new n(r),i._$AT(r,t,s)),s!==void 0?(t._$Co??=[])[s]=i:t._$Cl=i),i!==void 0&&(e=q(r,i._$AS(r,e.values),i,s)),e}let Kt=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){const{el:{content:t},parts:s}=this._$AD,i=(e?.creationScope??L).importNode(t,!0);P.currentNode=i;let n=P.nextNode(),a=0,o=0,l=s[0];for(;l!==void 0;){if(a===l.index){let c;l.type===2?c=new Y(n,n.nextSibling,this,e):l.type===1?c=new l.ctor(n,l.name,l.strings,this,e):l.type===6&&(c=new Vt(n,this,e)),this._$AV.push(c),l=s[++o]}a!==l?.index&&(n=P.nextNode(),a++)}return P.currentNode=L,i}p(e){let t=0;for(const s of this._$AV)s!==void 0&&(s.strings!==void 0?(s._$AI(e,s,t),t+=s.strings.length-2):s._$AI(e[t])),t++}};class Y{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,s,i){this.type=2,this._$AH=b,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=s,this.options=i,this._$Cv=i?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode;const t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=q(this,e,t),V(e)?e===b||e==null||e===""?(this._$AH!==b&&this._$AR(),this._$AH=b):e!==this._$AH&&e!==D&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Ht(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==b&&V(this._$AH)?this._$AA.nextSibling.data=e:this.T(L.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:s}=e,i=typeof s=="number"?this._$AC(e):(s.el===void 0&&(s.el=ge.createElement(dt(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===i)this._$AH.p(t);else{const n=new Kt(i,this),a=n.u(this.options);n.p(t),this.T(a),this._$AH=n}}_$AC(e){let t=Ke.get(e.strings);return t===void 0&&Ke.set(e.strings,t=new ge(e)),t}k(e){ye(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let s,i=0;for(const n of e)i===t.length?t.push(s=new Y(this.O(Q()),this.O(Q()),this,this.options)):s=t[i],s._$AI(n),i++;i<t.length&&(this._$AR(s&&s._$AB.nextSibling,i),t.length=i)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){const s=Fe(e).nextSibling;Fe(e).remove(),e=s}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}}let ae=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,s,i,n){this.type=1,this._$AH=b,this._$AN=void 0,this.element=e,this.name=t,this._$AM=i,this.options=n,s.length>2||s[0]!==""||s[1]!==""?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=b}_$AI(e,t=this,s,i){const n=this.strings;let a=!1;if(n===void 0)e=q(this,e,t,0),a=!V(e)||e!==this._$AH&&e!==D,a&&(this._$AH=e);else{const o=e;let l,c;for(e=n[0],l=0;l<n.length-1;l++)c=q(this,o[s+l],t,l),c===D&&(c=this._$AH[l]),a||=!V(c)||c!==this._$AH[l],c===b?e=b:e!==b&&(e+=(c??"")+n[l+1]),this._$AH[l]=c}a&&!i&&this.j(e)}j(e){e===b?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"")}},Zt=class extends ae{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===b?void 0:e}},Wt=class extends ae{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==b)}},Qt=class extends ae{constructor(e,t,s,i,n){super(e,t,s,i,n),this.type=5}_$AI(e,t=this){if((e=q(this,e,t,0)??b)===D)return;const s=this._$AH,i=e===b&&s!==b||e.capture!==s.capture||e.once!==s.once||e.passive!==s.passive,n=e!==b&&(s===b||i);i&&this.element.removeEventListener(this.name,this,s),n&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}},Vt=class{constructor(e,t,s){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=s}get _$AU(){return this._$AM._$AU}_$AI(e){q(this,e)}};const Yt=$e.litHtmlPolyfillSupport;Yt?.(ge,Y),($e.litHtmlVersions??=[]).push("3.3.3");const Gt=(r,e,t)=>{const s=t?.renderBefore??e;let i=s._$litPart$;if(i===void 0){const n=t?.renderBefore??null;s._$litPart$=i=new Y(e.insertBefore(Q(),n),n,void 0,t??{})}return i._$AI(r),i};/**
|
|
16
16
|
* @license
|
|
17
17
|
* Copyright 2017 Google LLC
|
|
18
18
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
19
|
-
*/const we=globalThis;let _=class extends F{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=Gt(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return D}};_._$litElement$=!0,_.finalized=!0,we.litElementHydrateSupport?.({LitElement:_});const Jt=we.litElementPolyfillSupport;Jt?.({LitElement:_});(we.litElementVersions??=[]).push("4.2.2");var gt;let pe=0;const
|
|
20
|
-
↳ while computing ${this._debugParent??"root"}`);this.#s=!0,this.#a(),u.push(this);try{const e=this.#e();this._set(e)}finally{u.pop(),this.#t=!1,this.#s=!1}return this._get()}get value(){return this.get()}set value(e){throw new Error(`Cannot set value of Computed ${this}. Computed values are read-only.`)}subscribe(e,t=!1){const s=super.subscribe(e,t);return u.activeConsumer||this.get(),s}}class oe{#e;#t=new Map;_debugParent;constructor(e){this.#e=e,e.addController(this);const t=e,s=t.update,i=this;t.update=function(n){u.push(i);try{s.call(this,n)}finally{u.pop()}}}track(e){this.#t.has(e)||this.#t.set(e,e.subscribe(this.#s,!0))}#s=()=>{this.#e.requestUpdate()};hostUpdate(){for(const e of this.#t.values())e();this.#t.clear()}hostDisconnected(){for(const e of this.#t.values())e();this.#t.clear()}toString(){const e=this.#e;return`SignalWatcher(${e?.localName??e?.tagName??e?.constructor?.name??"unknown"})`}}const rs=new Intl.DateTimeFormat("en-CA",{year:"numeric",month:"2-digit",day:"2-digit"});function ns(r){if(!r)return"unknown age";const e=new Date(r);return Number.isNaN(e.getTime())?"unknown age":rs.format(e)}function as(r){const e=[],t=new Map,s=[];for(const n of r){if(n._table!=="memory_docs"){s.push(n);continue}t.has(n.name)||(t.set(n.name,[]),e.push(n.name)),t.get(n.name).push(n)}const i=e.map(n=>({key:n,items:t.get(n)}));return s.length>0&&i.push({key:null,items:s}),i}class os extends _{static{this.properties={results:{attribute:!1},showFolder:{attribute:!1},onSelect:{attribute:!1},selectedIds:{attribute:!1},onToggleSelect:{attribute:!1}}}static{this.styles=O`
|
|
19
|
+
*/const we=globalThis;let _=class extends F{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=Gt(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return D}};_._$litElement$=!0,_.finalized=!0,we.litElementHydrateSupport?.({LitElement:_});const Jt=we.litElementPolyfillSupport;Jt?.({LitElement:_});(we.litElementVersions??=[]).push("4.2.2");var gt;let pe=0;const Ze=new Set;function Xt(r){pe++;try{r()}finally{pe--,pe===0&&es()}}function es(){const r=new Set(Ze);Ze.clear();for(const e of r)e()}function ts(r,e){return r!=r?e==e:r!==e||r&&typeof r=="object"||typeof r=="function"}function ss(r){return r&&typeof r.deref=="function"}class _e{static#e=0;#t;#s;#r=new Set;#i=gt.#e++;name;constructor(e,t){this.#t=e,this.#s=e,this.name=t}_get(){return u.activeConsumer&&u.activeConsumer.track(this),this.#t}_set(e){return ts(e,this.#t)?(this.#s=this.#t,this.#t=e,this._notify(),!0):!1}subscribe(e,t=!1){let s=e;return t&&(s=new WeakRef(e)),this.#r.add(s),()=>this.#r.delete(s)}_notify(){const e=[...this.#r];for(const t of e){let s;if(ss(t)){if(s=t.deref(),!s){this.#r.delete(t);continue}}else s=t;s()}}get id(){return this.#i}get previousValue(){return this.#s}toString(){return this.name?`${this.constructor.name}(${this.name})`:`${this.constructor.name}#${this.id}`}}gt=_e;class u extends _e{static#e=[];constructor(e,t){super(e,t)}static get activeConsumer(){return this.#e[this.#e.length-1]}static push(e){this.#e.push(e)}static pop(){this.#e.pop()}get(){return this._get()}set(e){Xt(()=>{this._set(e)})}get value(){return this.get()}set value(e){this.set(e)}update(e){this.set(e(this.get()))}}class is extends _e{#e;#t=!0;#s=!1;#r=new Map;_debugParent;#i;#d=()=>{this.#t||(this.#t=!0,this._notify())};constructor(e,t,s){super(void 0,t),this.#e=e,this.#i=s?.weak??!0}track(e){if(this.#r.has(e))return;const t=e.subscribe(this.#d,this.#i);this.#r.set(e,t)}dispose(){this.#a()}#a(){for(const e of this.#r.values())e();this.#r.clear()}get(){if(u.activeConsumer&&u.activeConsumer.track(this),!this.#t)return this._get();if(this.#s)throw new Error(`Cycle detected in ${this}
|
|
20
|
+
↳ while computing ${this._debugParent??"root"}`);this.#s=!0,this.#a(),u.push(this);try{const e=this.#e();this._set(e)}finally{u.pop(),this.#t=!1,this.#s=!1}return this._get()}get value(){return this.get()}set value(e){throw new Error(`Cannot set value of Computed ${this}. Computed values are read-only.`)}subscribe(e,t=!1){const s=super.subscribe(e,t);return u.activeConsumer||this.get(),s}}class oe{#e;#t=new Map;_debugParent;constructor(e){this.#e=e,e.addController(this);const t=e,s=t.update,i=this;t.update=function(n){u.push(i);try{s.call(this,n)}finally{u.pop()}}}track(e){this.#t.has(e)||this.#t.set(e,e.subscribe(this.#s,!0))}#s=()=>{this.#e.requestUpdate()};hostUpdate(){for(const e of this.#t.values())e();this.#t.clear()}hostDisconnected(){for(const e of this.#t.values())e();this.#t.clear()}toString(){const e=this.#e;return`SignalWatcher(${e?.localName??e?.tagName??e?.constructor?.name??"unknown"})`}}const rs=new Intl.DateTimeFormat("en-CA",{year:"numeric",month:"2-digit",day:"2-digit"});function ns(r){if(!r)return"unknown age";const e=new Date(r);return Number.isNaN(e.getTime())?"unknown age":rs.format(e)}function as(r){const e=[],t=new Map,s=[];for(const n of r){if(n._table!=="memory_docs"){s.push(n);continue}t.has(n.name)||(t.set(n.name,[]),e.push(n.name)),t.get(n.name).push(n)}const i=e.map(n=>({key:n,items:t.get(n)}));return s.length>0&&i.push({key:null,items:s}),i}class os extends _{static{this.properties={results:{attribute:!1},showFolder:{attribute:!1},onSelect:{attribute:!1},selectedIds:{attribute:!1},onToggleSelect:{attribute:!1},onKeyClick:{attribute:!1}}}static{this.styles=O`
|
|
21
21
|
:host { display: block; }
|
|
22
22
|
.count-header {
|
|
23
23
|
padding: 8px 14px;
|
|
@@ -40,6 +40,11 @@
|
|
|
40
40
|
gap: 6px;
|
|
41
41
|
}
|
|
42
42
|
.key-group-count { opacity: 0.6; font-weight: 400; }
|
|
43
|
+
.key-group-link {
|
|
44
|
+
background: none; border: none; padding: 0; margin: 0; font: inherit; font-weight: 700;
|
|
45
|
+
color: inherit; cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
|
|
46
|
+
}
|
|
47
|
+
.key-group-link:hover { opacity: 0.8; }
|
|
43
48
|
.row { padding: 10px 14px; border-bottom: 1px solid var(--border); cursor: pointer; display: flex; gap: 8px; }
|
|
44
49
|
.row:hover { background: var(--hover); }
|
|
45
50
|
.row.deprecated { opacity: 0.55; }
|
|
@@ -70,7 +75,17 @@
|
|
|
70
75
|
`}render(){return!this.results||this.results.length===0?h`<div class="empty">No results.</div>`:h`
|
|
71
76
|
<div class="count-header">${this.results.length} result${this.results.length===1?"":"s"}</div>
|
|
72
77
|
${as(this.results).map(e=>h`
|
|
73
|
-
${e.key?h`<div class="key-group-header"
|
|
78
|
+
${e.key?h`<div class="key-group-header">
|
|
79
|
+
🔑
|
|
80
|
+
<button
|
|
81
|
+
class="key-group-link"
|
|
82
|
+
title="Search for this key"
|
|
83
|
+
@click=${()=>this.onKeyClick?.(e.key)}
|
|
84
|
+
>
|
|
85
|
+
${e.key}
|
|
86
|
+
</button>
|
|
87
|
+
<span class="key-group-count">(${e.items.length})</span>
|
|
88
|
+
</div>`:""}
|
|
74
89
|
${e.items.map(t=>this.#e(t))}
|
|
75
90
|
`)}
|
|
76
91
|
`}#e(e){const t=e._table==="skills"&&e.folder==="builtin";return h`
|
|
@@ -98,8 +113,8 @@
|
|
|
98
113
|
</div>
|
|
99
114
|
</div>
|
|
100
115
|
</div>
|
|
101
|
-
`}}customElements.define("result-list",os);function Se(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var M=Se();function ft(r){M=r}var z={exec:()=>null};function N(r){let e=[];return t=>{let s=Math.max(0,Math.min(3,t-1)),i=e[s];return i||(i=r(s),e[s]=i),i}}function f(r,e=""){let t=typeof r=="string"?r:r.source,s={replace:(i,n)=>{let a=typeof n=="string"?n:n.source;return a=a.replace(v.caret,"$1"),t=t.replace(i,a),s},getRegex:()=>new RegExp(t,e)};return s}var ls=((r="")=>{try{return!!new RegExp("(?<=1)(?<!1)"+r)}catch{return!1}})(),v={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] +\S/,listReplaceTask:/^\[[ xX]\] +/,listTaskCheckbox:/\[[ xX]\]/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:r=>new RegExp(`^( {0,3}${r})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:N(r=>new RegExp(`^ {0,${r}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)),hrRegex:N(r=>new RegExp(`^ {0,${r}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`)),fencesBeginRegex:N(r=>new RegExp(`^ {0,${r}}(?:\`\`\`|~~~)`)),headingBeginRegex:N(r=>new RegExp(`^ {0,${r}}#`)),htmlBeginRegex:N(r=>new RegExp(`^ {0,${r}}<(?:[a-z].*>|!--)`,"i")),blockquoteBeginRegex:N(r=>new RegExp(`^ {0,${r}}>`))},cs=/^(?:[ \t]*(?:\n|$))+/,hs=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,ps=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,G=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,ds=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,Ae=/ {0,3}(?:[*+-]|\d{1,9}[.)])/,bt=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,mt=f(bt).replace(/bull/g,Ae).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}(?:\s|$)/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),us=f(bt).replace(/bull/g,Ae).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}(?:\s|$)/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),Te=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table|[ \t]+\n)[^\n]+)*)/,gs=/^[^\n]+/,Ce=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/,fs=f(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",Ce).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),bs=f(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g,Ae).getRegex(),le="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Ee=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,ms=f("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n*|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>[^\\n]*\\n*|$)|<![A-Z][\\s\\S]*?(?:>[^\\n]*\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>[^\\n]*\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",Ee).replace("tag",le).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),xt=r=>f(Te).replace("hr",G).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list",r).replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",le).getRegex(),xs=xt(/ {0,3}(?:[*+-]|1[.)])[ \t]+[^ \t\n]/),ks=xt(/ {0,3}(?:[*+-]|\d{1,9}[.)])(?:[ \t]|\n|$)/),vs=f(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",ks).getRegex(),Re={blockquote:vs,code:hs,def:fs,fences:ps,heading:ds,hr:G,html:ms,lheading:mt,list:bs,newline:cs,paragraph:xs,table:z,text:gs},
|
|
102
|
-
]`).replace("lheading",mt).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},ws=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,_s=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,kt=/^( {2,}|\\)\n(?!\s*$)/,Ss=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,T=/[\p{P}\p{S}]/u,U=/[\s\p{P}\p{S}]/u,J=/[^\s\p{P}\p{S}]/u,As=f(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,U).getRegex(),Ts=/[\p{Pi}\p{Ps}"']/u,vt=/(?!~)[\p{P}\p{S}]/u,Cs=/(?!~)[\s\p{P}\p{S}]/u,Es=/(?:[^\s\p{P}\p{S}]|~)/u,Rs=f(/link|precode-code|html/,"g").replace("link",/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-",ls?"(?<!`)()":"(^^|[^`])").replace("code",/(?<b>`+)[^`]+\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),$t=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,zs=f($t,"u").replace(/punct/g,T).getRegex(),Ps=f($t,"u").replace(/punct/g,vt).getRegex(),Ls=/^(?:\*+(?:((?!\*)(?!openQuote)punct)|([^\s*]))?)|^_+(?:((?!_)(?!openQuote)punct)|([^\s_]))?/,Ds=f(Ls,"u").replace(/openQuote/g,Ts).replace(/punct/g,T).getRegex(),yt="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Is=f(yt,"gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,U).replace(/punct/g,T).getRegex(),Os=f(yt,"gu").replace(/notPunctSpace/g,Es).replace(/punctSpace/g,Cs).replace(/punct/g,vt).getRegex(),Ms="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)[\\s](\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|(?:(?!\\*)punct|notPunctSpace)(\\*+)(?!\\*)(?=notPunctSpace)",Ns=f(Ms,"gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,U).replace(/punct/g,T).getRegex(),Fs=f("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,U).replace(/punct/g,T).getRegex(),qs="^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)[\\s](_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)|(?:(?!_)punct|notPunctSpace)(_+)(?!_)(?=notPunctSpace)",Us=f(qs,"gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,U).replace(/punct/g,T).getRegex(),Hs=f(/^~~?(?:((?!~)punct)|[^\s~])/,"u").replace(/punct/g,T).getRegex(),Bs="^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)",js=f(Bs,"gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,U).replace(/punct/g,T).getRegex(),
|
|
116
|
+
`}}customElements.define("result-list",os);function Se(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var M=Se();function ft(r){M=r}var z={exec:()=>null};function N(r){let e=[];return t=>{let s=Math.max(0,Math.min(3,t-1)),i=e[s];return i||(i=r(s),e[s]=i),i}}function f(r,e=""){let t=typeof r=="string"?r:r.source,s={replace:(i,n)=>{let a=typeof n=="string"?n:n.source;return a=a.replace(v.caret,"$1"),t=t.replace(i,a),s},getRegex:()=>new RegExp(t,e)};return s}var ls=((r="")=>{try{return!!new RegExp("(?<=1)(?<!1)"+r)}catch{return!1}})(),v={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] +\S/,listReplaceTask:/^\[[ xX]\] +/,listTaskCheckbox:/\[[ xX]\]/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:r=>new RegExp(`^( {0,3}${r})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:N(r=>new RegExp(`^ {0,${r}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)),hrRegex:N(r=>new RegExp(`^ {0,${r}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`)),fencesBeginRegex:N(r=>new RegExp(`^ {0,${r}}(?:\`\`\`|~~~)`)),headingBeginRegex:N(r=>new RegExp(`^ {0,${r}}#`)),htmlBeginRegex:N(r=>new RegExp(`^ {0,${r}}<(?:[a-z].*>|!--)`,"i")),blockquoteBeginRegex:N(r=>new RegExp(`^ {0,${r}}>`))},cs=/^(?:[ \t]*(?:\n|$))+/,hs=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,ps=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,G=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,ds=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,Ae=/ {0,3}(?:[*+-]|\d{1,9}[.)])/,bt=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,mt=f(bt).replace(/bull/g,Ae).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}(?:\s|$)/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),us=f(bt).replace(/bull/g,Ae).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}(?:\s|$)/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),Te=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table|[ \t]+\n)[^\n]+)*)/,gs=/^[^\n]+/,Ce=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/,fs=f(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",Ce).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),bs=f(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g,Ae).getRegex(),le="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Ee=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,ms=f("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n*|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>[^\\n]*\\n*|$)|<![A-Z][\\s\\S]*?(?:>[^\\n]*\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>[^\\n]*\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",Ee).replace("tag",le).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),xt=r=>f(Te).replace("hr",G).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list",r).replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",le).getRegex(),xs=xt(/ {0,3}(?:[*+-]|1[.)])[ \t]+[^ \t\n]/),ks=xt(/ {0,3}(?:[*+-]|\d{1,9}[.)])(?:[ \t]|\n|$)/),vs=f(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",ks).getRegex(),Re={blockquote:vs,code:hs,def:fs,fences:ps,heading:ds,hr:G,html:ms,lheading:mt,list:bs,newline:cs,paragraph:xs,table:z,text:gs},We=f("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",G).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",le).getRegex(),$s={...Re,lheading:us,table:We,paragraph:f(Te).replace("hr",G).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",We).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",le).getRegex()},ys={...Re,html:f(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",Ee).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:z,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:f(Te).replace("hr",G).replace("heading",` *#{1,6} *[^
|
|
117
|
+
]`).replace("lheading",mt).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},ws=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,_s=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,kt=/^( {2,}|\\)\n(?!\s*$)/,Ss=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,T=/[\p{P}\p{S}]/u,U=/[\s\p{P}\p{S}]/u,J=/[^\s\p{P}\p{S}]/u,As=f(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,U).getRegex(),Ts=/[\p{Pi}\p{Ps}"']/u,vt=/(?!~)[\p{P}\p{S}]/u,Cs=/(?!~)[\s\p{P}\p{S}]/u,Es=/(?:[^\s\p{P}\p{S}]|~)/u,Rs=f(/link|precode-code|html/,"g").replace("link",/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-",ls?"(?<!`)()":"(^^|[^`])").replace("code",/(?<b>`+)[^`]+\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),$t=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,zs=f($t,"u").replace(/punct/g,T).getRegex(),Ps=f($t,"u").replace(/punct/g,vt).getRegex(),Ls=/^(?:\*+(?:((?!\*)(?!openQuote)punct)|([^\s*]))?)|^_+(?:((?!_)(?!openQuote)punct)|([^\s_]))?/,Ds=f(Ls,"u").replace(/openQuote/g,Ts).replace(/punct/g,T).getRegex(),yt="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Is=f(yt,"gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,U).replace(/punct/g,T).getRegex(),Os=f(yt,"gu").replace(/notPunctSpace/g,Es).replace(/punctSpace/g,Cs).replace(/punct/g,vt).getRegex(),Ms="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)[\\s](\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|(?:(?!\\*)punct|notPunctSpace)(\\*+)(?!\\*)(?=notPunctSpace)",Ns=f(Ms,"gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,U).replace(/punct/g,T).getRegex(),Fs=f("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,U).replace(/punct/g,T).getRegex(),qs="^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)[\\s](_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)|(?:(?!_)punct|notPunctSpace)(_+)(?!_)(?=notPunctSpace)",Us=f(qs,"gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,U).replace(/punct/g,T).getRegex(),Hs=f(/^~~?(?:((?!~)punct)|[^\s~])/,"u").replace(/punct/g,T).getRegex(),Bs="^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)",js=f(Bs,"gu").replace(/notPunctSpace/g,J).replace(/punctSpace/g,U).replace(/punct/g,T).getRegex(),Ks=f(/\\(punct)/,"gu").replace(/punct/g,T).getRegex(),Zs=f(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Ws=f(Ee).replace("(?:-->|$)","-->").getRegex(),Qs=f("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",Ws).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),se=/(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/,Vs=f(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace("label",se).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]+|(?=\))/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),wt=f(/^!?\[(label)\]\[(ref)\]/).replace("label",se).replace("ref",Ce).getRegex(),_t=f(/^!?\[(ref)\](?:\[\])?/).replace("ref",Ce).getRegex(),Ys=f("reflink|nolink(?!\\()","g").replace("reflink",wt).replace("nolink",_t).getRegex(),Qe=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,ze={_backpedal:z,anyPunctuation:Ks,autolink:Zs,blockSkip:Rs,br:kt,code:_s,del:z,delLDelim:z,delRDelim:z,emStrongLDelim:zs,emStrongRDelimAst:Is,emStrongRDelimUnd:Fs,escape:ws,link:Vs,nolink:_t,punctuation:As,reflink:wt,reflinkSearch:Ys,tag:Qs,text:Ss,url:z},Gs={...ze,emStrongLDelim:Ds,emStrongRDelimAst:Ns,emStrongRDelimUnd:Us,link:f(/^!?\[(label)\]\((.*?)\)/).replace("label",se).getRegex(),reflink:f(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",se).getRegex()},fe={...ze,emStrongRDelimAst:Os,emStrongLDelim:Ps,delLDelim:Hs,delRDelim:js,url:f(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol",Qe).replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/,text:f(/^(`+|~+|[^`~])(?:(?=[`~])|(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol",Qe).getRegex()},Js={...fe,br:f(kt).replace("{2,}","*").getRegex(),text:f(fe.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},X={normal:Re,gfm:$s,pedantic:ys},K={normal:ze,gfm:fe,breaks:Js,pedantic:Gs},Xs={"&":"&","<":"<",">":">",'"':""","'":"'"},Ve=r=>Xs[r];function A(r,e){if(e){if(v.escapeTest.test(r))return r.replace(v.escapeReplace,Ve)}else if(v.escapeTestNoEncode.test(r))return r.replace(v.escapeReplaceNoEncode,Ve);return r}function Ye(r){try{r=encodeURI(r).replace(v.percentDecode,"%")}catch{return null}return r}function Ge(r,e){let t=r.replace(v.findPipe,(n,a,o)=>{let l=!1,c=a;for(;--c>=0&&o[c]==="\\";)l=!l;return l?"|":" |"}),s=t.split(v.splitPipe),i=0;if(s[0].trim()||s.shift(),s.length>0&&!s.at(-1)?.trim()&&s.pop(),e)if(s.length>e)s.splice(e);else for(;s.length<e;)s.push("");for(;i<s.length;i++)s[i]=s[i].trim().replace(v.slashPipe,"|");return s}function C(r,e,t){let s=r.length;if(s===0)return"";let i=0;for(;i<s&&r.charAt(s-i-1)===e;)i++;return r.slice(0,s-i)}function Je(r){let e=r.split(`
|
|
103
118
|
`),t=e.length-1;for(;t>=0&&v.blankLine.test(e[t]);)t--;return e.length-t<=2?r:e.slice(0,t+1).join(`
|
|
104
119
|
`)}function ei(r,e){if(r.indexOf(e[1])===-1)return-1;let t=0;for(let s=0;s<r.length;s++)if(r[s]==="\\")s++;else if(r[s]===e[0])t++;else if(r[s]===e[1]&&(t--,t<0))return s;return t>0?-2:-1}function ti(r,e=0){let t=e,s="";for(let i of r)if(i===" "){let n=4-t%4;s+=" ".repeat(n),t+=n}else s+=i,t++;return s}function Xe(r,e,t,s,i){let n=e.href,a=e.title||null,o=r[1].replace(i.other.outputLinkReplace,"$1");s.state.inLink=!0;let l={type:r[0].charAt(0)==="!"?"image":"link",raw:t,href:n,title:a,text:o,tokens:s.inlineTokens(o)};return s.state.inLink=!1,l}function si(r,e,t){let s=r.match(t.other.indentCodeCompensation);if(s===null)return e;let i=s[1];return e.split(`
|
|
105
120
|
`).map(n=>{let a=n.match(t.other.beginningSpace);if(a===null)return n;let[o]=a;return o.length>=i.length?n.slice(i.length):n}).join(`
|
|
@@ -111,25 +126,25 @@
|
|
|
111
126
|
`),d=c.replace(this.rules.other.blockquoteSetextReplace,`
|
|
112
127
|
$1`).replace(this.rules.other.blockquoteSetextReplace2,"");s=s?`${s}
|
|
113
128
|
${c}`:c,i=i?`${i}
|
|
114
|
-
${d}`:d;let p=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(d,n,!0),this.lexer.state.top=p,t.length===0)break;let g=n.at(-1);if(g?.type==="code")break;if(g?.type==="blockquote"){let k=g,
|
|
129
|
+
${d}`:d;let p=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(d,n,!0),this.lexer.state.top=p,t.length===0)break;let g=n.at(-1);if(g?.type==="code")break;if(g?.type==="blockquote"){let k=g,m=t.join(`
|
|
115
130
|
`),S=k.raw+`
|
|
116
|
-
`+
|
|
117
|
-
${
|
|
131
|
+
`+m.replace(this.rules.other.blockquoteSetextReplace2,""),H=this.blockquote(S);n[n.length-1]=H,s=`${s}
|
|
132
|
+
${m}`,i=i.substring(0,i.length-k.text.length)+H.text;break}else if(g?.type==="list"){let k=g,m=k.raw+`
|
|
118
133
|
`+t.join(`
|
|
119
|
-
`),S=this.list(
|
|
134
|
+
`),S=this.list(m);n[n.length-1]=S,s=s.substring(0,s.length-g.raw.length)+S.raw,i=i.substring(0,i.length-k.raw.length)+S.raw,t=m.substring(n.at(-1).raw.length).split(`
|
|
120
135
|
`);continue}}return{type:"blockquote",raw:s,tokens:n,text:i}}}list(r){let e=this.rules.block.list.exec(r);if(e){let t=e[1].trim(),s=t.length>1,i={type:"list",raw:"",ordered:s,start:s?+t.slice(0,-1):"",loose:!1,items:[]};t=s?`\\d{1,9}\\${t.slice(-1)}`:`\\${t}`,this.options.pedantic&&(t=s?t:"[*+-]");let n=this.rules.other.listItemRegex(t),a=!1;for(;r;){let l=!1,c="",d="";if(!(e=n.exec(r))||this.rules.block.hr.test(r))break;c=e[0],r=r.substring(c.length);let p=ti(e[2].split(`
|
|
121
136
|
`,1)[0],e[1].length),g=r.split(`
|
|
122
|
-
`,1)[0],k=!p.trim(),
|
|
123
|
-
`,r=r.substring(g.length+1),l=!0),!l){let S=this.rules.other.nextBulletRegex(
|
|
124
|
-
`,1)[0],B;if(g=ce,this.options.pedantic?(g=g.replace(this.rules.other.listReplaceNesting," "),B=g):B=g.replace(this.rules.other.tabCharGlobal," "),Le.test(g)||De.test(g)||Et.test(g)||Rt.test(g)||S.test(g)||H.test(g))break;if(B.search(this.rules.other.nonSpaceChar)>=
|
|
125
|
-
`+B.slice(
|
|
137
|
+
`,1)[0],k=!p.trim(),m=0;if(this.options.pedantic?(m=2,d=p.trimStart()):k?m=e[1].length+1:(m=p.search(this.rules.other.nonSpaceChar),m=m>4?1:m,d=p.slice(m),m+=e[1].length),k&&this.rules.other.blankLine.test(g)&&(c+=g+`
|
|
138
|
+
`,r=r.substring(g.length+1),l=!0),!l){let S=this.rules.other.nextBulletRegex(m),H=this.rules.other.hrRegex(m),Le=this.rules.other.fencesBeginRegex(m),De=this.rules.other.headingBeginRegex(m),Et=this.rules.other.htmlBeginRegex(m),Rt=this.rules.other.blockquoteBeginRegex(m);for(;r;){let ce=r.split(`
|
|
139
|
+
`,1)[0],B;if(g=ce,this.options.pedantic?(g=g.replace(this.rules.other.listReplaceNesting," "),B=g):B=g.replace(this.rules.other.tabCharGlobal," "),Le.test(g)||De.test(g)||Et.test(g)||Rt.test(g)||S.test(g)||H.test(g))break;if(B.search(this.rules.other.nonSpaceChar)>=m||!g.trim())d+=`
|
|
140
|
+
`+B.slice(m);else{if(k||p.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||Le.test(p)||De.test(p)||H.test(p))break;d+=`
|
|
126
141
|
`+g}k=!g.trim(),c+=ce+`
|
|
127
|
-
`,r=r.substring(ce.length+1),p=B.slice(
|
|
142
|
+
`,r=r.substring(ce.length+1),p=B.slice(m)}}i.loose||(a?i.loose=!0:this.rules.other.doubleBlankLine.test(c)&&(a=!0)),i.items.push({type:"list_item",raw:c,task:!!this.options.gfm&&this.rules.other.listIsTask.test(d),loose:!1,text:d,tokens:[]}),i.raw+=c}let o=i.items.at(-1);if(o)o.raw=o.raw.trimEnd(),o.text=o.text.trimEnd();else return;i.raw=i.raw.trimEnd();for(let l of i.items)if(this.lexer.state.top=!1,l.tokens=this.lexer.blockTokens(l.text,[]),!i.loose){let c=l.tokens.filter(p=>p.type==="space"),d=c.length>0&&c.some(p=>this.rules.other.anyLine.test(p.raw));i.loose=d}for(let l of i.items){let c=l.tokens[0];if(l.task&&(c?.type==="text"||c?.type==="paragraph")){l.text=l.text.replace(this.rules.other.listReplaceTask,""),c.raw=c.raw.replace(this.rules.other.listReplaceTask,""),c.text=c.text.replace(this.rules.other.listReplaceTask,"");for(let p=this.lexer.inlineQueue.length-1;p>=0;p--)if(this.rules.other.listIsTask.test(this.lexer.inlineQueue[p].src)){this.lexer.inlineQueue[p].src=this.lexer.inlineQueue[p].src.replace(this.rules.other.listReplaceTask,"");break}let d=this.rules.other.listTaskCheckbox.exec(l.raw);if(d){let p={type:"checkbox",raw:d[0]+" ",checked:d[0]!=="[ ]"};l.checked=p.checked,i.loose?l.tokens[0]&&["paragraph","text"].includes(l.tokens[0].type)&&"tokens"in l.tokens[0]&&l.tokens[0].tokens?(l.tokens[0].raw=p.raw+l.tokens[0].raw,l.tokens[0].text=p.raw+l.tokens[0].text,l.tokens[0].tokens.unshift(p)):l.tokens.unshift({type:"paragraph",raw:p.raw,text:p.raw,tokens:[p]}):l.tokens.unshift(p)}}else l.task&&(l.task=!1)}if(i.loose)for(let l of i.items){l.loose=!0;for(let c of l.tokens)c.type==="text"&&(c.type="paragraph")}return i}}html(r){let e=this.rules.block.html.exec(r);if(e){let t=Je(e[0]);return{type:"html",block:!0,raw:t,pre:e[1]==="pre"||e[1]==="script"||e[1]==="style",text:t}}}def(r){let e=this.rules.block.def.exec(r);if(e){let t=e[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),s=e[2]?e[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",i=e[3]?e[3].substring(1,e[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):e[3];return{type:"def",tag:t,raw:C(e[0],`
|
|
128
143
|
`),href:s,title:i}}}table(r){let e=this.rules.block.table.exec(r);if(!e||!this.rules.other.tableDelimiter.test(e[2]))return;let t=Ge(e[1]),s=e[2].replace(this.rules.other.tableAlignChars,"").split("|"),i=e[3]?.trim()?e[3].replace(this.rules.other.tableRowBlankLine,"").split(`
|
|
129
144
|
`):[],n={type:"table",raw:C(e[0],`
|
|
130
145
|
`),header:[],align:[],rows:[]};if(t.length===s.length){for(let a of s)this.rules.other.tableAlignRight.test(a)?n.align.push("right"):this.rules.other.tableAlignCenter.test(a)?n.align.push("center"):this.rules.other.tableAlignLeft.test(a)?n.align.push("left"):n.align.push(null);for(let a=0;a<t.length;a++)n.header.push({text:t[a],tokens:this.lexer.inline(t[a]),header:!0,align:n.align[a]});for(let a of i)n.rows.push(Ge(a,n.header.length).map((o,l)=>({text:o,tokens:this.lexer.inline(o),header:!1,align:n.align[l]})));return n}}lheading(r){let e=this.rules.block.lheading.exec(r);if(e){let t=e[1].trim();return{type:"heading",raw:C(e[0],`
|
|
131
146
|
`),depth:e[2].charAt(0)==="="?1:2,text:t,tokens:this.lexer.inline(t)}}}paragraph(r){let e=this.rules.block.paragraph.exec(r);if(e){let t=e[1].charAt(e[1].length-1)===`
|
|
132
|
-
`?e[1].slice(0,-1):e[1];return{type:"paragraph",raw:e[0],text:t,tokens:this.lexer.inline(t)}}}text(r){let e=this.rules.block.text.exec(r);if(e)return{type:"text",raw:e[0],text:e[0],tokens:this.lexer.inline(e[0])}}escape(r){let e=this.rules.inline.escape.exec(r);if(e)return{type:"escape",raw:e[0],text:e[1]}}tag(r){let e=this.rules.inline.tag.exec(r);if(e)return!this.lexer.state.inLink&&this.rules.other.startATag.test(e[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(e[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(e[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(e[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:e[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:e[0]}}link(r){let e=this.rules.inline.link.exec(r);if(e){let t=e[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(t)){if(!this.rules.other.endAngleBracket.test(t))return;let n=C(t.slice(0,-1),"\\");if((t.length-n.length)%2===0)return}else{let n=ei(e[2],"()");if(n===-2)return;if(n>-1){let a=(e[0].indexOf("!")===0?5:4)+e[1].length+n;e[2]=e[2].substring(0,n),e[0]=e[0].substring(0,a).trim(),e[3]=""}}let s=e[2],i="";if(this.options.pedantic){let n=this.rules.other.pedanticHrefTitle.exec(s);n&&(s=n[1],i=n[3])}else i=e[3]?e[3].slice(1,-1):"";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(t)?s=s.slice(1):s=s.slice(1,-1)),Xe(e,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:i&&i.replace(this.rules.inline.anyPunctuation,"$1")},e[0],this.lexer,this.rules)}}reflink(r,e){let t;if((t=this.rules.inline.reflink.exec(r))||(t=this.rules.inline.nolink.exec(r))){let s=(t[2]||t[1]).replace(this.rules.other.multipleSpaceGlobal," "),i=e[s.toLowerCase()];if(!i){let n=t[0].charAt(0);return{type:"text",raw:n,text:n}}return Xe(t,i,t[0],this.lexer,this.rules)}}emStrong(r,e,t=""){let s=this.rules.inline.emStrongLDelim.exec(r);if(!(!s||!s[1]&&!s[2]&&!s[3]&&!s[4]||s[4]&&t.match(this.rules.other.unicodeAlphaNumeric))&&(!(s[1]||s[3])||!t||this.rules.inline.punctuation.exec(t))){let i=[...s[0]].length-1,n,a,o=i,l=0,c=s[0][0],d=t===c,p=c==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(p.lastIndex=0,e=e.slice(-1*r.length+i);(s=p.exec(e))!==null;){if(n=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!n)continue;if(a=[...n].length,s[3]||s[4]){o+=a;continue}else if(s[5]||s[6]){if(i%3&&!((i+a)%3)){l+=a;continue}if(d)break}if(o-=a,o>0)continue;a=Math.min(a,a+o+l);let g=[...s[0]][0].length,k=r.slice(0,i+s.index+g+a);if(Math.min(i,a)%2){let S=k.slice(1,-1);return{type:"em",raw:k,text:S,tokens:this.lexer.inlineTokens(S)}}let
|
|
147
|
+
`?e[1].slice(0,-1):e[1];return{type:"paragraph",raw:e[0],text:t,tokens:this.lexer.inline(t)}}}text(r){let e=this.rules.block.text.exec(r);if(e)return{type:"text",raw:e[0],text:e[0],tokens:this.lexer.inline(e[0])}}escape(r){let e=this.rules.inline.escape.exec(r);if(e)return{type:"escape",raw:e[0],text:e[1]}}tag(r){let e=this.rules.inline.tag.exec(r);if(e)return!this.lexer.state.inLink&&this.rules.other.startATag.test(e[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(e[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(e[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(e[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:e[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:e[0]}}link(r){let e=this.rules.inline.link.exec(r);if(e){let t=e[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(t)){if(!this.rules.other.endAngleBracket.test(t))return;let n=C(t.slice(0,-1),"\\");if((t.length-n.length)%2===0)return}else{let n=ei(e[2],"()");if(n===-2)return;if(n>-1){let a=(e[0].indexOf("!")===0?5:4)+e[1].length+n;e[2]=e[2].substring(0,n),e[0]=e[0].substring(0,a).trim(),e[3]=""}}let s=e[2],i="";if(this.options.pedantic){let n=this.rules.other.pedanticHrefTitle.exec(s);n&&(s=n[1],i=n[3])}else i=e[3]?e[3].slice(1,-1):"";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(t)?s=s.slice(1):s=s.slice(1,-1)),Xe(e,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:i&&i.replace(this.rules.inline.anyPunctuation,"$1")},e[0],this.lexer,this.rules)}}reflink(r,e){let t;if((t=this.rules.inline.reflink.exec(r))||(t=this.rules.inline.nolink.exec(r))){let s=(t[2]||t[1]).replace(this.rules.other.multipleSpaceGlobal," "),i=e[s.toLowerCase()];if(!i){let n=t[0].charAt(0);return{type:"text",raw:n,text:n}}return Xe(t,i,t[0],this.lexer,this.rules)}}emStrong(r,e,t=""){let s=this.rules.inline.emStrongLDelim.exec(r);if(!(!s||!s[1]&&!s[2]&&!s[3]&&!s[4]||s[4]&&t.match(this.rules.other.unicodeAlphaNumeric))&&(!(s[1]||s[3])||!t||this.rules.inline.punctuation.exec(t))){let i=[...s[0]].length-1,n,a,o=i,l=0,c=s[0][0],d=t===c,p=c==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(p.lastIndex=0,e=e.slice(-1*r.length+i);(s=p.exec(e))!==null;){if(n=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!n)continue;if(a=[...n].length,s[3]||s[4]){o+=a;continue}else if(s[5]||s[6]){if(i%3&&!((i+a)%3)){l+=a;continue}if(d)break}if(o-=a,o>0)continue;a=Math.min(a,a+o+l);let g=[...s[0]][0].length,k=r.slice(0,i+s.index+g+a);if(Math.min(i,a)%2){let S=k.slice(1,-1);return{type:"em",raw:k,text:S,tokens:this.lexer.inlineTokens(S)}}let m=k.slice(2,-2);return{type:"strong",raw:k,text:m,tokens:this.lexer.inlineTokens(m)}}}}codespan(r){let e=this.rules.inline.code.exec(r);if(e){let t=e[2].replace(this.rules.other.newLineCharGlobal," "),s=this.rules.other.nonSpaceChar.test(t),i=this.rules.other.startingSpaceChar.test(t)&&this.rules.other.endingSpaceChar.test(t);return s&&i&&(t=t.substring(1,t.length-1)),{type:"codespan",raw:e[0],text:t}}}br(r){let e=this.rules.inline.br.exec(r);if(e)return{type:"br",raw:e[0]}}del(r,e,t=""){let s=this.rules.inline.delLDelim.exec(r);if(s&&(!s[1]||!t||this.rules.inline.punctuation.exec(t))){let i=[...s[0]].length-1,n,a,o=i,l=this.rules.inline.delRDelim;for(l.lastIndex=0,e=e.slice(-1*r.length+i);(s=l.exec(e))!==null;){if(n=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!n||(a=[...n].length,a!==i))continue;if(s[3]||s[4]){o+=a;continue}if(o-=a,o>0)continue;a=Math.min(a,a+o);let c=[...s[0]][0].length,d=r.slice(0,i+s.index+c+a),p=d.slice(i,-i);return{type:"del",raw:d,text:p,tokens:this.lexer.inlineTokens(p)}}}}autolink(r){let e=this.rules.inline.autolink.exec(r);if(e){let t,s;return e[2]==="@"?(t=e[1],s="mailto:"+t):(t=e[1],s=t),{type:"link",raw:e[0],text:t,href:s,tokens:[{type:"text",raw:t,text:t}]}}}url(r){let e;if(e=this.rules.inline.url.exec(r)){let t,s;if(e[2]==="@")t=e[0],s="mailto:"+t;else{let i;do i=e[0],e[0]=this.rules.inline._backpedal.exec(e[0])?.[0]??"";while(i!==e[0]);t=e[0],e[1]==="www."?s="http://"+e[0]:s=e[0]}return{type:"link",raw:e[0],text:t,href:s,tokens:[{type:"text",raw:t,text:t}]}}}inlineText(r){let e=this.rules.inline.text.exec(r);if(e){let t=this.lexer.state.inRawBlock;return{type:"text",raw:e[0],text:e[0],escaped:t}}}},y=class be{tokens;options;state;inlineQueue;tokenizer;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||M,this.options.tokenizer=this.options.tokenizer||new ie,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};let t={other:v,block:X.normal,inline:K.normal};this.options.pedantic?(t.block=X.pedantic,t.inline=K.pedantic):this.options.gfm&&(t.block=X.gfm,this.options.breaks?t.inline=K.breaks:t.inline=K.gfm),this.tokenizer.rules=t}static get rules(){return{block:X,inline:K}}static lex(e,t){return new be(t).lex(e)}static lexInline(e,t){return new be(t).inlineTokens(e)}lex(e){e=e.replace(v.carriageReturn,`
|
|
133
148
|
`),this.blockTokens(e,this.tokens);for(let t=0;t<this.inlineQueue.length;t++){let s=this.inlineQueue[t];this.inlineTokens(s.src,s.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(e,t=[],s=!1){this.tokenizer.lexer=this,this.options.pedantic&&(e=e.replace(v.tabCharGlobal," ").replace(v.spaceLine,""));let i=1/0;for(;e;){if(e.length<i)i=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}let n;if(this.options.extensions?.block?.some(o=>(n=o.call({lexer:this},e,t))?(e=e.substring(n.raw.length),t.push(n),!0):!1))continue;if(n=this.tokenizer.space(e)){e=e.substring(n.raw.length);let o=t.at(-1);n.raw.length===1&&o!==void 0?o.raw+=`
|
|
134
149
|
`:t.push(n);continue}if(n=this.tokenizer.code(e)){e=e.substring(n.raw.length);let o=t.at(-1);o?.type==="paragraph"||o?.type==="text"?(o.raw+=(o.raw.endsWith(`
|
|
135
150
|
`)?"":`
|
|
@@ -161,8 +176,8 @@ ${this.parser.parse(r)}</blockquote>
|
|
|
161
176
|
`}tablerow({text:r}){return`<tr>
|
|
162
177
|
${r}</tr>
|
|
163
178
|
`}tablecell(r){let e=this.parser.parseInline(r.tokens),t=r.header?"th":"td";return(r.align?`<${t} align="${r.align}">`:`<${t}>`)+e+`</${t}>
|
|
164
|
-
`}strong({tokens:r}){return`<strong>${this.parser.parseInline(r)}</strong>`}em({tokens:r}){return`<em>${this.parser.parseInline(r)}</em>`}codespan({text:r}){return`<code>${A(r,!0)}</code>`}br(r){return"<br>"}del({tokens:r}){return`<del>${this.parser.parseInline(r)}</del>`}link({href:r,title:e,tokens:t}){let s=this.parser.parseInline(t),i=Ye(r);if(i===null)return s;r=i;let n='<a href="'+r+'"';return e&&(n+=' title="'+A(e)+'"'),n+=">"+s+"</a>",n}image({href:r,title:e,text:t,tokens:s}){s&&(t=this.parser.parseInline(s,this.parser.textRenderer));let i=Ye(r);if(i===null)return A(t);r=i;let n=`<img src="${r}" alt="${A(t)}"`;return e&&(n+=` title="${A(e)}"`),n+=">",n}text(r){return"tokens"in r&&r.tokens?this.parser.parseInline(r.tokens):"escaped"in r&&r.escaped?r.text:A(r.text)}},Pe=class{strong({text:r}){return r}em({text:r}){return r}codespan({text:r}){return r}del({text:r}){return r}html({text:r}){return r}text({text:r}){return r}link({text:r}){return""+r}image({text:r}){return""+r}br(){return""}checkbox({raw:r}){return r}},w=class me{options;renderer;textRenderer;constructor(e){this.options=e||M,this.options.renderer=this.options.renderer||new re,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new Pe}static parse(e,t){return new me(t).parse(e)}static parseInline(e,t){return new me(t).parseInline(e)}parse(e){this.renderer.parser=this;let t="";for(let s=0;s<e.length;s++){let i=e[s];if(this.options.extensions?.renderers?.[i.type]){let a=i,o=this.options.extensions.renderers[a.type].call({parser:this},a);if(o!==!1||!["space","hr","heading","code","table","blockquote","list","checkbox","html","def","paragraph","text"].includes(a.type)){t+=o||"";continue}}let n=i;switch(n.type){case"space":{t+=this.renderer.space(n);break}case"hr":{t+=this.renderer.hr(n);break}case"heading":{t+=this.renderer.heading(n);break}case"code":{t+=this.renderer.code(n);break}case"table":{t+=this.renderer.table(n);break}case"blockquote":{t+=this.renderer.blockquote(n);break}case"list":{t+=this.renderer.list(n);break}case"checkbox":{t+=this.renderer.checkbox(n);break}case"html":{t+=this.renderer.html(n);break}case"def":{t+=this.renderer.def(n);break}case"paragraph":{t+=this.renderer.paragraph(n);break}case"text":{t+=this.renderer.text(n);break}default:{let a='Token with "'+n.type+'" type was not found.';if(this.options.silent)return console.error(a),"";throw new Error(a)}}}return t}parseInline(e,t=this.renderer){this.renderer.parser=this;let s="";for(let i=0;i<e.length;i++){let n=e[i];if(this.options.extensions?.renderers?.[n.type]){let o=this.options.extensions.renderers[n.type].call({parser:this},n);if(o!==!1||!["escape","html","link","image","checkbox","strong","em","codespan","br","del","text"].includes(n.type)){s+=o||"";continue}}let a=n;switch(a.type){case"escape":{s+=t.text(a);break}case"html":{s+=t.html(a);break}case"link":{s+=t.link(a);break}case"image":{s+=t.image(a);break}case"checkbox":{s+=t.checkbox(a);break}case"strong":{s+=t.strong(a);break}case"em":{s+=t.em(a);break}case"codespan":{s+=t.codespan(a);break}case"br":{s+=t.br(a);break}case"del":{s+=t.del(a);break}case"text":{s+=t.text(a);break}default:{let o='Token with "'+a.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return s}},
|
|
165
|
-
Please report this to https://github.com/markedjs/marked.`,r){let s="<p>An error occurred:</p><pre>"+A(t.message+"",!0)+"</pre>";return e?Promise.resolve(s):s}if(e)return Promise.reject(t);throw t}}},I=new ii;function x(r,e){return I.parse(r,e)}x.options=x.setOptions=function(r){return I.setOptions(r),x.defaults=I.defaults,ft(x.defaults),x};x.getDefaults=Se;x.defaults=M;function ri(...r){return I.use(...r),x.defaults=I.defaults,ft(x.defaults),x}x.use=ri;x.walkTokens=function(r,e){return I.walkTokens(r,e)};x.parseInline=I.parseInline;x.Parser=w;x.parser=w.parse;x.Renderer=re;x.TextRenderer=Pe;x.Lexer=y;x.lexer=y.lex;x.Tokenizer=ie;x.Hooks=
|
|
179
|
+
`}strong({tokens:r}){return`<strong>${this.parser.parseInline(r)}</strong>`}em({tokens:r}){return`<em>${this.parser.parseInline(r)}</em>`}codespan({text:r}){return`<code>${A(r,!0)}</code>`}br(r){return"<br>"}del({tokens:r}){return`<del>${this.parser.parseInline(r)}</del>`}link({href:r,title:e,tokens:t}){let s=this.parser.parseInline(t),i=Ye(r);if(i===null)return s;r=i;let n='<a href="'+r+'"';return e&&(n+=' title="'+A(e)+'"'),n+=">"+s+"</a>",n}image({href:r,title:e,text:t,tokens:s}){s&&(t=this.parser.parseInline(s,this.parser.textRenderer));let i=Ye(r);if(i===null)return A(t);r=i;let n=`<img src="${r}" alt="${A(t)}"`;return e&&(n+=` title="${A(e)}"`),n+=">",n}text(r){return"tokens"in r&&r.tokens?this.parser.parseInline(r.tokens):"escaped"in r&&r.escaped?r.text:A(r.text)}},Pe=class{strong({text:r}){return r}em({text:r}){return r}codespan({text:r}){return r}del({text:r}){return r}html({text:r}){return r}text({text:r}){return r}link({text:r}){return""+r}image({text:r}){return""+r}br(){return""}checkbox({raw:r}){return r}},w=class me{options;renderer;textRenderer;constructor(e){this.options=e||M,this.options.renderer=this.options.renderer||new re,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new Pe}static parse(e,t){return new me(t).parse(e)}static parseInline(e,t){return new me(t).parseInline(e)}parse(e){this.renderer.parser=this;let t="";for(let s=0;s<e.length;s++){let i=e[s];if(this.options.extensions?.renderers?.[i.type]){let a=i,o=this.options.extensions.renderers[a.type].call({parser:this},a);if(o!==!1||!["space","hr","heading","code","table","blockquote","list","checkbox","html","def","paragraph","text"].includes(a.type)){t+=o||"";continue}}let n=i;switch(n.type){case"space":{t+=this.renderer.space(n);break}case"hr":{t+=this.renderer.hr(n);break}case"heading":{t+=this.renderer.heading(n);break}case"code":{t+=this.renderer.code(n);break}case"table":{t+=this.renderer.table(n);break}case"blockquote":{t+=this.renderer.blockquote(n);break}case"list":{t+=this.renderer.list(n);break}case"checkbox":{t+=this.renderer.checkbox(n);break}case"html":{t+=this.renderer.html(n);break}case"def":{t+=this.renderer.def(n);break}case"paragraph":{t+=this.renderer.paragraph(n);break}case"text":{t+=this.renderer.text(n);break}default:{let a='Token with "'+n.type+'" type was not found.';if(this.options.silent)return console.error(a),"";throw new Error(a)}}}return t}parseInline(e,t=this.renderer){this.renderer.parser=this;let s="";for(let i=0;i<e.length;i++){let n=e[i];if(this.options.extensions?.renderers?.[n.type]){let o=this.options.extensions.renderers[n.type].call({parser:this},n);if(o!==!1||!["escape","html","link","image","checkbox","strong","em","codespan","br","del","text"].includes(n.type)){s+=o||"";continue}}let a=n;switch(a.type){case"escape":{s+=t.text(a);break}case"html":{s+=t.html(a);break}case"link":{s+=t.link(a);break}case"image":{s+=t.image(a);break}case"checkbox":{s+=t.checkbox(a);break}case"strong":{s+=t.strong(a);break}case"em":{s+=t.em(a);break}case"codespan":{s+=t.codespan(a);break}case"br":{s+=t.br(a);break}case"del":{s+=t.del(a);break}case"text":{s+=t.text(a);break}default:{let o='Token with "'+a.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return s}},Z=class{options;block;constructor(r){this.options=r||M}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(r){return r}postprocess(r){return r}processAllTokens(r){return r}emStrongMask(r){return r}provideLexer(r=this.block){return r?y.lex:y.lexInline}provideParser(r=this.block){return r?w.parse:w.parseInline}},ii=class{defaults=Se();options=this.setOptions;parse=this.parseMarkdown(!0);parseInline=this.parseMarkdown(!1);Parser=w;Renderer=re;TextRenderer=Pe;Lexer=y;Tokenizer=ie;Hooks=Z;constructor(...r){this.use(...r)}walkTokens(r,e){let t=[];for(let s of r)switch(t=t.concat(e.call(this,s)),s.type){case"table":{let i=s;for(let n of i.header)t=t.concat(this.walkTokens(n.tokens,e));for(let n of i.rows)for(let a of n)t=t.concat(this.walkTokens(a.tokens,e));break}case"list":{let i=s;t=t.concat(this.walkTokens(i.items,e));break}default:{let i=s;this.defaults.extensions?.childTokens?.[i.type]?this.defaults.extensions.childTokens[i.type].forEach(n=>{let a=i[n].flat(1/0);t=t.concat(this.walkTokens(a,e))}):i.tokens&&(t=t.concat(this.walkTokens(i.tokens,e)))}}return t}use(...r){let e=this.defaults.extensions||{renderers:{},childTokens:{}};return r.forEach(t=>{let s={...t};if(s.async=this.defaults.async||s.async||!1,t.extensions&&(t.extensions.forEach(i=>{if(!i.name)throw new Error("extension name required");if("renderer"in i){let n=e.renderers[i.name];n?e.renderers[i.name]=function(...a){let o=i.renderer.apply(this,a);return o===!1&&(o=n.apply(this,a)),o}:e.renderers[i.name]=i.renderer}if("tokenizer"in i){if(!i.level||i.level!=="block"&&i.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let n=e[i.level];n?n.unshift(i.tokenizer):e[i.level]=[i.tokenizer],i.start&&(i.level==="block"?e.startBlock?e.startBlock.push(i.start):e.startBlock=[i.start]:i.level==="inline"&&(e.startInline?e.startInline.push(i.start):e.startInline=[i.start]))}"childTokens"in i&&i.childTokens&&(e.childTokens[i.name]=i.childTokens)}),s.extensions=e),t.renderer){let i=this.defaults.renderer||new re(this.defaults);for(let n in t.renderer){if(!(n in i))throw new Error(`renderer '${n}' does not exist`);if(["options","parser"].includes(n))continue;let a=n,o=t.renderer[a],l=i[a];i[a]=(...c)=>{let d=o.apply(i,c);return d===!1&&(d=l.apply(i,c)),d||""}}s.renderer=i}if(t.tokenizer){let i=this.defaults.tokenizer||new ie(this.defaults);for(let n in t.tokenizer){if(!(n in i))throw new Error(`tokenizer '${n}' does not exist`);if(["options","rules","lexer"].includes(n))continue;let a=n,o=t.tokenizer[a],l=i[a];i[a]=(...c)=>{let d=o.apply(i,c);return d===!1&&(d=l.apply(i,c)),d}}s.tokenizer=i}if(t.hooks){let i=this.defaults.hooks||new Z;for(let n in t.hooks){if(!(n in i))throw new Error(`hook '${n}' does not exist`);if(["options","block"].includes(n))continue;let a=n,o=t.hooks[a],l=i[a];Z.passThroughHooks.has(n)?i[a]=c=>{if(this.defaults.async&&Z.passThroughHooksRespectAsync.has(n))return(async()=>{let p=await o.call(i,c);return l.call(i,p)})();let d=o.call(i,c);return l.call(i,d)}:i[a]=(...c)=>{if(this.defaults.async)return(async()=>{let p=await o.apply(i,c);return p===!1&&(p=await l.apply(i,c)),p})();let d=o.apply(i,c);return d===!1&&(d=l.apply(i,c)),d}}s.hooks=i}if(t.walkTokens){let i=this.defaults.walkTokens,n=t.walkTokens;s.walkTokens=function(a){let o=[];return o.push(n.call(this,a)),i&&(o=o.concat(i.call(this,a))),o}}this.defaults={...this.defaults,...s}}),this}setOptions(r){return this.defaults={...this.defaults,...r},this}lexer(r,e){return y.lex(r,e??this.defaults)}parser(r,e){return w.parse(r,e??this.defaults)}parseMarkdown(r){return(e,t)=>{let s={...t},i={...this.defaults,...s},n=this.onError(!!i.silent,!!i.async);if(this.defaults.async===!0&&s.async===!1)return n(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof e>"u"||e===null)return n(new Error("marked(): input parameter is undefined or null"));if(typeof e!="string")return n(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected"));if(i.hooks&&(i.hooks.options=i,i.hooks.block=r),i.async)return(async()=>{let a=i.hooks?await i.hooks.preprocess(e):e,o=await(i.hooks?await i.hooks.provideLexer(r):r?y.lex:y.lexInline)(a,i),l=i.hooks?await i.hooks.processAllTokens(o):o;i.walkTokens&&await Promise.all(this.walkTokens(l,i.walkTokens));let c=await(i.hooks?await i.hooks.provideParser(r):r?w.parse:w.parseInline)(l,i);return i.hooks?await i.hooks.postprocess(c):c})().catch(n);try{i.hooks&&(e=i.hooks.preprocess(e));let a=(i.hooks?i.hooks.provideLexer(r):r?y.lex:y.lexInline)(e,i);i.hooks&&(a=i.hooks.processAllTokens(a)),i.walkTokens&&this.walkTokens(a,i.walkTokens);let o=(i.hooks?i.hooks.provideParser(r):r?w.parse:w.parseInline)(a,i);return i.hooks&&(o=i.hooks.postprocess(o)),o}catch(a){return n(a)}}}onError(r,e){return t=>{if(t.message+=`
|
|
180
|
+
Please report this to https://github.com/markedjs/marked.`,r){let s="<p>An error occurred:</p><pre>"+A(t.message+"",!0)+"</pre>";return e?Promise.resolve(s):s}if(e)return Promise.reject(t);throw t}}},I=new ii;function x(r,e){return I.parse(r,e)}x.options=x.setOptions=function(r){return I.setOptions(r),x.defaults=I.defaults,ft(x.defaults),x};x.getDefaults=Se;x.defaults=M;function ri(...r){return I.use(...r),x.defaults=I.defaults,ft(x.defaults),x}x.use=ri;x.walkTokens=function(r,e){return I.walkTokens(r,e)};x.parseInline=I.parseInline;x.Parser=w;x.parser=w.parse;x.Renderer=re;x.TextRenderer=Pe;x.Lexer=y;x.lexer=y.lex;x.Tokenizer=ie;x.Hooks=Z;x.parse=x;x.options;x.setOptions;x.walkTokens;x.parseInline;w.parse;y.lex;/**
|
|
166
181
|
* @license
|
|
167
182
|
* Copyright 2017 Google LLC
|
|
168
183
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
@@ -170,7 +185,7 @@ Please report this to https://github.com/markedjs/marked.`,r){let s="<p>An error
|
|
|
170
185
|
* @license
|
|
171
186
|
* Copyright 2017 Google LLC
|
|
172
187
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
173
|
-
*/class xe extends oi{constructor(e){if(super(e),this.it=
|
|
188
|
+
*/class xe extends oi{constructor(e){if(super(e),this.it=b,e.type!==ni.CHILD)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===b||e==null)return this._t=void 0,this.it=e;if(e===D)return e;if(typeof e!="string")throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}xe.directiveName="unsafeHTML",xe.resultType=1;const li=ai(xe);let et=0;class ci extends _{static{this.properties={tags:{attribute:!1},active:{attribute:!1},onToggle:{attribute:!1},allowCreate:{attribute:!1},width:{attribute:!1}}}#e=new u("");#t=new u(!1);#s=new u(-1);#r;#i;static{this.styles=O`
|
|
174
189
|
:host {
|
|
175
190
|
display: inline-block;
|
|
176
191
|
position: relative;
|
|
@@ -600,7 +615,7 @@ Please report this to https://github.com/markedjs/marked.`,r){let s="<p>An error
|
|
|
600
615
|
>
|
|
601
616
|
${this.text}
|
|
602
617
|
</div>
|
|
603
|
-
`}}customElements.define("help-tooltip",gi);const st="mem-bucket-detail-view-mode";function fi(r){return new Intl.DateTimeFormat("en-CA",{year:"numeric",month:"2-digit",day:"2-digit"}).format(new Date(r))}const bi=["stable","beta","unreviewed"],mi=["active","shipped","abandoned"],it=["plan","spec","sql","testing-todo","discovery","session-summary","other"],xi=["ticket","freeform"],$={description:"What this doc is / does, shown in search results and list views. For skills, this is also the only thing an agent sees before deciding whether to load the full body — so state both what it does and when to use it.",tags:"Free-form keywords used to filter and search. Not the only thing matched during full-text search, but the fastest way to narrow a list view.",status:`Lifecycle state — stable/beta/unreviewed for skills, active/shipped/abandoned for memory docs. Skills default to "unreviewed" if left unset, so low-trust content doesn't read as equivalent to a reviewed pattern.`,name:"The skill's identifier — becomes its containing folder name on disk. Lowercase letters, numbers, and hyphens only.",owner:"Who authored or maintains this skill — a person or team name, free text.",extends:"Name of another skill this one builds on or specializes, if any. Leave blank if it doesn't extend anything.",trigger_phrases:"Extra keyword phrases beyond the description that should surface this skill in search — phrasings a user might type that don't literally appear in the description text.",key:"The lookup handle for this memory doc — usually a ticket ID, sometimes a free-form name. One key can have several docs attached (a plan, a spec, session notes) all retrievable together.",key_type:'"ticket" if the key is a real ticket ID, "freeform" for a name like "Spot Chart Design".',doc_type:"What kind of content this is — shapes how it should be read (a plan reads differently than raw SQL or a session summary).",related_to:"Another key this doc relates to, if any — free text, not validated against existing keys."};function rt(r){return{description:r.description??"",tags:r.tags??[],status:r.status??"",name:r.name??"",owner:r.owner??"",extends:r.extends??"",trigger_phrases:r.trigger_phrases??[],key:r.key??"",key_type:r.key_type??"",doc_type:r.doc_type??"",related_to:r.related_to??""}}class ki extends _{constructor(){super(...arguments),this._viewMode=localStorage.getItem(st)??"markdown",this._editing=!1,this._draft=null,this._addingFrontmatter=!1,this._renaming=!1,this._renameValue=""}static{this.properties={selected:{attribute:!1},onChanged:{attribute:!1},facets:{attribute:!1},onTagClick:{attribute:!1},onFolderClick:{attribute:!1},onDateClick:{attribute:!1},_doc:{state:!0},_viewMode:{state:!0},_editing:{state:!0},_draft:{state:!0},_addingFrontmatter:{state:!0},_renaming:{state:!0},_renameValue:{state:!0}}}static{this.styles=O`
|
|
618
|
+
`}}customElements.define("help-tooltip",gi);const st="mem-bucket-detail-view-mode";function fi(r){return new Intl.DateTimeFormat("en-CA",{year:"numeric",month:"2-digit",day:"2-digit"}).format(new Date(r))}const bi=["stable","beta","unreviewed"],mi=["active","shipped","abandoned"],it=["plan","spec","sql","testing-todo","discovery","session-summary","other"],xi=["ticket","freeform"],$={description:"What this doc is / does, shown in search results and list views. For skills, this is also the only thing an agent sees before deciding whether to load the full body — so state both what it does and when to use it.",tags:"Free-form keywords used to filter and search. Not the only thing matched during full-text search, but the fastest way to narrow a list view.",status:`Lifecycle state — stable/beta/unreviewed for skills, active/shipped/abandoned for memory docs. Skills default to "unreviewed" if left unset, so low-trust content doesn't read as equivalent to a reviewed pattern.`,name:"The skill's identifier — becomes its containing folder name on disk. Lowercase letters, numbers, and hyphens only.",owner:"Who authored or maintains this skill — a person or team name, free text.",extends:"Name of another skill this one builds on or specializes, if any. Leave blank if it doesn't extend anything.",trigger_phrases:"Extra keyword phrases beyond the description that should surface this skill in search — phrasings a user might type that don't literally appear in the description text.",key:"The lookup handle for this memory doc — usually a ticket ID, sometimes a free-form name. One key can have several docs attached (a plan, a spec, session notes) all retrievable together.",key_type:'"ticket" if the key is a real ticket ID, "freeform" for a name like "Spot Chart Design".',doc_type:"What kind of content this is — shapes how it should be read (a plan reads differently than raw SQL or a session summary).",related_to:"Another key this doc relates to, if any — free text, not validated against existing keys."};function rt(r){return{description:r.description??"",tags:r.tags??[],status:r.status??"",name:r.name??"",owner:r.owner??"",extends:r.extends??"",trigger_phrases:r.trigger_phrases??[],key:r.key??"",key_type:r.key_type??"",doc_type:r.doc_type??"",related_to:r.related_to??""}}class ki extends _{constructor(){super(...arguments),this._viewMode=localStorage.getItem(st)??"markdown",this._editing=!1,this._draft=null,this._addingFrontmatter=!1,this._renaming=!1,this._renameValue=""}static{this.properties={selected:{attribute:!1},onChanged:{attribute:!1},facets:{attribute:!1},onTagClick:{attribute:!1},onFolderClick:{attribute:!1},onDateClick:{attribute:!1},onKeyClick:{attribute:!1},_doc:{state:!0},_viewMode:{state:!0},_editing:{state:!0},_draft:{state:!0},_addingFrontmatter:{state:!0},_renaming:{state:!0},_renameValue:{state:!0}}}static{this.styles=O`
|
|
604
619
|
:host { display: block; padding: 16px; }
|
|
605
620
|
h2 { margin: 0 0 4px; font-size: 16px; }
|
|
606
621
|
.title-row {
|
|
@@ -611,6 +626,17 @@ Please report this to https://github.com/markedjs/marked.`,r){let s="<p>An error
|
|
|
611
626
|
margin-bottom: 10px;
|
|
612
627
|
}
|
|
613
628
|
.title-row h2 { margin: 0; }
|
|
629
|
+
.title-link {
|
|
630
|
+
background: none; border: none; padding: 0; margin: 0; font: inherit; font-weight: inherit;
|
|
631
|
+
color: inherit; cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
|
|
632
|
+
text-align: left;
|
|
633
|
+
}
|
|
634
|
+
.title-link:hover { opacity: 0.8; }
|
|
635
|
+
.key-link {
|
|
636
|
+
background: none; border: none; padding: 0; margin: 0; font: inherit;
|
|
637
|
+
color: inherit; cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
|
|
638
|
+
}
|
|
639
|
+
.key-link:hover { opacity: 0.8; }
|
|
614
640
|
.pill {
|
|
615
641
|
border: 1px solid var(--border-strong);
|
|
616
642
|
border-radius: 999px;
|
|
@@ -675,6 +701,27 @@ Please report this to https://github.com/markedjs/marked.`,r){let s="<p>An error
|
|
|
675
701
|
.info-grid .date-value:hover { opacity: 0.75; }
|
|
676
702
|
.info-grid .hint { opacity: 0.5; font-style: italic; }
|
|
677
703
|
.bare-notice { font-size: 12px; opacity: 0.6; font-style: italic; margin-bottom: 12px; }
|
|
704
|
+
.attachments-section {
|
|
705
|
+
font-size: 12px;
|
|
706
|
+
margin-bottom: 12px;
|
|
707
|
+
}
|
|
708
|
+
.attachments-section h4 {
|
|
709
|
+
margin: 0 0 6px;
|
|
710
|
+
font-size: 10.5px;
|
|
711
|
+
text-transform: uppercase;
|
|
712
|
+
letter-spacing: 0.04em;
|
|
713
|
+
opacity: 0.55;
|
|
714
|
+
font-weight: 600;
|
|
715
|
+
}
|
|
716
|
+
.attachments-section ul {
|
|
717
|
+
list-style: none;
|
|
718
|
+
margin: 0;
|
|
719
|
+
padding: 0;
|
|
720
|
+
display: flex;
|
|
721
|
+
flex-direction: column;
|
|
722
|
+
gap: 4px;
|
|
723
|
+
}
|
|
724
|
+
.attachment-meta { opacity: 0.55; font-size: 11px; }
|
|
678
725
|
.source-path {
|
|
679
726
|
font-family: monospace;
|
|
680
727
|
font-size: 11px;
|
|
@@ -971,9 +1018,13 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
971
1018
|
<button class="cancel" @click=${()=>this.#h()}>Cancel</button>
|
|
972
1019
|
</div>
|
|
973
1020
|
</div>
|
|
974
|
-
`}#g(e){return h`
|
|
1021
|
+
`}#g(e,t){const s=t?void 0:e.key;return h`
|
|
975
1022
|
<div class="title-row">
|
|
976
|
-
<h2
|
|
1023
|
+
<h2>
|
|
1024
|
+
${s?h`<button class="title-link" title="Search for key '${s}'" @click=${()=>this.onKeyClick?.(s)}>
|
|
1025
|
+
${e.name??s??e.id}
|
|
1026
|
+
</button>`:e.name??e.key??e.id}
|
|
1027
|
+
</h2>
|
|
977
1028
|
<button class="pill folder-pill" title="Filter by folder '${e.folder}'" @click=${()=>this.onFolderClick?.(e.folder)}>
|
|
978
1029
|
📁 ${e.folder}
|
|
979
1030
|
</button>
|
|
@@ -994,19 +1045,23 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
994
1045
|
${e.deprecated||e.paused?h`
|
|
995
1046
|
<dt>Flags</dt>
|
|
996
1047
|
<dd>
|
|
997
|
-
${e.deprecated?h`<span class="pill warn-pill">deprecated</span>`:
|
|
998
|
-
${e.paused?h`<span class="pill muted-pill">paused</span>`:
|
|
1048
|
+
${e.deprecated?h`<span class="pill warn-pill">deprecated</span>`:b}
|
|
1049
|
+
${e.paused?h`<span class="pill muted-pill">paused</span>`:b}
|
|
999
1050
|
</dd>
|
|
1000
|
-
`:
|
|
1051
|
+
`:b}
|
|
1001
1052
|
|
|
1002
1053
|
${t?h`
|
|
1003
1054
|
${e.owner?h`<dt>Owner</dt>
|
|
1004
|
-
<dd>${e.owner}</dd>`:
|
|
1055
|
+
<dd>${e.owner}</dd>`:b}
|
|
1005
1056
|
${e.extends?h`<dt>Extends</dt>
|
|
1006
|
-
<dd>${e.extends}</dd>`:
|
|
1057
|
+
<dd>${e.extends}</dd>`:b}
|
|
1007
1058
|
`:h`
|
|
1008
1059
|
<dt>Key</dt>
|
|
1009
|
-
<dd
|
|
1060
|
+
<dd>
|
|
1061
|
+
<button class="key-link" title="Search for this key" @click=${()=>e.key&&this.onKeyClick?.(e.key)}>
|
|
1062
|
+
${e.key}
|
|
1063
|
+
</button>
|
|
1064
|
+
</dd>
|
|
1010
1065
|
|
|
1011
1066
|
<dt>Key type</dt>
|
|
1012
1067
|
<dd>${e.key_type}</dd>
|
|
@@ -1015,7 +1070,7 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1015
1070
|
<dd>${e.doc_type}</dd>
|
|
1016
1071
|
|
|
1017
1072
|
${e.related_to?h`<dt>Related to</dt>
|
|
1018
|
-
<dd>${e.related_to}</dd>`:
|
|
1073
|
+
<dd>${e.related_to}</dd>`:b}
|
|
1019
1074
|
`}
|
|
1020
1075
|
|
|
1021
1076
|
<dt>Created</dt>
|
|
@@ -1025,17 +1080,31 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1025
1080
|
>`:h`<span class="hint">unknown</span>`}
|
|
1026
1081
|
</dd>
|
|
1027
1082
|
</dl>
|
|
1028
|
-
`}
|
|
1029
|
-
|
|
1083
|
+
`}#w(e,t){const s=new x.Renderer,i=s.link.bind(s);return s.link=n=>{if(typeof n.href=="string"&&n.href.startsWith("attachment://")){const a=n.href.slice(13);return i({...n,href:`/api/entries/${e}/${encodeURIComponent(t)}/attachments/${encodeURIComponent(a)}`})}return i(n)},s}#S(e,t){return e.attachments?.length?h`
|
|
1084
|
+
<div class="attachments-section">
|
|
1085
|
+
<h4>Attachments</h4>
|
|
1086
|
+
<ul>
|
|
1087
|
+
${e.attachments.map(s=>h`
|
|
1088
|
+
<li>
|
|
1089
|
+
<a href="/api/entries/${t}/${encodeURIComponent(e.id)}/attachments/${encodeURIComponent(s.filename)}" target="_blank" rel="noopener"
|
|
1090
|
+
>${s.filename}</a
|
|
1091
|
+
>
|
|
1092
|
+
<span class="attachment-meta">(${s.mime_type}, ${s.size} bytes)</span>
|
|
1093
|
+
</li>
|
|
1094
|
+
`)}
|
|
1095
|
+
</ul>
|
|
1096
|
+
</div>
|
|
1097
|
+
`:b}render(){if(!this.selected)return h`<div class="empty">Select an entry to view its details.</div>`;if(!this._doc)return b;const e=this._doc,t=this.selected.table==="skills",s=t&&e.folder==="builtin",i=!t&&e.has_frontmatter===!1;return this._addingFrontmatter?h`${this.#g(e,t)}${this.#x()}`:this._editing&&this._draft?h`${this.#g(e,t)}${this.#v(t)}`:h`
|
|
1098
|
+
${this.#g(e,t)}
|
|
1030
1099
|
${i?h`<div class="bare-notice">No frontmatter — this is a plain, unmanaged file.</div>`:this.#y(e,t)}
|
|
1031
|
-
${s?
|
|
1100
|
+
${s?b:h`
|
|
1032
1101
|
<div class="actions">
|
|
1033
1102
|
${i?h`<button class="primary" @click=${()=>this.#o()}>Add frontmatter</button>`:h`
|
|
1034
1103
|
<button @click=${()=>this.#a()}>Edit</button>
|
|
1035
|
-
${t?h`<button @click=${()=>this.#m()}>Rename</button>`:
|
|
1104
|
+
${t?h`<button @click=${()=>this.#m()}>Rename</button>`:b}
|
|
1036
1105
|
<button @click=${()=>this.#r()}>${e.deprecated?"Un-deprecate":"Mark deprecated"}</button>
|
|
1037
1106
|
<button @click=${()=>this.#i()}>${e.paused?"Resume":"Pause"}</button>
|
|
1038
|
-
${t?
|
|
1107
|
+
${t?b:h`<button class="danger" @click=${()=>this.#b()}>Delete frontmatter</button>`}
|
|
1039
1108
|
`}
|
|
1040
1109
|
<button class="danger" @click=${()=>this.#d()}>Delete</button>
|
|
1041
1110
|
</div>
|
|
@@ -1050,8 +1119,9 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1050
1119
|
<button @click=${()=>this.#k()}>Save</button>
|
|
1051
1120
|
<button @click=${()=>this._renaming=!1}>Cancel</button>
|
|
1052
1121
|
</div>
|
|
1053
|
-
`:
|
|
1122
|
+
`:b}
|
|
1054
1123
|
`}
|
|
1124
|
+
${this.#S(e,this.selected.table)}
|
|
1055
1125
|
<div class="view-toggle">
|
|
1056
1126
|
<button
|
|
1057
1127
|
class=${this._viewMode==="markdown"?"active":""}
|
|
@@ -1066,7 +1136,7 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1066
1136
|
Raw
|
|
1067
1137
|
</button>
|
|
1068
1138
|
</div>
|
|
1069
|
-
${this._viewMode==="markdown"?h`<div class="markdown-body">${li(x.parse(e.body??"",{async:!1}))}</div>`:h`<pre>${e.raw_file??e.body}</pre>`}
|
|
1139
|
+
${this._viewMode==="markdown"?h`<div class="markdown-body">${li(x.parse(e.body??"",{async:!1,renderer:this.#w(this.selected.table,e.id)}))}</div>`:h`<pre>${e.raw_file??e.body}</pre>`}
|
|
1070
1140
|
<div class="source-path" title="click to copy" @click=${()=>this.#t()}>${e.source_path}</div>
|
|
1071
1141
|
`}}customElements.define("detail-panel",ki);class vi extends _{static{this.properties={defaultKind:{attribute:!1},lockKind:{attribute:!1},onAdded:{attribute:!1},onCancel:{attribute:!1}}}#e=new u("skill");#t=new u("");#s=new u([]);#r=new u(null);#i=new u("");#d=new u("");#a=new u("");#o=new u(!1);#c=new u(!1);#h=new u(!1);#n=new u("");static{this.styles=O`
|
|
1072
1142
|
:host { display: block; }
|
|
@@ -1433,27 +1503,27 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1433
1503
|
cursor: pointer;
|
|
1434
1504
|
}
|
|
1435
1505
|
.bulk-bar button.danger { border-color: var(--danger); color: var(--danger); }
|
|
1436
|
-
`}#e=Ci();#t=new u(this.#e.query??"");#s=new u(this.#e.typeFilter??"all");#r=new u(this.#e.activeTags??[]);#i=new u(this.#e.activeFolders??[]);#d=new u([]);#a=new u(yi);#o=new u(null);#c=new u(wi);#h=new u(!1);#n=new u("");#p=new u(!1);#u=new u(_i());#f=new u(!1);#b=new u(this.#e.sort??"mtime_desc");#m=new u(this.#e.deprecatedFilter??"all");#k=new u(this.#e.pausedFilter??"all");#x=new u(this.#e.dateFrom??"");#v=new u(this.#e.dateTo??"");#g=new u(new Set);#y=new u(Ti());#
|
|
1506
|
+
`}#e=Ci();#t=new u(this.#e.query??"");#s=new u(this.#e.typeFilter??"all");#r=new u(this.#e.activeTags??[]);#i=new u(this.#e.activeFolders??[]);#d=new u([]);#a=new u(yi);#o=new u(null);#c=new u(wi);#h=new u(!1);#n=new u("");#p=new u(!1);#u=new u(_i());#f=new u(!1);#b=new u(this.#e.sort??"mtime_desc");#m=new u(this.#e.deprecatedFilter??"all");#k=new u(this.#e.pausedFilter??"all");#x=new u(this.#e.dateFrom??"");#v=new u(this.#e.dateTo??"");#g=new u(new Set);#y=new u(Ti());#w=new u(!1);#S=e=>this.#N(e);#C=()=>this.#F();constructor(){super(),new oe(this),at(this.#y.value)}#D(e){this.#y.set(e),localStorage.setItem(Ct,e),at(e)}#I(){const e=de[(de.indexOf(this.#y.value)+1)%de.length];this.#D(e)}async#O(){if(!this.#w.value){this.#w.set(!0);try{await fetch("/api/rebuild-cache",{method:"POST"}),await Promise.all([this.#_(),this.#$(),this.#l()])}finally{this.#w.set(!1)}}}#M(e){e.preventDefault(),this.#f.set(!0),document.addEventListener("pointermove",this.#S),document.addEventListener("pointerup",this.#C)}#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.#u.set(Math.min(Tt,Math.max(At,i)))}#F(){this.#f.set(!1),document.removeEventListener("pointermove",this.#S),document.removeEventListener("pointerup",this.#C),localStorage.setItem(St,String(this.#u.value))}#q=new is(()=>{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.#r.value)e.append("tag",t);for(const t of this.#i.value)e.append("folder",t);return this.#b.value!=="mtime_desc"&&e.set("sort",this.#b.value),this.#m.value==="hide"?e.set("deprecated","0"):this.#m.value==="only"&&e.set("deprecated","1"),this.#k.value==="hide"?e.set("paused","0"):this.#k.value==="only"&&e.set("paused","1"),this.#x.value&&e.set("date_from",this.#x.value),this.#v.value&&e.set("date_to",this.#v.value),e.toString()});#A=()=>this.#U();connectedCallback(){super.connectedCallback(),this.#l(),this.#$(),this.#_(),window.addEventListener("focus",this.#A),document.addEventListener("visibilitychange",this.#A)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("focus",this.#A),document.removeEventListener("visibilitychange",this.#A)}#U(){document.visibilityState==="visible"&&(this.#l(),this.#$(),this.#_())}async#l(){const e=this.#q.value;history.replaceState(null,"",e?`#${e}`:location.pathname+location.search);const t=await fetch(`/api/entries?${e}`);this.#d.set(await t.json()),this.renderRoot.querySelector("result-list")?.scrollTo(0,0)}async#$(){const e=this.#s.value==="all"?"":`?type=${this.#s.value}`,t=await fetch(`/api/facets${e}`);this.#a.set(await t.json())}async#_(){const e=await fetch("/api/folders");this.#c.set(await e.json()),this.#p.set(!0)}#H(e){const t=this.#i.value;this.#i.set(t.includes(e)?t.filter(s=>s!==e):[...t,e]),this.#l()}async#B(e,t){if(t.stopPropagation(),window.prompt(`Type "${e.name}" to remove this ${e.kind} folder (files on disk are untouched):`)===e.name){this.#n.set(e.name);try{await fetch(`/api/folders/${e.kind}/${encodeURIComponent(e.name)}`,{method:"DELETE"}),this.#i.set(this.#i.value.filter(i=>i!==e.name)),await Promise.all([this.#_(),this.#$(),this.#l()])}finally{this.#n.set("")}}}#E(){this.#h.set(!1),this.#_(),this.#$(),this.#l()}#j(){return[...this.#c.value.skill,...this.#c.value.memory]}#K(e){this.#s.set(e),this.#r.set([]),this.#$(),this.#l()}#Z(e){const t=this.#r.value;this.#r.set(t.includes(e)?t.filter(s=>s!==e):[...t,e]),this.#l()}#W(e){this.#r.value.includes(e)||this.#r.set([...this.#r.value,e]),this.#l()}#Q(e){this.#i.value.includes(e)||this.#i.set([...this.#i.value,e]),this.#l()}#V(e){this.#x.set(e),this.#v.set(e),this.#l()}#Y(e){this.#t.set(e.target.value),this.#l()}#R(e){this.#t.set(e),this.#l()}#G(){this.#t.set(""),this.#l()}#J(e){this.#o.set({table:e._table,id:e.id})}#X(e){this.#b.set(e.target.value),this.#l()}#ee(e){this.#m.set(e.target.value),this.#l()}#te(e){this.#k.set(e.target.value),this.#l()}#se(e){this.#x.set(e.target.value),this.#l()}#ie(e){this.#v.set(e.target.value),this.#l()}#re(){this.#x.set(""),this.#v.set(""),this.#l()}#ne(e){const t=new Set(this.#g.value);t.has(e.id)?t.delete(e.id):t.add(e.id),this.#g.set(t)}#ae(){return new Map(this.#d.value.map(e=>[e.id,e]))}#T(){const e=new Map,t=this.#ae();for(const s of this.#g.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#z(e){const t=this.#T();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.#g.set(new Set),await this.#l()}async#P(e){const t=this.#T();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.#g.set(new Set),await this.#l()}async#oe(){if(!window.confirm(`Delete ${this.#g.value.size} doc(s)? This can't be undone.`))return;const e=this.#T();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.#g.set(new Set),await this.#l()}#L(){const e=this.#y.value;return h`
|
|
1437
1507
|
<button
|
|
1438
1508
|
class="theme-toggle"
|
|
1439
1509
|
title=${`Theme: ${Ai[e]} (click to change)`}
|
|
1440
1510
|
aria-label="Toggle color theme"
|
|
1441
|
-
@click=${()=>this.#
|
|
1511
|
+
@click=${()=>this.#I()}
|
|
1442
1512
|
>
|
|
1443
1513
|
${Si[e]}
|
|
1444
1514
|
</button>
|
|
1445
|
-
`}#
|
|
1515
|
+
`}#le(){const e=this.#w.value;return h`
|
|
1446
1516
|
<button
|
|
1447
1517
|
class=${`reindex-toggle${e?" spinning":""}`}
|
|
1448
1518
|
title=${e?"Reindexing…":"Rebuild cache from disk"}
|
|
1449
1519
|
aria-label="Rebuild cache from disk"
|
|
1450
1520
|
?disabled=${e}
|
|
1451
|
-
@click=${()=>this.#
|
|
1521
|
+
@click=${()=>this.#O()}
|
|
1452
1522
|
>
|
|
1453
1523
|
♻
|
|
1454
1524
|
</button>
|
|
1455
|
-
`}render(){const e=this.#a.value,t=this.#
|
|
1456
|
-
${this.#
|
|
1525
|
+
`}render(){const e=this.#a.value,t=this.#j();return this.#p.value&&t.length===0&&!this.#h.value?h`
|
|
1526
|
+
${this.#L()}
|
|
1457
1527
|
<div class="first-run">
|
|
1458
1528
|
<h1>No folders configured yet</h1>
|
|
1459
1529
|
<p>
|
|
@@ -1469,21 +1539,21 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1469
1539
|
.onCancel=${()=>this.#h.set(!1)}
|
|
1470
1540
|
></add-folder-modal>`:""}
|
|
1471
1541
|
`:h`
|
|
1472
|
-
${this.#
|
|
1473
|
-
${this.#
|
|
1542
|
+
${this.#le()}
|
|
1543
|
+
${this.#L()}
|
|
1474
1544
|
<div class="folders-bar">
|
|
1475
1545
|
<span class="filter-label">Folders:</span>
|
|
1476
1546
|
${t.map(s=>h`
|
|
1477
1547
|
<button
|
|
1478
1548
|
class="folder-chip ${this.#i.value.includes(s.name)?"active":""}"
|
|
1479
1549
|
title=${s.path}
|
|
1480
|
-
@click=${()=>this.#
|
|
1550
|
+
@click=${()=>this.#H(s.name)}
|
|
1481
1551
|
>
|
|
1482
1552
|
📁 ${s.name}
|
|
1483
1553
|
<span
|
|
1484
1554
|
class="remove"
|
|
1485
1555
|
title="Remove folder"
|
|
1486
|
-
@click=${i=>this.#
|
|
1556
|
+
@click=${i=>this.#B(s,i)}
|
|
1487
1557
|
>${this.#n.value===s.name?"…":"✕"}</span
|
|
1488
1558
|
>
|
|
1489
1559
|
</button>
|
|
@@ -1497,14 +1567,14 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1497
1567
|
type="search"
|
|
1498
1568
|
placeholder="Search descriptions, bodies, tags..."
|
|
1499
1569
|
.value=${this.#t.value}
|
|
1500
|
-
@input=${s=>this.#
|
|
1570
|
+
@input=${s=>this.#Y(s)}
|
|
1501
1571
|
/>
|
|
1502
1572
|
${this.#t.value?h`
|
|
1503
1573
|
<button
|
|
1504
1574
|
class="search-clear-btn"
|
|
1505
1575
|
title="Clear search"
|
|
1506
1576
|
aria-label="Clear search"
|
|
1507
|
-
@click=${()=>this.#
|
|
1577
|
+
@click=${()=>this.#G()}
|
|
1508
1578
|
>
|
|
1509
1579
|
✕
|
|
1510
1580
|
</button>
|
|
@@ -1514,7 +1584,7 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1514
1584
|
${$i.map(s=>h`
|
|
1515
1585
|
<button
|
|
1516
1586
|
class=${this.#s.value===s.value?"active":""}
|
|
1517
|
-
@click=${()=>this.#
|
|
1587
|
+
@click=${()=>this.#K(s.value)}
|
|
1518
1588
|
>
|
|
1519
1589
|
${s.label}
|
|
1520
1590
|
</button>
|
|
@@ -1534,39 +1604,39 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1534
1604
|
type="date"
|
|
1535
1605
|
aria-label="From date"
|
|
1536
1606
|
.value=${this.#x.value}
|
|
1537
|
-
@change=${s=>this.#
|
|
1607
|
+
@change=${s=>this.#se(s)}
|
|
1538
1608
|
/>
|
|
1539
1609
|
<span class="date-range-sep">–</span>
|
|
1540
1610
|
<input
|
|
1541
1611
|
type="date"
|
|
1542
1612
|
aria-label="To date"
|
|
1543
1613
|
.value=${this.#v.value}
|
|
1544
|
-
@change=${s=>this.#
|
|
1614
|
+
@change=${s=>this.#ie(s)}
|
|
1545
1615
|
/>
|
|
1546
1616
|
${this.#x.value||this.#v.value?h`
|
|
1547
1617
|
<button
|
|
1548
1618
|
class="date-range-clear"
|
|
1549
1619
|
title="Clear date range"
|
|
1550
1620
|
aria-label="Clear date range"
|
|
1551
|
-
@click=${()=>this.#
|
|
1621
|
+
@click=${()=>this.#re()}
|
|
1552
1622
|
>
|
|
1553
1623
|
✕
|
|
1554
1624
|
</button>
|
|
1555
1625
|
`:""}
|
|
1556
1626
|
</div>
|
|
1557
1627
|
<span class="filter-label">Sort:</span>
|
|
1558
|
-
<select .value=${this.#b.value} @change=${s=>this.#
|
|
1628
|
+
<select .value=${this.#b.value} @change=${s=>this.#X(s)}>
|
|
1559
1629
|
<option value="mtime_desc">Recently touched</option>
|
|
1560
1630
|
<option value="mtime_asc">Least recently touched</option>
|
|
1561
1631
|
<option value="created_at_asc">Oldest first</option>
|
|
1562
1632
|
<option value="name_asc">Name</option>
|
|
1563
1633
|
</select>
|
|
1564
1634
|
<span class="filter-label">Deprecated:</span>
|
|
1565
|
-
<select .value=${this.#m.value} @change=${s=>this.#
|
|
1635
|
+
<select .value=${this.#m.value} @change=${s=>this.#ee(s)}>
|
|
1566
1636
|
${nt.map(s=>h`<option value=${s.value}>${s.label}</option>`)}
|
|
1567
1637
|
</select>
|
|
1568
1638
|
<span class="filter-label">Paused:</span>
|
|
1569
|
-
<select .value=${this.#k.value} @change=${s=>this.#
|
|
1639
|
+
<select .value=${this.#k.value} @change=${s=>this.#te(s)}>
|
|
1570
1640
|
${nt.map(s=>h`<option value=${s.value}>${s.label}</option>`)}
|
|
1571
1641
|
</select>
|
|
1572
1642
|
</div>
|
|
@@ -1574,11 +1644,11 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1574
1644
|
${this.#g.value.size>0?h`
|
|
1575
1645
|
<div class="bulk-bar">
|
|
1576
1646
|
<span>${this.#g.value.size} selected</span>
|
|
1577
|
-
<button @click=${()=>this.#
|
|
1578
|
-
<button @click=${()=>this.#
|
|
1579
|
-
<button @click=${()=>this.#
|
|
1580
|
-
<button @click=${()=>this.#
|
|
1581
|
-
<button class="danger" @click=${()=>this.#
|
|
1647
|
+
<button @click=${()=>this.#z(!0)}>Mark deprecated</button>
|
|
1648
|
+
<button @click=${()=>this.#z(!1)}>Un-deprecate</button>
|
|
1649
|
+
<button @click=${()=>this.#P(!0)}>Pause</button>
|
|
1650
|
+
<button @click=${()=>this.#P(!1)}>Resume</button>
|
|
1651
|
+
<button class="danger" @click=${()=>this.#oe()}>Delete</button>
|
|
1582
1652
|
<button @click=${()=>this.#g.set(new Set)}>Clear</button>
|
|
1583
1653
|
</div>
|
|
1584
1654
|
`:""}
|
|
@@ -1587,21 +1657,23 @@ This removes the doc's key, tags, and status — it drops out of key-based looku
|
|
|
1587
1657
|
style=${`width: ${this.#u.value}%; border-right: 1px solid var(--border);`}
|
|
1588
1658
|
.results=${this.#d.value}
|
|
1589
1659
|
.showFolder=${t.length>1}
|
|
1590
|
-
.onSelect=${s=>this.#
|
|
1660
|
+
.onSelect=${s=>this.#J(s)}
|
|
1591
1661
|
.selectedIds=${this.#g.value}
|
|
1592
|
-
.onToggleSelect=${s=>this.#
|
|
1662
|
+
.onToggleSelect=${s=>this.#ne(s)}
|
|
1663
|
+
.onKeyClick=${s=>this.#R(s)}
|
|
1593
1664
|
></result-list>
|
|
1594
1665
|
<div
|
|
1595
1666
|
class="splitter ${this.#f.value?"dragging":""}"
|
|
1596
|
-
@pointerdown=${s=>this.#
|
|
1667
|
+
@pointerdown=${s=>this.#M(s)}
|
|
1597
1668
|
></div>
|
|
1598
1669
|
<detail-panel
|
|
1599
1670
|
.selected=${this.#o.value}
|
|
1600
1671
|
.facets=${e}
|
|
1601
1672
|
.onChanged=${()=>{this.#l(),this.#$()}}
|
|
1602
|
-
.onTagClick=${s=>this.#
|
|
1673
|
+
.onTagClick=${s=>this.#W(s)}
|
|
1603
1674
|
.onFolderClick=${s=>this.#Q(s)}
|
|
1604
|
-
.onDateClick=${s=>this.#
|
|
1675
|
+
.onDateClick=${s=>this.#V(s)}
|
|
1676
|
+
.onKeyClick=${s=>this.#R(s)}
|
|
1605
1677
|
></detail-panel>
|
|
1606
1678
|
</div>
|
|
1607
1679
|
${this.#h.value?h`<add-folder-modal
|
package/dist/client/index.html
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
:root[data-theme='dark'] { color-scheme: dark; }
|
|
28
28
|
body { font-family: system-ui, sans-serif; margin: 0; background: var(--bg); color: var(--fg); }
|
|
29
29
|
</style>
|
|
30
|
-
<script type="module" crossorigin src="/assets/index-
|
|
30
|
+
<script type="module" crossorigin src="/assets/index-PIigsGBG.js"></script>
|
|
31
31
|
</head>
|
|
32
32
|
<body>
|
|
33
33
|
<mem-bucket-app></mem-bucket-app>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { attachmentsDirFor, writeAttachmentFile, listAttachmentFiles } from './storage.js';
|
|
4
|
+
import { resolveWithinBase } from '../store/safe-path.js';
|
|
5
|
+
export class AttachmentRepository {
|
|
6
|
+
memoryRepo;
|
|
7
|
+
skillRepo;
|
|
8
|
+
constructor(memoryRepo, skillRepo) {
|
|
9
|
+
this.memoryRepo = memoryRepo;
|
|
10
|
+
this.skillRepo = skillRepo;
|
|
11
|
+
}
|
|
12
|
+
getDoc(kind, docIdOrName) {
|
|
13
|
+
const doc = kind === 'memory' ? this.memoryRepo.get(docIdOrName) : this.skillRepo.get(docIdOrName);
|
|
14
|
+
if (!doc)
|
|
15
|
+
throw new Error(`${kind} doc "${docIdOrName}" not found`);
|
|
16
|
+
return doc;
|
|
17
|
+
}
|
|
18
|
+
saveAttachmentsList(kind, docIdOrName, attachments) {
|
|
19
|
+
if (kind === 'memory') {
|
|
20
|
+
this.memoryRepo.update(docIdOrName, { attachments });
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
this.skillRepo.update(docIdOrName, { attachments });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
add(kind, docIdOrName, filename, data) {
|
|
27
|
+
const doc = this.getDoc(kind, docIdOrName);
|
|
28
|
+
const dir = attachmentsDirFor(doc.source_path, kind);
|
|
29
|
+
const entry = writeAttachmentFile(dir, filename, data);
|
|
30
|
+
const existing = doc.attachments ?? [];
|
|
31
|
+
this.saveAttachmentsList(kind, docIdOrName, [...existing, entry]);
|
|
32
|
+
return entry;
|
|
33
|
+
}
|
|
34
|
+
get(kind, docIdOrName, filename) {
|
|
35
|
+
const doc = this.getDoc(kind, docIdOrName);
|
|
36
|
+
return (doc.attachments ?? []).find((a) => a.filename === filename);
|
|
37
|
+
}
|
|
38
|
+
update(kind, docIdOrName, filename, data) {
|
|
39
|
+
const doc = this.getDoc(kind, docIdOrName);
|
|
40
|
+
const dir = attachmentsDirFor(doc.source_path, kind);
|
|
41
|
+
const existingEntry = (doc.attachments ?? []).find((a) => a.filename === filename);
|
|
42
|
+
if (!existingEntry)
|
|
43
|
+
throw new Error(`attachment "${filename}" not found on ${kind} doc "${docIdOrName}"`);
|
|
44
|
+
const safePath = resolveWithinBase(dir, undefined, filename);
|
|
45
|
+
fs.rmSync(safePath, { force: true });
|
|
46
|
+
const written = writeAttachmentFile(dir, filename, data);
|
|
47
|
+
// Full replace: preserve position, overwrite metadata for this filename entry.
|
|
48
|
+
const next = (doc.attachments ?? []).map((a) => (a.filename === filename ? written : a));
|
|
49
|
+
this.saveAttachmentsList(kind, docIdOrName, next);
|
|
50
|
+
return written;
|
|
51
|
+
}
|
|
52
|
+
remove(kind, docIdOrName, filename) {
|
|
53
|
+
const doc = this.getDoc(kind, docIdOrName);
|
|
54
|
+
const dir = attachmentsDirFor(doc.source_path, kind);
|
|
55
|
+
const safePath = resolveWithinBase(dir, undefined, filename);
|
|
56
|
+
fs.rmSync(safePath, { force: true });
|
|
57
|
+
const next = (doc.attachments ?? []).filter((a) => a.filename !== filename);
|
|
58
|
+
this.saveAttachmentsList(kind, docIdOrName, next);
|
|
59
|
+
}
|
|
60
|
+
list(kind, docIdOrName) {
|
|
61
|
+
return this.getDoc(kind, docIdOrName).attachments ?? [];
|
|
62
|
+
}
|
|
63
|
+
/** Absolute filesystem path for an attachment's file, for callers (e.g. MCP tools) that need to Read it. */
|
|
64
|
+
absolutePathFor(kind, docIdOrName, filename) {
|
|
65
|
+
const doc = this.getDoc(kind, docIdOrName);
|
|
66
|
+
return path.join(attachmentsDirFor(doc.source_path, kind), filename);
|
|
67
|
+
}
|
|
68
|
+
reconcile(kind, docIdOrName) {
|
|
69
|
+
const doc = this.getDoc(kind, docIdOrName);
|
|
70
|
+
const dir = attachmentsDirFor(doc.source_path, kind);
|
|
71
|
+
const declared = new Set((doc.attachments ?? []).map((a) => a.filename));
|
|
72
|
+
const onDisk = new Set(listAttachmentFiles(dir));
|
|
73
|
+
const orphans = [...declared].filter((f) => !onDisk.has(f));
|
|
74
|
+
const unlisted = [...onDisk].filter((f) => !declared.has(f));
|
|
75
|
+
return { orphans, unlisted };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export { attachmentsDirFor };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { resolveWithinBase } from '../store/safe-path.js';
|
|
4
|
+
import { ATTACHMENT_MAX_BYTES } from '../config.js';
|
|
5
|
+
export { ATTACHMENT_MAX_BYTES };
|
|
6
|
+
/**
|
|
7
|
+
* Skills already live one-per-directory (<skillDir>/SKILL.md), so attachments
|
|
8
|
+
* sit directly in that directory. Memory docs are flat files (<id>.md) with no
|
|
9
|
+
* per-doc directory, so attachments get a new sibling directory named after
|
|
10
|
+
* the doc's id, alongside the existing file.
|
|
11
|
+
*/
|
|
12
|
+
export function attachmentsDirFor(docSourcePath, kind) {
|
|
13
|
+
if (kind === 'skill') {
|
|
14
|
+
return path.join(path.dirname(docSourcePath), 'attachments');
|
|
15
|
+
}
|
|
16
|
+
const dir = path.dirname(docSourcePath);
|
|
17
|
+
const id = path.basename(docSourcePath, '.md');
|
|
18
|
+
return path.join(dir, id, 'attachments');
|
|
19
|
+
}
|
|
20
|
+
const MIME_BY_EXT = {
|
|
21
|
+
'.json': 'application/json',
|
|
22
|
+
'.xml': 'application/xml',
|
|
23
|
+
'.txt': 'text/plain',
|
|
24
|
+
'.png': 'image/png',
|
|
25
|
+
'.jpg': 'image/jpeg',
|
|
26
|
+
'.jpeg': 'image/jpeg',
|
|
27
|
+
'.gif': 'image/gif',
|
|
28
|
+
'.pdf': 'application/pdf',
|
|
29
|
+
'.csv': 'text/csv',
|
|
30
|
+
};
|
|
31
|
+
function guessMimeType(filename) {
|
|
32
|
+
return MIME_BY_EXT[path.extname(filename).toLowerCase()] ?? 'application/octet-stream';
|
|
33
|
+
}
|
|
34
|
+
function uniqueFilename(dir, filename) {
|
|
35
|
+
// Validate that the filename doesn't escape the directory
|
|
36
|
+
resolveWithinBase(dir, undefined, filename);
|
|
37
|
+
if (!fs.existsSync(path.join(dir, filename)))
|
|
38
|
+
return filename;
|
|
39
|
+
const ext = path.extname(filename);
|
|
40
|
+
const base = path.basename(filename, ext);
|
|
41
|
+
let n = 2;
|
|
42
|
+
while (fs.existsSync(path.join(dir, `${base}-${n}${ext}`)))
|
|
43
|
+
n++;
|
|
44
|
+
return `${base}-${n}${ext}`;
|
|
45
|
+
}
|
|
46
|
+
/** `dir` is the attachments directory itself, as returned by attachmentsDirFor. */
|
|
47
|
+
export function writeAttachmentFile(dir, filename, data) {
|
|
48
|
+
if (data.byteLength > ATTACHMENT_MAX_BYTES) {
|
|
49
|
+
throw new Error(`attachment "${filename}" (${data.byteLength} bytes) exceeds the ${ATTACHMENT_MAX_BYTES}-byte limit`);
|
|
50
|
+
}
|
|
51
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
52
|
+
const finalName = uniqueFilename(dir, filename);
|
|
53
|
+
const safePath = resolveWithinBase(dir, undefined, finalName);
|
|
54
|
+
fs.writeFileSync(safePath, data);
|
|
55
|
+
return {
|
|
56
|
+
filename: finalName,
|
|
57
|
+
path: path.join('attachments', finalName),
|
|
58
|
+
mime_type: guessMimeType(finalName),
|
|
59
|
+
size: data.byteLength,
|
|
60
|
+
added_at: new Date().toISOString(),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function listAttachmentFiles(dir) {
|
|
64
|
+
if (!fs.existsSync(dir))
|
|
65
|
+
return [];
|
|
66
|
+
return fs.readdirSync(dir).filter((name) => fs.statSync(path.join(dir, name)).isFile());
|
|
67
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { ATTACHMENT_MAX_BYTES } from './storage.js';
|
|
4
|
+
const kindSchema = z.enum(['memory', 'skill']);
|
|
5
|
+
/** Cheap pre-check so we never read a too-large file's bytes into memory before rejecting it. */
|
|
6
|
+
function assertFileSizeOk(file_path) {
|
|
7
|
+
const { size } = fs.statSync(file_path);
|
|
8
|
+
if (size > ATTACHMENT_MAX_BYTES) {
|
|
9
|
+
throw new Error(`file "${file_path}" (${size} bytes) exceeds the ${ATTACHMENT_MAX_BYTES}-byte limit`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function registerAttachmentTools(mcp, attachRepo) {
|
|
13
|
+
mcp.tool('attachment_add', 'Attaches a raw file (JSON, image, XML, etc.) to a memory doc or skill. Auto-renames on filename collision.', {
|
|
14
|
+
kind: kindSchema,
|
|
15
|
+
doc: z.string().describe('memory doc id or skill name'),
|
|
16
|
+
filename: z.string(),
|
|
17
|
+
file_path: z.string().describe('local filesystem path to the file to attach'),
|
|
18
|
+
}, async ({ kind, doc, filename, file_path }) => {
|
|
19
|
+
try {
|
|
20
|
+
assertFileSizeOk(file_path);
|
|
21
|
+
const data = fs.readFileSync(file_path);
|
|
22
|
+
const entry = attachRepo.add(kind, doc, filename, data);
|
|
23
|
+
const absolute_path = attachRepo.absolutePathFor(kind, doc, entry.filename);
|
|
24
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ...entry, absolute_path }, null, 2) }] };
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
mcp.tool('attachment_get', 'Returns the on-disk path (not content) of an attachment, plus its metadata. Use Read on the returned absolute_path for the content.', { kind: kindSchema, doc: z.string(), filename: z.string() }, async ({ kind, doc, filename }) => {
|
|
31
|
+
try {
|
|
32
|
+
const entry = attachRepo.get(kind, doc, filename);
|
|
33
|
+
if (!entry)
|
|
34
|
+
throw new Error(`attachment "${filename}" not found`);
|
|
35
|
+
const absolute_path = attachRepo.absolutePathFor(kind, doc, entry.filename);
|
|
36
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ...entry, absolute_path }, null, 2) }] };
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
mcp.tool('attachment_update', "Replaces an attachment's content in place.", { kind: kindSchema, doc: z.string(), filename: z.string(), file_path: z.string() }, async ({ kind, doc, filename, file_path }) => {
|
|
43
|
+
try {
|
|
44
|
+
assertFileSizeOk(file_path);
|
|
45
|
+
const data = fs.readFileSync(file_path);
|
|
46
|
+
const entry = attachRepo.update(kind, doc, filename, data);
|
|
47
|
+
const absolute_path = attachRepo.absolutePathFor(kind, doc, entry.filename);
|
|
48
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ...entry, absolute_path }, null, 2) }] };
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
mcp.tool('attachment_remove', 'Deletes an attachment from a memory doc or skill.', { kind: kindSchema, doc: z.string(), filename: z.string() }, async ({ kind, doc, filename }) => {
|
|
55
|
+
try {
|
|
56
|
+
attachRepo.remove(kind, doc, filename);
|
|
57
|
+
return { content: [{ type: 'text', text: `removed "${filename}"` }] };
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
mcp.tool('attachment_list', 'Lists all attachments on a memory doc or skill, each with its absolute on-disk path.', { kind: kindSchema, doc: z.string() }, async ({ kind, doc }) => {
|
|
64
|
+
try {
|
|
65
|
+
const entries = attachRepo.list(kind, doc);
|
|
66
|
+
const withPaths = entries.map((entry) => ({
|
|
67
|
+
...entry,
|
|
68
|
+
absolute_path: attachRepo.absolutePathFor(kind, doc, entry.filename),
|
|
69
|
+
}));
|
|
70
|
+
return { content: [{ type: 'text', text: JSON.stringify(withPaths, null, 2) }] };
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
mcp.tool('attachment_reconcile', "Compares a doc's declared attachments against what is actually on disk; reports orphans (declared but missing) and unlisted files (present but not declared). Report-only, does not repair.", { kind: kindSchema, doc: z.string() }, async ({ kind, doc }) => {
|
|
77
|
+
try {
|
|
78
|
+
const result = attachRepo.reconcile(kind, doc);
|
|
79
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/src/config.js
CHANGED
|
@@ -97,3 +97,6 @@ export function removeFolder(config, kind, name) {
|
|
|
97
97
|
const next = { ...current, [key]: filtered };
|
|
98
98
|
fs.writeFileSync(config.configPath, JSON.stringify(next, null, 2) + '\n');
|
|
99
99
|
}
|
|
100
|
+
export const ATTACHMENT_MAX_BYTES = process.env.ATTACHMENT_MAX_BYTES
|
|
101
|
+
? Number(process.env.ATTACHMENT_MAX_BYTES)
|
|
102
|
+
: 20 * 1024 * 1024; // 20MB default
|
|
@@ -6,6 +6,7 @@ import { slugify } from '../store/slug.js';
|
|
|
6
6
|
import { resolveWithinBase } from '../store/safe-path.js';
|
|
7
7
|
import { upsertFile, removeFile, scanSingleFolder, unregisterFolder, memorySyncSpec } from '../store/sync.js';
|
|
8
8
|
import { SearchQueryError, sanitizeFtsQuery } from '../store/search.js';
|
|
9
|
+
import { attachmentsDirFor } from '../attachments/storage.js';
|
|
9
10
|
import { normalizeKey } from '../types.js';
|
|
10
11
|
/** Uppercases and strips everything but letters/digits — used to compare keys that differ only in
|
|
11
12
|
* punctuation/whitespace formatting (e.g. `RMXS-15` and `RMXS15` strip to the same `RMXS15`). */
|
|
@@ -25,6 +26,7 @@ function rowToDoc(row) {
|
|
|
25
26
|
deprecated: !!row.deprecated,
|
|
26
27
|
paused: !!row.paused,
|
|
27
28
|
created_at: row.created_at ?? undefined,
|
|
29
|
+
attachments: row.attachments ? JSON.parse(row.attachments) : undefined,
|
|
28
30
|
source_path: row.source_path,
|
|
29
31
|
folder: row.folder,
|
|
30
32
|
body: row.body,
|
|
@@ -309,6 +311,10 @@ export class MemoryRepository {
|
|
|
309
311
|
const existing = this.get(id);
|
|
310
312
|
if (!existing)
|
|
311
313
|
throw new Error(`memory doc with id "${id}" not found`);
|
|
314
|
+
// The <id>/ wrapper directory exists solely to hold attachments/ for this doc (memory docs
|
|
315
|
+
// are otherwise flat <id>.md files), so remove the whole wrapper — not just attachments/ —
|
|
316
|
+
// to avoid leaving an orphaned empty <id>/ directory behind. No-op if it never existed.
|
|
317
|
+
fs.rmSync(path.dirname(attachmentsDirFor(existing.source_path, 'memory')), { recursive: true, force: true });
|
|
312
318
|
fs.unlinkSync(existing.source_path);
|
|
313
319
|
removeFile(this.db, 'memory_docs', existing.source_path);
|
|
314
320
|
}
|
package/dist/src/server.js
CHANGED
|
@@ -13,6 +13,8 @@ import { registerMemoryTools } from './memory/tools.js';
|
|
|
13
13
|
import { registerRelocateTool } from './shared/relocate-tool.js';
|
|
14
14
|
import { registerSearchTool } from './shared/search-tool.js';
|
|
15
15
|
import { registerBucketFolderTools } from './shared/bucket-folder-tool.js';
|
|
16
|
+
import { registerAttachmentTools } from './attachments/tools.js';
|
|
17
|
+
import { AttachmentRepository } from './attachments/repository.js';
|
|
16
18
|
import { buildWebRouter } from './web/routes.js';
|
|
17
19
|
import { registerUiTool } from './web/ui-tool.js';
|
|
18
20
|
// server.ts is rebuilt from `buildMcpServer()` on every /mcp request (see below),
|
|
@@ -41,6 +43,7 @@ const skillRepo = new SkillRepository(db, [{ name: 'builtin', path: builtinSkill
|
|
|
41
43
|
const memoryRepo = new MemoryRepository(db, config.memoryFolders);
|
|
42
44
|
skillRepo.setWatcher(skillWatcher);
|
|
43
45
|
memoryRepo.setWatcher(memoryWatcher);
|
|
46
|
+
const attachmentRepo = new AttachmentRepository(memoryRepo, skillRepo);
|
|
44
47
|
if (config.skillFolders.length === 0 && config.memoryFolders.length === 0) {
|
|
45
48
|
console.error(`[memory-bucket] no folders configured — open http://localhost:${PORT} to add one`);
|
|
46
49
|
}
|
|
@@ -57,6 +60,7 @@ function buildMcpServer() {
|
|
|
57
60
|
registerRelocateTool(server, skillRepo, memoryRepo);
|
|
58
61
|
registerSearchTool(server, db);
|
|
59
62
|
registerBucketFolderTools(server, config, skillRepo, memoryRepo, db, skillSpec, memorySpec);
|
|
63
|
+
registerAttachmentTools(server, attachmentRepo);
|
|
60
64
|
registerUiTool(server, PORT);
|
|
61
65
|
return server;
|
|
62
66
|
}
|
|
@@ -15,6 +15,7 @@ function rowToDoc(row) {
|
|
|
15
15
|
deprecated: !!row.deprecated,
|
|
16
16
|
paused: !!row.paused,
|
|
17
17
|
created_at: row.created_at ?? undefined,
|
|
18
|
+
attachments: row.attachments ? JSON.parse(row.attachments) : undefined,
|
|
18
19
|
source_path: row.source_path,
|
|
19
20
|
folder: row.folder,
|
|
20
21
|
body: row.body,
|
package/dist/src/store/db.js
CHANGED
|
@@ -16,6 +16,7 @@ export function openCache(dbPath) {
|
|
|
16
16
|
deprecated INTEGER NOT NULL DEFAULT 0,
|
|
17
17
|
paused INTEGER NOT NULL DEFAULT 0, -- local-only: never synced from/to SKILL.md, cache-file scoped
|
|
18
18
|
created_at TEXT,
|
|
19
|
+
attachments TEXT, -- JSON array of AttachmentEntry, mirrors frontmatter
|
|
19
20
|
body TEXT NOT NULL,
|
|
20
21
|
mtime_ms INTEGER NOT NULL
|
|
21
22
|
);
|
|
@@ -34,6 +35,7 @@ export function openCache(dbPath) {
|
|
|
34
35
|
deprecated INTEGER NOT NULL DEFAULT 0,
|
|
35
36
|
paused INTEGER NOT NULL DEFAULT 0, -- local-only: never synced from/to the doc's markdown file, cache-file scoped
|
|
36
37
|
created_at TEXT,
|
|
38
|
+
attachments TEXT, -- JSON array of AttachmentEntry, mirrors frontmatter
|
|
37
39
|
body TEXT NOT NULL,
|
|
38
40
|
mtime_ms INTEGER NOT NULL
|
|
39
41
|
);
|
|
@@ -64,12 +66,14 @@ export function openCache(dbPath) {
|
|
|
64
66
|
['deprecated', 'INTEGER NOT NULL DEFAULT 0'],
|
|
65
67
|
['paused', 'INTEGER NOT NULL DEFAULT 0'],
|
|
66
68
|
['created_at', 'TEXT'],
|
|
69
|
+
['attachments', 'TEXT'],
|
|
67
70
|
]);
|
|
68
71
|
ensureColumns(db, 'memory_docs', [
|
|
69
72
|
['folder', "TEXT NOT NULL DEFAULT ''"],
|
|
70
73
|
['deprecated', 'INTEGER NOT NULL DEFAULT 0'],
|
|
71
74
|
['paused', 'INTEGER NOT NULL DEFAULT 0'],
|
|
72
75
|
['created_at', 'TEXT'],
|
|
76
|
+
['attachments', 'TEXT'],
|
|
73
77
|
]);
|
|
74
78
|
ensureSearchIndexHasKeyColumn(db);
|
|
75
79
|
backfillSearchIndex(db);
|
package/dist/src/store/sync.js
CHANGED
|
@@ -9,8 +9,8 @@ import { normalizeKey } from '../types.js';
|
|
|
9
9
|
// `paused` is deliberately absent from both lists: it's a local-only cache column (see
|
|
10
10
|
// SkillRepository/MemoryRepository#setPaused) that never round-trips through frontmatter, so a
|
|
11
11
|
// file add/change/rescan must never overwrite it via the INSERT/ON CONFLICT UPDATE below.
|
|
12
|
-
const skillColumns = ['id', 'description', 'owner', 'status', 'tags', 'trigger_phrases', 'extends', 'deprecated', 'created_at'];
|
|
13
|
-
const memoryColumns = ['id', 'key', 'key_type', 'description', 'doc_type', 'tags', 'status', 'related_to', 'deprecated', 'created_at'];
|
|
12
|
+
const skillColumns = ['id', 'description', 'owner', 'status', 'tags', 'trigger_phrases', 'extends', 'deprecated', 'created_at', 'attachments'];
|
|
13
|
+
const memoryColumns = ['id', 'key', 'key_type', 'description', 'doc_type', 'tags', 'status', 'related_to', 'deprecated', 'created_at', 'attachments'];
|
|
14
14
|
export function skillSyncSpec(sources) {
|
|
15
15
|
return {
|
|
16
16
|
table: 'skills',
|
|
@@ -28,6 +28,7 @@ export function skillSyncSpec(sources) {
|
|
|
28
28
|
extends: fm.metadata?.extends ?? null,
|
|
29
29
|
deprecated: fm.deprecated ? 1 : 0,
|
|
30
30
|
created_at: fm.created_at ?? new Date(mtimeMs).toISOString(),
|
|
31
|
+
attachments: fm.attachments ? JSON.stringify(fm.attachments) : null,
|
|
31
32
|
}),
|
|
32
33
|
};
|
|
33
34
|
}
|
|
@@ -65,6 +66,7 @@ export function memorySyncSpec(sources) {
|
|
|
65
66
|
related_to: fm.related_to ?? null,
|
|
66
67
|
deprecated: fm.deprecated ? 1 : 0,
|
|
67
68
|
created_at: fm.created_at ?? null,
|
|
69
|
+
attachments: fm.attachments ? JSON.stringify(fm.attachments) : null,
|
|
68
70
|
}),
|
|
69
71
|
};
|
|
70
72
|
}
|
|
@@ -176,10 +178,12 @@ export function unregisterFolder(db, table, folderName) {
|
|
|
176
178
|
db.prepare(`DELETE FROM search_index WHERE ref_table = ? AND ref_id = ?`).run(table, row.id);
|
|
177
179
|
}
|
|
178
180
|
}
|
|
179
|
-
function* walkMarkdownFiles(dir) {
|
|
181
|
+
export function* walkMarkdownFiles(dir) {
|
|
180
182
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
181
183
|
const full = path.join(dir, entry.name);
|
|
182
184
|
if (entry.isDirectory()) {
|
|
185
|
+
if (entry.name === 'attachments')
|
|
186
|
+
continue;
|
|
183
187
|
yield* walkMarkdownFiles(full);
|
|
184
188
|
}
|
|
185
189
|
else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
@@ -188,7 +192,7 @@ function* walkMarkdownFiles(dir) {
|
|
|
188
192
|
}
|
|
189
193
|
}
|
|
190
194
|
export function watchSources(db, spec) {
|
|
191
|
-
const watcher = chokidar.watch(spec.sources.map((f) => f.path), { ignoreInitial: true, persistent: true, depth: 10 });
|
|
195
|
+
const watcher = chokidar.watch(spec.sources.map((f) => f.path), { ignoreInitial: true, persistent: true, depth: 10, ignored: /(^|[/\\])attachments([/\\]|$)/ });
|
|
192
196
|
watcher
|
|
193
197
|
.on('add', (filePath) => {
|
|
194
198
|
if (!spec.matchesFile(filePath))
|
package/dist/src/web/routes.js
CHANGED
|
@@ -7,6 +7,8 @@ import { saveFolder, removeFolder as removeFolderFromConfig, sanitizeFolderName
|
|
|
7
7
|
import { stripKey } from '../memory/repository.js';
|
|
8
8
|
import { initialScan } from '../store/sync.js';
|
|
9
9
|
import { sanitizeFtsQuery } from '../store/search.js';
|
|
10
|
+
import { resolveWithinBase } from '../store/safe-path.js';
|
|
11
|
+
import { attachmentsDirFor } from '../attachments/storage.js';
|
|
10
12
|
function asArray(v) {
|
|
11
13
|
if (v === undefined)
|
|
12
14
|
return [];
|
|
@@ -38,7 +40,9 @@ function queryEntries(db, memoryRepo, req) {
|
|
|
38
40
|
// doc whose body never repeats the literal key text (e.g. a session summary) still shows up.
|
|
39
41
|
// Skills have no `key` concept, so they still go through the normal FTS path below when q is set.
|
|
40
42
|
const keyMatch = q ? memoryRepo.suggestKeys(q, 1).find((m) => stripKey(m.key) === stripKey(q)) : undefined;
|
|
41
|
-
|
|
43
|
+
// Always compute FTS matches when q is set, even on a keyMatch — skills still need this to stay
|
|
44
|
+
// filtered by q (they have no key concept, so keyMatch only bypasses filtering for memory_docs below).
|
|
45
|
+
const matchedIds = q ? matchSearch(db, q) : null;
|
|
42
46
|
if (q && !keyMatch && matchedIds && matchedIds.skills.size === 0 && matchedIds.memory_docs.size === 0) {
|
|
43
47
|
return [];
|
|
44
48
|
}
|
|
@@ -295,6 +299,7 @@ export function buildWebRouter(db, config, skillRepo, memoryRepo, skillSpec, mem
|
|
|
295
299
|
}
|
|
296
300
|
const tags = JSON.parse(row.tags);
|
|
297
301
|
const trigger_phrases = row.trigger_phrases ? JSON.parse(row.trigger_phrases) : undefined;
|
|
302
|
+
const attachments = row.attachments ? JSON.parse(row.attachments) : undefined;
|
|
298
303
|
// A memory doc's cache row always looks fully populated even for a bare file (deriveFrontmatter's
|
|
299
304
|
// fallback backfills id/key/etc — see sync.ts), so whether it actually has an authored
|
|
300
305
|
// frontmatter block has to be checked on disk. This drives "Add frontmatter" (memory only —
|
|
@@ -314,7 +319,46 @@ export function buildWebRouter(db, config, skillRepo, memoryRepo, skillSpec, mem
|
|
|
314
319
|
// file unreadable/missing — treat as having frontmatter so the UI doesn't offer to "add"
|
|
315
320
|
// one for a doc it can't actually reach; the existing edit/delete-doc paths will 404 instead.
|
|
316
321
|
}
|
|
317
|
-
res.json({ ...row, tags, trigger_phrases, has_frontmatter, raw_file });
|
|
322
|
+
res.json({ ...row, tags, trigger_phrases, attachments, has_frontmatter, raw_file });
|
|
323
|
+
});
|
|
324
|
+
// Serves a single attachment file for a doc. Unauthenticated web-facing surface, so the
|
|
325
|
+
// filename from the URL is validated with resolveWithinBase (same containment check
|
|
326
|
+
// attachments/storage.ts uses when writing) to rule out path traversal before touching disk.
|
|
327
|
+
router.get('/api/entries/:table/:id/attachments/:filename', (req, res) => {
|
|
328
|
+
const { table, id, filename } = req.params;
|
|
329
|
+
if (table !== 'skills' && table !== 'memory_docs') {
|
|
330
|
+
res.status(400).json({ error: 'table must be "skills" or "memory_docs"' });
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (!filename) {
|
|
334
|
+
res.status(400).json({ error: 'filename is required' });
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const row = db.prepare(`SELECT source_path FROM ${table} WHERE id = ?`).get(id);
|
|
338
|
+
if (!row) {
|
|
339
|
+
res.status(404).json({ error: 'not found' });
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const dir = attachmentsDirFor(row.source_path, table === 'skills' ? 'skill' : 'memory');
|
|
343
|
+
let filePath;
|
|
344
|
+
try {
|
|
345
|
+
filePath = resolveWithinBase(dir, undefined, filename);
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
res.status(400).json({ error: err.message });
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
// Force a non-executable Content-Type and force-download disposition so a maliciously
|
|
352
|
+
// named attachment (e.g. "notes.html" with an embedded <script>) can never render inline
|
|
353
|
+
// in the browser and execute in this origin — Express/sendFile would otherwise infer
|
|
354
|
+
// Content-Type from the file extension.
|
|
355
|
+
res.setHeader('Content-Type', 'application/octet-stream');
|
|
356
|
+
res.setHeader('Content-Disposition', `attachment; filename="${encodeURIComponent(filename)}"`);
|
|
357
|
+
res.sendFile(filePath, (err) => {
|
|
358
|
+
if (err && !res.headersSent) {
|
|
359
|
+
res.status(404).json({ error: 'attachment not found' });
|
|
360
|
+
}
|
|
361
|
+
});
|
|
318
362
|
});
|
|
319
363
|
router.patch('/api/entries/:table/:id/deprecated', (req, res) => {
|
|
320
364
|
const { table, id } = req.params;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-memory-bucket",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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": {
|