@cachly-dev/mcp-server 0.10.223 → 0.10.225

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -64,13 +64,20 @@ move is refused with a message.
64
64
  npx @cachly-dev/mcp-server@latest autopilot
65
65
  ```
66
66
 
67
- `autopilot` finds the editors you use and writes the MCP config for each. It adds a git
67
+ `autopilot` finds the editors you use and writes the MCP config for each. It also writes
68
+ the rule file each editor reads in every chat (`CLAUDE.md`, `AGENTS.md`,
69
+ `.cursor/rules/cachly.mdc`, `.github/copilot-instructions.md`, `.windsurfrules`,
70
+ `.clinerules`; `GEMINI.md`, `.junie/guidelines.md` and `.continue/rules/cachly.md` where
71
+ you use Gemini CLI, Junie or Continue), which tells your AI to check its memory before a task. It adds a git
68
72
  hook that learns from your commits and fills your Brain from your git history. You sign
69
73
  in once in the browser (a device code, no password, no credit card), so the Brain
70
74
  belongs to your own account from the start. Restart your editor afterwards.
71
75
 
72
76
  You can also add the server by hand (see [Manual Setup](#manual-setup)). Without a key,
73
- the first tool call creates the same test Brain as in Claude Code.
77
+ the first tool call creates the same test Brain as in Claude Code. Without a rule file,
78
+ Claude Code still starts each task with `smart_recall`, because the server's instructions
79
+ ask for it. Gemini CLI also passes them on. Some editors do not (Cline, Continue and Zed,
80
+ for example); there, the rule file from `autopilot` is what makes your AI use its memory.
74
81
 
75
82
  > **Already inside Claude, Cursor or Copilot?** Paste this to your AI:
76
83
  > ```
@@ -1,2 +1,2 @@
1
- import{CKG_BELEG_SCHWELLE as h,SINN_BELEG_SCHWELLE as c,WORT_BELEG_SCHWELLE as u}from"./rangfolge-stellschrauben.js";const i=e=>typeof e=="number"&&Number.isFinite(e)?e:0;function b(e,t={}){return i(e.wortBelege)>=(t.woerter??u)||i(e.semScore)>=(t.naehe??c)||i(e.ckgScore)>=(t.kante??h)}function m(e,t={}){let r=0,n=0,o=!1,a=0;for(const s of e){const l=i(s.wortBelege),f=i(s.semScore);l>r&&(r=l),f>n&&(n=f),b(s,t)&&(o=!0,a++)}return{schweigen:e.length===0||!o,besteWortBelege:r,besteNaehe:n,geprueft:e.length,belegte:a}}const g="No matches found";function w(e,t={}){if(e.geprueft===0)return`\u{1F50D} **${g}** \u2014 there is no lesson for this question yet.`;const r=t.woerter??u,n=t.naehe??c;return[`\u{1F50D} **${g}.**`,"",`${e.geprueft} candidates checked, none confirmed \u2014 the best contained ${e.besteWortBelege} of the searched words (needed: ${r}), highest semantic similarity ${e.besteNaehe.toFixed(2)} (needed: ${n.toFixed(2)}).`,"They are deliberately NOT shown: a weak match looks like a strong one, and the difference matters.","",'_If the answer should be in the Brain anyway, ask with other words \u2014 or use `recall_best_solution(topic="\u2026")` if you know the topic._'].join(`
2
- `)}const d=5;function N(e){const t=e.filter(o=>Number.isFinite(o)&&o>=0);if(t.length===0)return null;const r=Math.min(...t),n=Math.max(...t);return r<d?null:t.length===1?`Der belegte Treffer ist ${n} Tage unbest\xE4tigt.`:r===n?`Die belegten Treffer sind ${n} Tage unbest\xE4tigt.`:`Die belegten Treffer sind seit ${r}\u2013${n} Tagen unbest\xE4tigt.`}export{d as ALTER_NENNEN_AB_TAGEN,g as SCHWEIGEN_MARKE,w as abstentionSatz,N as alterssatzFuerBelegte,m as beurteileTreffer,b as istBelegt};
1
+ import{CKG_BELEG_SCHWELLE as d,SINN_BELEG_SCHWELLE as f,WORT_BELEG_SCHWELLE as l}from"./rangfolge-stellschrauben.js";const s=e=>typeof e=="number"&&Number.isFinite(e)?e:0;function g(e,t={}){return s(e.wortBelege)>=(t.woerter??l)||s(e.semScore)>=(t.naehe??f)||s(e.ckgScore)>=(t.kante??d)}function E(e,t={}){let o=0,n=0,r=!1,a=0;for(const i of e){const c=s(i.wortBelege),h=s(i.semScore);c>o&&(o=c),h>n&&(n=h),g(i,t)&&(r=!0,a++)}return{schweigen:e.length===0||!r,besteWortBelege:o,besteNaehe:n,geprueft:e.length,belegte:a}}const u="No matches found";function w(e,t={}){if(e.geprueft===0)return`\u{1F50D} **${u}** \u2014 there is no lesson for this question yet.`;const o=t.woerter??l,n=t.naehe??f;return[`\u{1F50D} **${u}.**`,"",`${e.geprueft} candidates checked, none confirmed \u2014 the best contained ${e.besteWortBelege} of the searched words (needed: ${o}), highest semantic similarity ${e.besteNaehe.toFixed(2)} (needed: ${n.toFixed(2)}).`,"They are deliberately NOT shown: a weak match looks like a strong one, and the difference matters.","",'_If the answer should be in the Brain anyway, ask with other words \u2014 or use `recall_best_solution(topic="\u2026")` if you know the topic._'].join(`
2
+ `)}const b=5;function N(e){const t=e.filter(r=>Number.isFinite(r)&&r>=0);if(t.length===0)return null;const o=Math.min(...t),n=Math.max(...t);return o<b?null:t.length===1?`The backed match has not been confirmed for ${n} days.`:o===n?`The backed matches have not been confirmed for ${n} days.`:`The backed matches have not been confirmed for ${o}\u2013${n} days.`}export{b as ALTER_NENNEN_AB_TAGEN,u as SCHWEIGEN_MARKE,w as abstentionSatz,N as alterssatzFuerBelegte,E as beurteileTreffer,g as istBelegt};
package/dist/src/autor.js CHANGED
@@ -1 +1 @@
1
- import{execFileSync as c}from"node:child_process";const f=e=>n=>{try{return n.startsWith("-")?"":c("git",["config",n],{cwd:e,encoding:"utf-8",stdio:"pipe",timeout:1500,windowsHide:!0}).trim()}catch{return""}};function t(e){const n=(e??"").trim();return n?(n.split(/[\s.]+/)[0]??"").toLowerCase().replace(/[^a-z0-9_-]/g,"").slice(0,32):""}const a=new Set(["-","anonym","anonymous","none","kein","off"]);function g(e){const n=(e.uebergeben??"").trim().toLowerCase();if(a.has(n))return{autor:"",quelle:"anonym"};const r=(e.umgebung??"").trim().toLowerCase();if(a.has(r))return{autor:"",quelle:"anonym"};const o=t(e.uebergeben??"");if(o)return{autor:o,quelle:"uebergeben"};const i=t(e.umgebung??"");if(i)return{autor:i,quelle:"umgebung"};const u=t(e.git("user.name"));if(u)return{autor:u,quelle:"git-name"};const l=e.git("user.email"),s=t((l??"").split("@")[0]??"");return s?{autor:s,quelle:"git-mail"}:{autor:"",quelle:"unbekannt"}}const b="coauthor";function h(e){const n=(e??"").trim().toLowerCase();return!n||n==="off"||n==="false"||n==="0"||n==="none"?"":t(n)}function w(e,n){return e?!n||n===e?e:`${e}+${n}`:""}function d(e){return(e??"").split("+")[0]??""}function p(e){return e.autor||e.quelle==="anonym"?null:'\u{1F464} **Kein Autor ermittelt** \u2014 weder `author`, noch `CACHLY_AUTHOR`, noch `git config user.name`. Ohne Autor z\xE4hlt diese Lektion nicht als Team-Wissen: `brain_who_knows` findet niemanden und Wiederverwendung \xFCber Personengrenzen bleibt ungez\xE4hlt. Ein `git config user.name "Vorname"` im Projekt gen\xFCgt f\xFCr alle k\xFCnftigen Lektionen.'}export{b as COAUTHOR_PREF_KEY,p as autorHinweis,h as coautorAus,f as echterGitLeser,g as ermittleAutor,w as mitCoautor,t as normalisiere,d as nurMensch};
1
+ import{execFileSync as c}from"node:child_process";const m=e=>t=>{try{return t.startsWith("-")?"":c("git",["config",t],{cwd:e,encoding:"utf-8",stdio:"pipe",timeout:1500,windowsHide:!0}).trim()}catch{return""}};function r(e){const t=(e??"").trim();return t?(t.split(/[\s.]+/)[0]??"").toLowerCase().replace(/[^a-z0-9_-]/g,"").slice(0,32):""}const a=new Set(["-","anonym","anonymous","none","kein","off"]);function g(e){const t=(e.uebergeben??"").trim().toLowerCase();if(a.has(t))return{autor:"",quelle:"anonym"};const n=(e.umgebung??"").trim().toLowerCase();if(a.has(n))return{autor:"",quelle:"anonym"};const o=r(e.uebergeben??"");if(o)return{autor:o,quelle:"uebergeben"};const u=r(e.umgebung??"");if(u)return{autor:u,quelle:"umgebung"};const i=r(e.git("user.name"));if(i)return{autor:i,quelle:"git-name"};const l=e.git("user.email"),s=r((l??"").split("@")[0]??"");return s?{autor:s,quelle:"git-mail"}:{autor:"",quelle:"unbekannt"}}const h="coauthor";function b(e){const t=(e??"").trim().toLowerCase();return!t||t==="off"||t==="false"||t==="0"||t==="none"?"":r(t)}function p(e,t){return e?!t||t===e?e:`${e}+${t}`:""}function d(e){return(e??"").split("+")[0]??""}function w(e){return e.autor||e.quelle==="anonym"?null:'\u{1F464} **No author found** \u2014 neither `author`, nor `CACHLY_AUTHOR`, nor `git config user.name`. Without an author this lesson does not count as team knowledge: `brain_who_knows` finds nobody and reuse across people stays uncounted. A `git config user.name "Your Name"` in the project is enough for all future lessons.'}export{h as COAUTHOR_PREF_KEY,w as autorHinweis,b as coautorAus,m as echterGitLeser,g as ermittleAutor,p as mitCoautor,r as normalisiere,d as nurMensch};
@@ -1 +1 @@
1
- import{kosinus as x}from"./bedeutung.js";import{DOPPEL_SCHWELLE as w}from"./rangfolge-stellschrauben.js";const f="cachly:doppel:kandidaten",_=40,D=14,L=30,T=90*86400,y=1500,O=6,k=864e5,E=t=>typeof t.what_worked=="string"?t.what_worked.trim().length:0;function m(t,e,n,o=w){return t.topic===e.topic||!(n>=o)||E(t)<_||E(e)<_?!1:!(t.ersetzt===e.topic||t.ersetzt_durch===e.topic||e.ersetzt===t.topic||e.ersetzt_durch===t.topic)}function A(t,e){let n=null;for(const o of e)m(t,o.lektion,o.naehe)&&(!n||o.naehe>n.naehe)&&(n={topic:o.lektion.topic,naehe:o.naehe});return n}function g(t){if(!t)return null;try{const e=JSON.parse(t);return e&&typeof e=="object"?e:null}catch{return null}}const S=t=>Math.round(t*1e3)/1e3;async function z(t,e,n,o,a=new Date){try{await o.aktualisiere(t);const r=o.aehnlichste(n,O+1).filter(s=>s.topic!==e.topic&&s.naehe>=w);let i=null;if(r.length>0){const s=await t.mget(...r.map(h=>`cachly:lesson:best:${h.topic}`)),p=r.flatMap((h,P)=>{const d=g(s[P]);return d?[{lektion:{...d,topic:h.topic},naehe:h.naehe}]:[]});i=A(e,p)}const u=await t.hgetall(f),c=Object.entries(u).filter(([s,p])=>s===e.topic||a.getTime()-Date.parse(String(g(p)?.am??""))>L*k||!g(p)).map(([s])=>s);if(c.length>0&&await t.hdel(f,...c),!i)return null;const l={neu:e.topic,alt:i.topic,naehe:S(i.naehe),am:a.toISOString()};return await t.hset(f,e.topic,JSON.stringify({alt:l.alt,naehe:l.naehe,am:l.am})),await t.expire(f,T),l}catch{return null}}async function I(t,e=y){let n;const o=new Promise(a=>{n=setTimeout(()=>a(null),e),n.unref?.()});try{return await Promise.race([t,o])}finally{n&&clearTimeout(n)}}function M(t,e=""){return!t||e.includes(`\`${t.alt}\``)?"":`\u267B\uFE0F Sagt fast dasselbe wie \`${t.alt}\` (Bedeutung ${t.naehe.toFixed(2)}). Ist das die neuere Fassung: dieselbe Lektion noch einmal mit \`ersetzt="${t.alt}"\` und \`grund\` schreiben. Ist es eine eigene Sache: nichts zu tun.`}async function v(t,e,n=new Date){try{const o=await t.hgetall(f),a=new Map(e.map(i=>[i.topic,i])),r=[];for(const[i,u]of Object.entries(o)){const c=g(u);if(!c||typeof c.alt!="string")continue;const l=String(c.am??"");if(!(n.getTime()-Date.parse(l)<=D*k))continue;const s=a.get(i),p=a.get(c.alt),h=Number(c.naehe);!s||!p||!m(s,p,h)||r.push({neu:i,alt:c.alt,naehe:h,am:l})}return r.sort((i,u)=>u.naehe-i.naehe)}catch{return[]}}function H(t){const e=[];for(let n=0;n<t.length;n++)for(let o=n+1;o<t.length;o++){const a=t[n],r=t[o],i=x(a.vektor,r.vektor);if(!m(a.lektion,r.lektion,i))continue;const u=String(a.lektion.ts??"")>=String(r.lektion.ts??""),[c,l]=u?[a.lektion,r.lektion]:[r.lektion,a.lektion];e.push({neu:c.topic,alt:l.topic,naehe:S(i)})}return e.sort((n,o)=>o.naehe-n.naehe)}export{D as DOPPEL_BRIEFING_TAGE,L as DOPPEL_HALTEN_TAGE,_ as DOPPEL_MINDEST_TEXT,f as DOPPEL_SCHLUESSEL,T as DOPPEL_TTL_S,y as DOPPEL_WARTE_MS,M as doppelHinweis,H as doppelPaare,v as leseDoppelKandidaten,I as mitFrist,z as pruefeDoppelung,A as waehleDoppelKandidat,m as zaehltAlsDoppelung};
1
+ import{kosinus as x}from"./bedeutung.js";import{DOPPEL_SCHWELLE as _}from"./rangfolge-stellschrauben.js";const f="cachly:doppel:kandidaten",k=40,y=14,D=30,L=90*86400,T=1500,O=6,E=864e5,d=t=>typeof t.what_worked=="string"?t.what_worked.trim().length:0;function g(t,e,n,o=_){return t.topic===e.topic||!(n>=o)||d(t)<k||d(e)<k?!1:!(t.ersetzt===e.topic||t.ersetzt_durch===e.topic||e.ersetzt===t.topic||e.ersetzt_durch===t.topic)}function A(t,e){let n=null;for(const o of e)g(t,o.lektion,o.naehe)&&(!n||o.naehe>n.naehe)&&(n={topic:o.lektion.topic,naehe:o.naehe});return n}function m(t){if(!t)return null;try{const e=JSON.parse(t);return e&&typeof e=="object"?e:null}catch{return null}}const P=t=>Math.round(t*1e3)/1e3;async function z(t,e,n,o,i=new Date){try{await o.aktualisiere(t);const r=o.aehnlichste(n,O+1).filter(s=>s.topic!==e.topic&&s.naehe>=_);let a=null;if(r.length>0){const s=await t.mget(...r.map(h=>`cachly:lesson:best:${h.topic}`)),u=r.flatMap((h,S)=>{const w=m(s[S]);return w?[{lektion:{...w,topic:h.topic},naehe:h.naehe}]:[]});a=A(e,u)}const p=await t.hgetall(f),c=Object.entries(p).filter(([s,u])=>s===e.topic||i.getTime()-Date.parse(String(m(u)?.am??""))>D*E||!m(u)).map(([s])=>s);if(c.length>0&&await t.hdel(f,...c),!a)return null;const l={neu:e.topic,alt:a.topic,naehe:P(a.naehe),am:i.toISOString()};return await t.hset(f,e.topic,JSON.stringify({alt:l.alt,naehe:l.naehe,am:l.am})),await t.expire(f,L),l}catch{return null}}async function I(t,e=T){let n;const o=new Promise(i=>{n=setTimeout(()=>i(null),e),n.unref?.()});try{return await Promise.race([t,o])}finally{n&&clearTimeout(n)}}function M(t,e=""){return!t||e.includes(`\`${t.alt}\``)?"":`\u267B\uFE0F Says almost the same as \`${t.alt}\` (similarity ${t.naehe.toFixed(2)}). If this is the newer version: write the same lesson again with \`ersetzt="${t.alt}"\` and \`grund\`. If it is a separate matter: nothing to do.`}async function H(t,e,n=new Date){try{const o=await t.hgetall(f),i=new Map(e.map(a=>[a.topic,a])),r=[];for(const[a,p]of Object.entries(o)){const c=m(p);if(!c||typeof c.alt!="string")continue;const l=String(c.am??"");if(!(n.getTime()-Date.parse(l)<=y*E))continue;const s=i.get(a),u=i.get(c.alt),h=Number(c.naehe);!s||!u||!g(s,u,h)||r.push({neu:a,alt:c.alt,naehe:h,am:l})}return r.sort((a,p)=>p.naehe-a.naehe)}catch{return[]}}function $(t){const e=[];for(let n=0;n<t.length;n++)for(let o=n+1;o<t.length;o++){const i=t[n],r=t[o],a=x(i.vektor,r.vektor);if(!g(i.lektion,r.lektion,a))continue;const p=String(i.lektion.ts??"")>=String(r.lektion.ts??""),[c,l]=p?[i.lektion,r.lektion]:[r.lektion,i.lektion];e.push({neu:c.topic,alt:l.topic,naehe:P(a)})}return e.sort((n,o)=>o.naehe-n.naehe)}export{y as DOPPEL_BRIEFING_TAGE,D as DOPPEL_HALTEN_TAGE,k as DOPPEL_MINDEST_TEXT,f as DOPPEL_SCHLUESSEL,L as DOPPEL_TTL_S,T as DOPPEL_WARTE_MS,M as doppelHinweis,$ as doppelPaare,H as leseDoppelKandidaten,I as mitFrist,z as pruefeDoppelung,A as waehleDoppelKandidat,g as zaehltAlsDoppelung};
@@ -1 +1 @@
1
- const t=[/(?:bewusst|ausdruecklich|explizit)?\s*(?:haben wir uns|wir haben uns|ich habe mich|hat sich)?\s*entschieden gegen\s+([^,.;—\n]{3,80})(?:\s*[,—]\s*(?:weil|da|grund:?)\s+([^.;\n]{3,200}))?/i,/(?:bewusst|ausdruecklich|explizit)\s+gegen\s+([^,.;—\n]{3,80}?)\s+entschieden(?:\s*[,—]\s*(?:weil|da|grund:?)\s+([^.;\n]{3,200}))?/i,/decided against\s+(.{3,80}?)\s+because\s+([^.;\n]{3,200})/i,/decided against\s+([^,.;\n]{3,80})/i];function u(e){for(const i of t){const n=i.exec(e);if(!n)continue;const s=n[1].trim().replace(/\s+/g," ");if(!/^\d|^(mittag|abend|morgen|ende|anfang)\b/i.test(s))return{gegen:s,grund:n[2]?n[2].trim().replace(/\s+/g," "):null}}return null}function c(e){return`\u2696\uFE0F **Bewusst entschieden GEGEN ${e.gegen}**${e.grund?` \u2014 Grund: ${e.grund}`:""}. Nicht ohne NEUEN Grund aufweichen.`}export{c as entscheidungsZeile,u as leiteEntscheidungAb};
1
+ const t=[/(?:bewusst|ausdruecklich|explizit)?\s*(?:haben wir uns|wir haben uns|ich habe mich|hat sich)?\s*entschieden gegen\s+([^,.;—\n]{3,80})(?:\s*[,—]\s*(?:weil|da|grund:?)\s+([^.;\n]{3,200}))?/i,/(?:bewusst|ausdruecklich|explizit)\s+gegen\s+([^,.;—\n]{3,80}?)\s+entschieden(?:\s*[,—]\s*(?:weil|da|grund:?)\s+([^.;\n]{3,200}))?/i,/decided against\s+(.{3,80}?)\s+because\s+([^.;\n]{3,200})/i,/decided against\s+([^,.;\n]{3,80})/i];function c(e){for(const i of t){const n=i.exec(e);if(!n)continue;const s=n[1].trim().replace(/\s+/g," ");if(!/^\d|^(mittag|abend|morgen|ende|anfang)\b/i.test(s))return{gegen:s,grund:n[2]?n[2].trim().replace(/\s+/g," "):null}}return null}function r(e){return`\u2696\uFE0F **Deliberately decided AGAINST ${e.gegen}**${e.grund?` \u2014 reason: ${e.grund}`:""}. Do not soften this without a NEW reason.`}export{r as entscheidungsZeile,c as leiteEntscheidungAb};
@@ -1 +1 @@
1
- import{inhaltsWoerter as l,grobStamm as f}from"./rangfolge.js";const h=/\b(nicht mehr|doch nicht|stattdessen|statt dessen|in wahrheit|widerlegt|war falsch|stimmt nicht|korrektur|korrigiert|entgegen|no longer|instead|actually|turned out|wrong|superseded)\b/i;function u(t){return new Set([...l(t)].map(f))}function d(t,r){if(t.size===0||r.size===0)return 0;let n=0;for(const i of t)r.has(i)&&n++;return n/(t.size+r.size-n)}function g(t,r){const n=u(t.replace(/[:\-_/.]+/g," ")),i=u(r.replace(/[:\-_/.]+/g," "));if(n.size===0||i.size===0)return 0;let s=0;for(const e of n)i.has(e)&&s++;return s/Math.min(n.size,i.size)}function p(t,r,n){const i=r.match(h);if(!i)return null;const s=u(r);let e=null;for(const o of n){if(o.topic===t)continue;const c=g(t,o.topic),a=d(s,u(o.what_worked??""));c>=.5?(!e||c>e.wert)&&(e={topic:o.topic,grund:`Themen-Naehe ${(100*c).toFixed(0)} %`,wert:c}):a>=.3&&(!e||a>e.wert)&&(e={topic:o.topic,grund:`Text-Ueberlappung ${(100*a).toFixed(0)} %`,wert:a})}return e?`\u{1F501} Das klingt wie eine Korrektur von \`${e.topic}\` ("${i[0]}" + ${e.grund}). Wenn ja: dieselbe Lektion noch einmal mit \`ersetzt="${e.topic}"\` schreiben \u2014 dann wird die alte Fassung im Abruf verdraengt statt weiter als aktuell geliefert. Wenn nein: nichts zu tun.`:null}export{p as schlageErsetzungVor,g as themenNaehe};
1
+ import{inhaltsWoerter as f,grobStamm as h}from"./rangfolge.js";const u=/\b(nicht mehr|doch nicht|stattdessen|statt dessen|in wahrheit|widerlegt|war falsch|stimmt nicht|korrektur|korrigiert|entgegen|no longer|instead|actually|turned out|wrong|superseded)\b/i;function l(e){return new Set([...f(e)].map(h))}function d(e,n){if(e.size===0||n.size===0)return 0;let i=0;for(const r of e)n.has(r)&&i++;return i/(e.size+n.size-i)}function g(e,n){const i=l(e.replace(/[:\-_/.]+/g," ")),r=l(n.replace(/[:\-_/.]+/g," "));if(i.size===0||r.size===0)return 0;let s=0;for(const t of i)r.has(t)&&s++;return s/Math.min(i.size,r.size)}function m(e,n,i){const r=n.match(u);if(!r)return null;const s=l(n);let t=null;for(const o of i){if(o.topic===e)continue;const c=g(e,o.topic),a=d(s,l(o.what_worked??""));c>=.5?(!t||c>t.wert)&&(t={topic:o.topic,grund:`topic similarity ${(100*c).toFixed(0)} %`,wert:c}):a>=.3&&(!t||a>t.wert)&&(t={topic:o.topic,grund:`text overlap ${(100*a).toFixed(0)} %`,wert:a})}return t?`\u{1F501} This sounds like a correction of \`${t.topic}\` ("${r[0]}" + ${t.grund}). If so: write the same lesson again with \`ersetzt="${t.topic}"\` \u2014 then recall hides the old version instead of still serving it as current. If not: nothing to do.`:null}export{m as schlageErsetzungVor,g as themenNaehe};
@@ -3,7 +3,7 @@ import{ckgSlug as j}from"../ckg.js";import{safeJsonParse as x,darfHeraus as N}fr
3
3
  `)}case"causal_trace":{const{instance_id:l,problem:g,max_depth:$=5,tags:m=[]}=S,w=await W(l,L,`\u{1F50D} **Causal Trace: "${g}"**
4
4
 
5
5
  No matching lessons found in brain.`);if(w)return w;const d=await M(l),u=g.toLowerCase().replace(/[^a-z0-9\s\-_:]/g," ").split(/\s+/).filter(o=>o.length>2),_={critical:"\u{1F534}",major:"\u{1F7E0}",minor:"\u{1F7E1}"},c=[];try{for(const o of u.slice(0,4)){const a=await d.smembers(`cachly:ckg:idx:from:${j(o)}`),r=await d.smembers(`cachly:ckg:idx:to:${j(o)}`),p=[],n=d.scanStream({match:`cachly:ckg:node:*${o}*`,count:50});await new Promise((e,s)=>{n.on("data",i=>p.push(...i)),n.on("end",e),n.on("error",s)});for(const e of p.slice(0,10)){const s=await d.get(e);if(!s)continue;const i=x(s,null);if(!i)continue;const D=await d.smembers(`cachly:ckg:idx:from:${i.id}`);for(const T of D.slice(0,20)){const R=await d.get(T);if(!R)continue;const C=x(R,null);if(!C||C.edgeType!=="fixes"&&C.edgeType!=="requires")continue;const I=await d.get(`cachly:lesson:best:${C.from.replace(/-/g,":").replace(/^fix:/,"fix:")}`),E=I?x(I,null)??void 0:void 0;c.push({conceptId:i.id,edge:C,lesson:E&&B(E)?E:void 0})}}for(const e of[...a,...r].slice(0,20)){const s=await d.get(e);if(!s)continue;const i=x(s,null);if(!i)continue;const D=await d.get(`cachly:lesson:best:${i.from}`),T=D?x(D,null)??void 0:void 0;c.push({conceptId:i.from,edge:i,lesson:T&&B(T)?T:void 0})}}}catch{}const y=new Set,f=c.filter(o=>{const a=`${o.edge.from}:${o.edge.edgeType}:${o.edge.to}`;return y.has(a)?!1:(y.add(a),!0)}).sort((o,a)=>a.edge.confidence-o.edge.confidence).slice(0,$);let k=0;const b=[];do{const[o,a]=await d.scan(k,"MATCH","cachly:lesson:best:*","COUNT",200);k=parseInt(o),b.push(...a)}while(k!==0);const h=[];for(const o of b){const a=await d.get(o);if(a){const r=x(a,null);if(!r||!B(r)||m.length>0&&!(r.tags??[]).some(e=>m.includes(e)))continue;const p=[r.topic,r.what_failed??"",r.what_worked??"",r.context??""].join(" ").toLowerCase(),n=u.reduce((e,s)=>e+(p.includes(s)?1:0),0);n>0&&h.push({score:n,lesson:r,key:o})}}h.sort((o,a)=>a.score-o.score);const v=h.slice(0,$);if(v.length===0&&f.length===0)return[`\u{1F50D} **Causal Trace: "${g}"**`,"","No matching lessons found in brain.","","\u{1F4A1} After you solve this, call:","```","learn_from_attempts(",` instance_id = "${l}",`,` topic = "fix:${u[0]??"issue"}",`,' outcome = "success",',' what_worked = "...",',` what_failed = "${g}",`,")","```"].join(`
6
- `);const t=[`\u{1F50D} **Causal Trace: "${g}"**`,""];if(f.length>0){t.push("### \u{1F578}\uFE0F CKG Graph (confidence-ranked)");for(const o of f){const a=Math.round(o.edge.confidence*100),r="\u2593".repeat(Math.round(a/10))+"\u2591".repeat(10-Math.round(a/10));t.push(` ${o.edge.from} **\u2192[${o.edge.edgeType}]\u2192** ${o.edge.to}`),t.push(` ${r} ${a}% confidence (${o.edge.successes}/${o.edge.trials} confirmed)`),o.lesson?.what_worked&&t.push(` \u2705 Fix: ${o.lesson.what_worked.slice(0,150)}`),t.push("")}}if(v.length>0){t.push(f.length>0?`### \u{1F4DA} Text Search (${v.length} related lessons)`:`Found **${v.length}** related lessons. Reconstructed causal chain:`,"");const o=v.filter(p=>p.lesson.outcome!=="success"),a=v.filter(p=>p.lesson.outcome==="success");o.length>0&&(t.push("**Root causes & failure chain:**"),o.forEach((p,n)=>{const e=p.lesson,s=_[e.severity??"minor"]??"\u{1F7E1}";t.push(`${n===0?" Root:":" \u2192 :"} ${s} \`${e.topic}\``),e.what_failed&&t.push(` \u21B3 ${e.what_failed.slice(0,120)}`)}),t.push("")),a.length>0&&(t.push("**Solutions that worked before:**"),a.forEach((p,n)=>{const e=p.lesson,s=new Date(e.ts).toLocaleDateString("de-DE");t.push(` ${n+1}. \u2705 \`${e.topic}\` \u2014 ${s} \xB7 recalled ${e.recall_count??0}\xD7`),e.what_worked&&t.push(` ${e.what_worked.slice(0,200)}`)}),t.push(""));const r=a[0]?.lesson;if(r?.what_worked){t.push("**\u26A1 Most likely fix:**"),t.push("```"),t.push(r.what_worked.slice(0,500)),t.push("```"),t.push("");const p=F(r)?P(r,"trace"):0;p>0&&d.incrbyfloat(`cachly:stats:time_saved_mins:${l}`,p).catch(()=>{})}}return t.push(`\u{1F4A1} After applying: \`learn_from_attempts(topic="fix:${u[0]??"issue"}", outcome="success", ...)\``),f.length>0&&t.push(`\u{1F578}\uFE0F Explore graph: \`ckg_inspect(concept="${u[0]??"fix"}")\``),t.join(`
6
+ `);const t=[`\u{1F50D} **Causal Trace: "${g}"**`,""];if(f.length>0){t.push("### \u{1F578}\uFE0F CKG Graph (confidence-ranked)");for(const o of f){const a=Math.round(o.edge.confidence*100),r="\u2593".repeat(Math.round(a/10))+"\u2591".repeat(10-Math.round(a/10));t.push(` ${o.edge.from} **\u2192[${o.edge.edgeType}]\u2192** ${o.edge.to}`),t.push(` ${r} ${a}% confidence (${o.edge.successes}/${o.edge.trials} confirmed)`),o.lesson?.what_worked&&t.push(` \u2705 Fix: ${o.lesson.what_worked.slice(0,150)}`),t.push("")}}if(v.length>0){t.push(f.length>0?`### \u{1F4DA} Text Search (${v.length} related lessons)`:`Found **${v.length}** related lessons. Reconstructed causal chain:`,"");const o=v.filter(p=>p.lesson.outcome!=="success"),a=v.filter(p=>p.lesson.outcome==="success");o.length>0&&(t.push("**Root causes & failure chain:**"),o.forEach((p,n)=>{const e=p.lesson,s=_[e.severity??"minor"]??"\u{1F7E1}";t.push(`${n===0?" Root:":" \u2192 :"} ${s} \`${e.topic}\``),e.what_failed&&t.push(` \u21B3 ${e.what_failed.slice(0,120)}`)}),t.push("")),a.length>0&&(t.push("**Solutions that worked before:**"),a.forEach((p,n)=>{const e=p.lesson,s=new Date(e.ts).toLocaleDateString("de-DE");t.push(` ${n+1}. \u2705 \`${e.topic}\` \u2014 ${s} \xB7 in ${e.recall_count??0} answers`),e.what_worked&&t.push(` ${e.what_worked.slice(0,200)}`)}),t.push(""));const r=a[0]?.lesson;if(r?.what_worked){t.push("**\u26A1 Most likely fix:**"),t.push("```"),t.push(r.what_worked.slice(0,500)),t.push("```"),t.push("");const p=F(r)?P(r,"trace"):0;p>0&&d.incrbyfloat(`cachly:stats:time_saved_mins:${l}`,p).catch(()=>{})}}return t.push(`\u{1F4A1} After applying: \`learn_from_attempts(topic="fix:${u[0]??"issue"}", outcome="success", ...)\``),f.length>0&&t.push(`\u{1F578}\uFE0F Explore graph: \`ckg_inspect(concept="${u[0]??"fix"}")\``),t.join(`
7
7
  `)}case"knowledge_decay":{let f=function(t){const o=Math.round(t/10);return"\u2588".repeat(o)+"\u2591".repeat(10-o)+` ${t}%`};const{instance_id:l,min_age_days:g=0,show_top:$=20}=S,m=await M(l),w=Date.now(),d=g*864e5;let u=0;const _=[];do{const[t,o]=await m.scan(u,"MATCH","cachly:lesson:best:*","COUNT",200);u=parseInt(t),_.push(...o)}while(u!==0);const c=[];for(const t of _){const o=await m.get(t);if(o){const a=x(o,null);if(!a)continue;const r=w-new Date(a.ts).getTime();if(r<d)continue;const p=Math.floor(r/864e5),n=a.recall_count??0,e=Math.max(0,p-7),s=Math.max(5,100-e),i=Math.min(50,n*5),D=a.outcome==="failure"?-20:0,T=Math.min(100,Math.max(0,s+i+D));c.push({topic:a.topic,confidence:T,age_days:p,recalls:n,outcome:a.outcome})}}c.sort((t,o)=>t.confidence-o.confidence);const y=c.slice(0,$),k=c.length>0?Math.round(c.reduce((t,o)=>t+o.confidence,0)/c.length):0,b=c.filter(t=>t.confidence<30).length,h=c.filter(t=>t.confidence>=70).length;return[`\u{1F9EA} **Knowledge Decay Report** \u2014 ${c.length} lessons`,"",`Average confidence: **${f(k)}**`,`\u{1F534} Critical (<30%): ${b} \u{1F7E2} Healthy (\u226570%): ${h}`,"","Lowest confidence lessons (fix these first):","",...y.map((t,o)=>`${(o+1).toString().padStart(2)}. \`${t.topic}\`
8
8
  ${f(t.confidence)} \xB7 ${t.age_days}d old \xB7 ${t.recalls} recalls \xB7 ${t.outcome}`),"",c.length>$?`\u2026 and ${c.length-$} more lessons`:"","",b>0?`\u26A0\uFE0F ${b} lessons are critically stale. Validate them and re-run \`learn_from_attempts\` with updated findings.`:"\u2705 Brain confidence is healthy overall.","","\u{1F4A1} Run `memory_consolidate` to prune stale entries \xB7 `causal_trace` to find root causes."].filter(t=>t!=="").join(`
9
9
  `)}case"autopilot":{const{instance_id:l,editor:g="claude",project_name:$="this project",style:m="full"}=S,w=z({editor:String(g),project_name:String($)},"die Anweisungsdatei (CLAUDE.md)");if(!w.ok)return w.meldung;const d=(b,h)=>b.replace(/[\p{C}\s]+/gu," ").trim().slice(0,h),u=d(w.felder.editor,30)||"claude",_=d(w.felder.project_name,80)||"this project",c=`## Cachly AI Brain \u2014 Autopilot