@cachly-dev/mcp-server 0.10.184 → 0.10.186
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 +6 -6
- package/dist/src/autor.js +1 -1
- package/dist/src/brain-watch-hook.js +7 -7
- package/dist/src/browser-adresse.js +1 -0
- package/dist/src/cls-hook.js +6 -6
- package/dist/src/embeddings.js +2 -2
- package/dist/src/git-ohne-shell.js +1 -0
- package/dist/src/handlers/brain.js +60 -60
- package/dist/src/handlers/cache.js +28 -32
- package/dist/src/handlers/fedbrain.js +38 -38
- package/dist/src/index.js +129 -129
- package/glama.json +1 -1
- package/hooks/cachly-ambient-einblendung.mjs +11 -11
- package/package.json +4 -3
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
> the right moment. You build faster, and your team builds on what you figured out.
|
|
7
7
|
|
|
8
8
|
[](https://www.npmjs.com/package/@cachly-dev/mcp-server)
|
|
9
|
-

|
|
10
9
|

|
|
11
10
|
|
|
12
11
|
`@cachly-dev/mcp-server` connects [cachly](https://cachly.dev) to Claude Code, Cursor,
|
|
13
12
|
GitHub Copilot, Windsurf, Cline, Continue.dev, Zed, Codex CLI and Gemini CLI over
|
|
14
|
-
[MCP](https://modelcontextprotocol.io). It offers 124 MCP tools. Your
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
[MCP](https://modelcontextprotocol.io). It offers 124 MCP tools. Your editor lists 27 entries
|
|
14
|
+
by default and reaches the rest through one of them, `cachly_tool` (details under MCP
|
|
15
|
+
Tools below). Your AI stores a lesson after a fix, and finds it again when the same
|
|
16
|
+
problem returns. Your Brain (the store of your lessons) lives on EU servers.
|
|
17
17
|
|
|
18
18
|
## Start without an account
|
|
19
19
|
|
|
@@ -151,7 +151,7 @@ cachly_tool(tool: "team_roster", describe: true) get its schema first
|
|
|
151
151
|
|
|
152
152
|
Nothing is unreachable. The server dispatches by name, so `team_roster` called directly
|
|
153
153
|
still works. Set `CACHLY_ALLE_WERKZEUGE=1` to list all 124. Set `CACHLY_PROFILE=lean` to
|
|
154
|
-
list 8
|
|
154
|
+
list 8 plus `cachly_tool`, or `CACHLY_PROFILE=recall` to list the 3 read-only tools.
|
|
155
155
|
|
|
156
156
|
### Session and lessons (most used)
|
|
157
157
|
|
|
@@ -441,7 +441,7 @@ The free tier needs no credit card.
|
|
|
441
441
|
| `CACHLY_API_URL` | `https://api.cachly.dev` | Override for a self-hosted backend |
|
|
442
442
|
| `CACHLY_EMBED_PROVIDER` | automatic | Name an embedding provider yourself (see above) |
|
|
443
443
|
| `CACHLY_ALLE_WERKZEUGE` | unset | Set to `1` to list all 124 tools instead of 27 |
|
|
444
|
-
| `CACHLY_PROFILE` | unset | `lean` lists 8 tools
|
|
444
|
+
| `CACHLY_PROFILE` | unset | `lean` lists 8 tools plus `cachly_tool`, `recall` lists the 3 read-only tools |
|
|
445
445
|
| `CACHLY_UPDATE_CHECK` | on | Set to `false` to stop the version check. npm is asked at most once a day, with a 2-second limit |
|
|
446
446
|
| `CACHLY_NO_TELEMETRY` | unset | Set to `1` to disable usage pings. They include your API token and up to 80 characters of `smart_recall` queries |
|
|
447
447
|
|
package/dist/src/autor.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
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,8 +1,8 @@
|
|
|
1
|
-
import{existsSync as _}from"node:fs";import{readFile as
|
|
2
|
-
`,"utf-8"),await c(t,493).catch(()=>{}),{result:"written",hookPath:t};if(
|
|
3
|
-
`)?
|
|
4
|
-
`,"utf-8"),await c(t,493).catch(()=>{}),{result:"upgraded",hookPath:t}}return await o(t,
|
|
1
|
+
import{existsSync as _}from"node:fs";import{readFile as m,writeFile as o,chmod as c,mkdir as p}from"node:fs/promises";import{resolve as s}from"node:path";import{instanzIdFuerSkript as f,schluesselFuerSkript as $}from"./git-ohne-shell.js";const u="v1",h=/(?:#!\/bin\/sh\n)?# cachly brain_watch[\s\S]*?\nexit 0\n?/;async function H(r,e,d){if(!_(s(r,".git")))return{result:"skipped-no-git",hookPath:""};const l=s(r,".git","hooks"),t=s(l,"post-commit");await p(l,{recursive:!0});const i=w(e,d);let n="";try{n=await m(t,"utf-8")}catch{}if(!n)return await o(t,i+`
|
|
2
|
+
`,"utf-8"),await c(t,493).catch(()=>{}),{result:"written",hookPath:t};if(n.includes(`cachly brain_watch \u2014 Auto-Learn ${u}`))return{result:"unchanged",hookPath:t};if(h.test(n)){const a=n.replace(h,i);return await o(t,a.endsWith(`
|
|
3
|
+
`)?a:a+`
|
|
4
|
+
`,"utf-8"),await c(t,493).catch(()=>{}),{result:"upgraded",hookPath:t}}return await o(t,n.trimEnd()+`
|
|
5
5
|
|
|
6
|
-
`+
|
|
7
|
-
`,"utf-8"),await c(t,493).catch(()=>{}),{result:"appended",hookPath:t}}function
|
|
8
|
-
`)}export{u as BRAIN_WATCH_HOOK_VERSION,
|
|
6
|
+
`+i+`
|
|
7
|
+
`,"utf-8"),await c(t,493).catch(()=>{}),{result:"appended",hookPath:t}}function w(r,e){return r=f(r),e&&(e=$(e)),["#!/bin/sh",`# cachly brain_watch \u2014 Auto-Learn ${u}`,"# Silently teaches your Brain after every commit \u2014 no manual brain_from_git needed.",...e?[`CACHLY_JWT="${e}"`]:[],'_BW_SHA=$(git rev-parse HEAD 2>/dev/null || echo "")',"_BW_MSG=$(git log -1 --pretty=%B 2>/dev/null | head -1 | cut -c1-200)","_BW_FILES=$(git diff-tree --no-commit-id -r --name-only HEAD 2>/dev/null | tr '\\n' '\\t' | sed 's/\\t$//')","(curl -s -o /dev/null -m 8 \\",` -X POST "https://api.cachly.dev/api/v1/instances/${r}/learn" \\`,' -H "Authorization: Bearer ${CACHLY_JWT}" \\',' -H "Content-Type: application/json" \\',` --data-raw "{\\"message\\":\\"$(echo "$_BW_MSG" | sed 's/"/\\\\"/g')\\",\\"sha\\":\\"$_BW_SHA\\",\\"files\\":[$(echo "$_BW_FILES" | tr '\\t' '\\n' | grep -v '^$' | sed 's/.*/\\"&\\"/' | tr '\\n' ',' | sed 's/,$//')],\\"source\\":\\"brain_watch\\"}" \\`,") 2>/dev/null &","exit 0"].join(`
|
|
8
|
+
`)}export{u as BRAIN_WATCH_HOOK_VERSION,w as buildBrainWatchHook,H as installBrainWatchHook};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(r){if(typeof r!="string")return null;try{const t=new URL(r);return t.protocol==="http:"||t.protocol==="https:"?t.href:null}catch{return null}}function n(r){return r.replace(/[&|<>^]/g,"^$&")}export{e as browserAdresse,n as fuerCmd};
|
package/dist/src/cls-hook.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{existsSync as C}from"node:fs";import{readFile as
|
|
2
|
-
`,"utf-8"),await c(
|
|
1
|
+
import{existsSync as C}from"node:fs";import{readFile as m,writeFile as s,chmod as c,mkdir as d}from"node:fs/promises";import{resolve as a}from"node:path";import{instanzIdFuerSkript as _,schluesselFuerSkript as L}from"./git-ohne-shell.js";const u="v2",S=/(?:#!\/bin\/sh\n)?# cachly CLS[\s\S]*?\nexit 0\n?/;async function y(n,t,p){if(!C(a(n,".git")))return"skipped-no-git";const l=a(n,".git","hooks"),e=a(l,"post-commit");await d(l,{recursive:!0});const i=f(t,p);let o="";try{o=await m(e,"utf-8")}catch{}if(!o)return await s(e,i+`
|
|
2
|
+
`,"utf-8"),await c(e,493).catch(()=>{}),"written";if(o.includes(`cachly CLS \u2014 Continuous Learning Stream ${u}`))return"unchanged";if(S.test(o)){const r=o.replace(S,i);return await s(e,r.endsWith(`
|
|
3
3
|
`)?r:r+`
|
|
4
|
-
`,"utf-8"),await c(
|
|
4
|
+
`,"utf-8"),await c(e,493).catch(()=>{}),"upgraded"}return await s(e,o.trimEnd()+`
|
|
5
5
|
|
|
6
|
-
`+
|
|
7
|
-
`,"utf-8"),await c(
|
|
8
|
-
`)}export{u as CLS_HOOK_VERSION,
|
|
6
|
+
`+i+`
|
|
7
|
+
`,"utf-8"),await c(e,493).catch(()=>{}),"appended"}const h="try{var p={instance_id:process.env.CACHLY_BRAIN_INSTANCE_ID,source:'git_commit',payload:{message:process.env.CLS_MSG||'',sha:process.env.CLS_SHA||'',files:(process.env.CLS_FILES||'').split(',').filter(Boolean)}};require('child_process').execFileSync('npx',['@cachly-dev/mcp-server@latest','cls-ingest',JSON.stringify(p)],{stdio:'ignore',timeout:8000});}catch(e){}";function f(n,t){return n=_(n),t&&(t=L(t)),["#!/bin/sh",`# cachly CLS \u2014 Continuous Learning Stream ${u}`,"# Runs silently on every commit to keep your brain up to date.",`export CACHLY_BRAIN_INSTANCE_ID="${n}"`,...t?[`export CACHLY_JWT="${t}"`]:[],'CLS_SHA=$(git rev-parse HEAD 2>/dev/null || echo "")',"CLS_MSG=$(git log -1 --pretty=%B 2>/dev/null | head -1 | cut -c1-200)","CLS_FILES=$(git diff-tree --no-commit-id -r --name-only HEAD 2>/dev/null | tr '\\n' ',' | sed 's/,$//')","export CLS_SHA CLS_MSG CLS_FILES",`node -e "${h}" 2>/dev/null &`,"exit 0"].join(`
|
|
8
|
+
`)}export{u as CLS_HOOK_VERSION,f as buildClsPostCommitHook,y as installClsPostCommitHook};
|
package/dist/src/embeddings.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{zeitpunkt as u}from"./zeitmessung.js";const s={apiUrl:process.env.CACHLY_API_URL??"https://api.cachly.dev",jwt:process.env.CACHLY_JWT??"",model:process.env.CACHLY_EMBED_MODEL??""};function
|
|
1
|
+
import{zeitpunkt as u}from"./zeitmessung.js";const s={apiUrl:process.env.CACHLY_API_URL??"https://api.cachly.dev",jwt:process.env.CACHLY_JWT??"",model:process.env.CACHLY_EMBED_MODEL??""};function S(n){s.jwt=n,n&&!b&&c==="none"&&(c="cachly")}const A=Number(process.env.CACHLY_EMBED_TIMEOUT_MS??8e3),p=Number(process.env.CACHLY_EMBED_TIMEOUT_MAX_MS??45e3),h=12;function f(n,r){return r==="kurz"?A:Math.min(p,A+n.length*h)}function g(){return process.env.CACHLY_JWT?"cachly":process.env.OLLAMA_BASE_URL?"ollama":"none"}const b=!!process.env.CACHLY_EMBED_PROVIDER;let c=(process.env.CACHLY_EMBED_PROVIDER??g()).toLowerCase();async function I(n,r,a){const d=f(n,r);switch(c){case"cachly":{if(!s.jwt)throw new Error(`CACHLY_JWT not set.
|
|
2
2
|
|
|
3
3
|
The "cachly" provider uses server-side embeddings via the Cachly API.
|
|
4
4
|
Set CACHLY_JWT, or use another provider via CACHLY_EMBED_PROVIDER:
|
|
@@ -10,4 +10,4 @@ Set OPENAI_API_KEY in your .env, or switch provider:
|
|
|
10
10
|
CACHLY_EMBED_PROVIDER=gemini (+ GEMINI_API_KEY)
|
|
11
11
|
CACHLY_EMBED_PROVIDER=ollama (local, free)
|
|
12
12
|
CACHLY_EMBED_PROVIDER=cachly (server-side, no key needed)`);const o=s.model||"text-embedding-3-small",t=await fetch("https://api.openai.com/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({model:o,input:n}),signal:AbortSignal.timeout(d)});if(!t.ok)throw new Error(`OpenAI embedding error: ${t.statusText}`);const i=await t.json();if(!i.data?.[0]?.embedding)throw new Error("OpenAI returned empty embedding response");return i.data[0].embedding}default:throw new Error(`Unknown CACHLY_EMBED_PROVIDER="${c}".
|
|
13
|
-
Supported: cachly (default), openai, mistral, cohere, ollama, gemini`)}}const y=3,
|
|
13
|
+
Supported: cachly (default), openai, mistral, cohere, ollama, gemini`)}}const y=3,C=4;function w(n){const r=n;if(typeof r?.status=="number")return r.status===429||r.status>=500;if(r?.name==="TimeoutError"||r?.name==="AbortError")return!1;if(/fetch failed/i.test(String(r?.message??"")))return!0;const a=r?.cause?.code??"";return["ECONNRESET","ECONNREFUSED","ETIMEDOUT","EAI_AGAIN","EPIPE","UND_ERR_SOCKET"].includes(a)}function M(n,r,a){if(r>=(a==="lang"?C:y)||!w(n))return null;const e=n?.retryAfterSek;if(typeof e=="number"&&Number.isFinite(e)&&e>=0){const o=e*1e3;return a==="kurz"?o<=2e3?o:null:Math.min(o,61e3)}return a==="lang"?Math.min(1e3*2**(r-1),8e3):250*2**(r-1)}async function L(n,r){const a=r?.geduld??"kurz";if(r?.modell&&c!=="cachly"&&c!=="ollama")throw new Error(`Anbieter "${c}" kann kein abweichendes Modell anfragen (verlangt: ${r.modell}).`);let d=0;for(;;){d++;try{u(`einbettung: Anfang (${n.length} Zeichen, Versuch ${d})`);const e=await I(n,a,r?.modell);return u("einbettung: fertig"),e}catch(e){const o=M(e,d,a);if(o===null)throw e;await new Promise(t=>setTimeout(t,o))}}}function T(){switch(c){case"cachly":return!!s.jwt;case"mistral":return!!process.env.MISTRAL_API_KEY;case"cohere":return!!process.env.COHERE_API_KEY;case"ollama":return!0;case"gemini":return!!process.env.GEMINI_API_KEY;case"openai":return!!process.env.OPENAI_API_KEY;case"none":return!1;default:return!1}}function v(){const n={cachly:"CACHLY_JWT (server-side, no extra key needed)",openai:"OPENAI_API_KEY",mistral:"MISTRAL_API_KEY",cohere:"COHERE_API_KEY",ollama:"OLLAMA_BASE_URL (optional, default: http://localhost:11434)",gemini:"GEMINI_API_KEY"};if(c==="none")return"No embedding provider configured. Sign in (CACHLY_JWT) to use the EU-hosted cachly embeddings, or set OLLAMA_BASE_URL for a local model. Brain works without embedding.";const r=n[c]??"CACHLY_JWT";return`CACHLY_EMBED_PROVIDER=${c} \u2192 requires ${r}`}export{c as EMBED_PROVIDER,L as computeEmbedding,s as embedConfig,v as embedProviderHint,T as hasEmbedProvider,w as istVoruebergehend,S as setEmbedJwt,M as wiederholungMs,f as zeitlimitMs};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{execFileSync as r}from"node:child_process";import{statSync as i}from"node:fs";import{resolve as o}from"node:path";function p(t){if(typeof t!="string"||t===""||t.includes("\0"))return null;const e=o(t);try{return i(e).isDirectory()?e:null}catch{return null}}function a(t){return typeof t=="string"&&/^[0-9a-f]{7,64}$/i.test(t)}function h(t){return t.startsWith("-")}const u=/^[A-Za-z0-9_-]{1,64}$/,s=/^[A-Za-z0-9._~-]{1,4096}$/;function d(t){if(typeof t!="string"||!u.test(t))throw new Error("instance_id fehlt oder enthaelt Zeichen, die nicht in ein Hook-Skript gehoeren (erlaubt: Buchstaben, Ziffern, _ und -).");return t}function S(t){if(typeof t!="string"||!s.test(t))throw new Error("Der API-Schluessel enthaelt Zeichen, die nicht in ein Hook-Skript gehoeren (erlaubt: Buchstaben, Ziffern, ., _, ~ und -).");return t}function g(t){return`'${t.replace(/'/g,"'\\''")}'`}function m(t,e,n={}){return r("git",[...e],{cwd:t,encoding:"utf-8",stdio:["ignore","pipe",n.stderr??"ignore"],timeout:n.timeoutMs??5e3,windowsHide:!0})}export{g as alsShellWort,h as beginntMitBindestrich,m as gitLesen,d as instanzIdFuerSkript,a as istCommitHash,p as pruefeOrdner,S as schluesselFuerSkript};
|