@cachly-dev/mcp-server 0.10.222 → 0.10.224
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 +8 -2
- package/dist/src/abstention.js +2 -2
- package/dist/src/autor.js +1 -1
- package/dist/src/doppel-kandidat.js +1 -1
- package/dist/src/entscheidung-ableiten.js +1 -1
- package/dist/src/ersetzung-vorschlag.js +1 -1
- package/dist/src/handlers/brain.js +64 -65
- package/dist/src/index.js +42 -42
- package/dist/src/leeres-brain.js +5 -5
- package/dist/src/rangfolge.js +1 -1
- package/dist/src/search.js +1 -1
- package/dist/src/sitzungs-kosten.js +1 -1
- package/dist/src/startwissen.js +19 -19
- package/dist/src/upgrade-nudge.js +1 -1
- package/dist/src/vorspann.js +1 -1
- package/glama.json +1 -1
- package/hooks/cachly-ambient-einblendung.mjs +17 -17
- package/package.json +1 -1
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -64,13 +64,19 @@ 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
|
|
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`), which tells your AI to check its memory before a task. It adds a git
|
|
68
71
|
hook that learns from your commits and fills your Brain from your git history. You sign
|
|
69
72
|
in once in the browser (a device code, no password, no credit card), so the Brain
|
|
70
73
|
belongs to your own account from the start. Restart your editor afterwards.
|
|
71
74
|
|
|
72
75
|
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.
|
|
76
|
+
the first tool call creates the same test Brain as in Claude Code. Without a rule file,
|
|
77
|
+
Claude Code still starts each task with `smart_recall`, because the server's instructions
|
|
78
|
+
ask for it. Some editors do not pass those instructions to the AI (Cline, for example);
|
|
79
|
+
there, the rule file from `autopilot` is what makes your AI use its memory.
|
|
74
80
|
|
|
75
81
|
> **Already inside Claude, Cursor or Copilot?** Paste this to your AI:
|
|
76
82
|
> ```
|
package/dist/src/abstention.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{CKG_BELEG_SCHWELLE as
|
|
2
|
-
`)}const b=5;function
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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};
|