@cachly-dev/mcp-server 0.10.224 → 0.10.226

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
@@ -67,7 +67,8 @@ npx @cachly-dev/mcp-server@latest autopilot
67
67
  `autopilot` finds the editors you use and writes the MCP config for each. It also writes
68
68
  the rule file each editor reads in every chat (`CLAUDE.md`, `AGENTS.md`,
69
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
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
71
72
  hook that learns from your commits and fills your Brain from your git history. You sign
72
73
  in once in the browser (a device code, no password, no credit card), so the Brain
73
74
  belongs to your own account from the start. Restart your editor afterwards.
@@ -75,8 +76,8 @@ belongs to your own account from the start. Restart your editor afterwards.
75
76
  You can also add the server by hand (see [Manual Setup](#manual-setup)). Without a key,
76
77
  the first tool call creates the same test Brain as in Claude Code. Without a rule file,
77
78
  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.
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.
80
81
 
81
82
  > **Already inside Claude, Cursor or Copilot?** Paste this to your AI:
82
83
  > ```
@@ -342,7 +343,7 @@ Manual snippets are in [Manual Setup](#manual-setup).
342
343
 
343
344
  | Editor / client | Auto-setup | Config file written | Global config | Notes |
344
345
  |---|---|---|---|---|
345
- | **Claude Code** | yes | `~/.claude/mcp.json` + `.mcp.json` | yes, always | Without a key: test Brain at session start (plugin) or on the first tool call; browser sign-in only as fallback |
346
+ | **Claude Code** | yes | `.mcp.json` | with the plugin | Without a key: test Brain at session start (plugin) or on the first tool call; browser sign-in only as fallback |
346
347
  | **Cursor** | yes, detected via `.cursor/` | `.cursor/mcp.json`, hooks in `.cursor/hooks.json` | no | Project-level; restart Cursor after setup. Lessons arrive with the first tool call of a turn |
347
348
  | **Windsurf** | yes, detected via `.windsurf/` | `.windsurf/mcp.json` | no | Project-level; restart Windsurf after setup |
348
349
  | **VS Code + Copilot** | yes, detected via `.vscode/` | `.vscode/mcp.json`, hooks in `.github/hooks/cachly-ambient.json` | no | Needs the VS Code MCP support or Copilot chat. Briefing at session start, lessons before each prompt |
@@ -360,14 +361,14 @@ Manual snippets are in [Manual Setup](#manual-setup).
360
361
  |---|---|
361
362
  | `autosetup` or `autopilot` from a terminal (TTY) | OAuth device flow: one click in the browser, the API key is saved automatically |
362
363
  | `autosetup` from a VS Code task or CI (no TTY) | Detects the non-interactive run, opens the browser with a step-by-step guide, prints the `CACHLY_JWT=... autosetup` command |
363
- | First tool call without any key | Test Brain: an anonymous Brain on EU servers. The key is saved to `~/.cachly/credentials.json` and `~/.claude/mcp.json`, and the call goes through. If that fails (offline, rate limit), the inline device flow starts with a URL and a code |
364
+ | First tool call without any key | Test Brain: an anonymous Brain on EU servers. The key is saved to `~/.cachly/credentials.json`, and the call goes through. If that fails (offline, rate limit), the inline device flow starts with a URL and a code |
364
365
  | First tool call with `CACHLY_BRAIN_INSTANCE_ID` set but no key | Inline device flow. You already have a Brain, so no second account is created |
365
366
  | `CACHLY_JWT=cky_live_xxx npx ... autosetup` | Skips the sign-in step and uses the key you pass |
366
367
 
367
368
  ## Manual Setup
368
369
 
369
370
  <details>
370
- <summary><b>Claude Code</b> (<code>~/.claude/mcp.json</code> or <code>.mcp.json</code>)</summary>
371
+ <summary><b>Claude Code</b> (<code>.mcp.json</code> in the project)</summary>
371
372
 
372
373
  ```json
373
374
  {
@@ -380,6 +381,10 @@ Manual snippets are in [Manual Setup](#manual-setup).
380
381
  }
381
382
  ```
382
383
 
384
+ For all your projects at once, use the plugin above, or
385
+ `claude mcp add -s user cachly -- npx -y @cachly-dev/mcp-server@latest`
386
+ (Claude Code stores that in `~/.claude.json`).
387
+
383
388
  Without a key, the first tool call creates a test Brain on EU servers. No sign-up.
384
389
  Run `npx @cachly-dev/mcp-server@latest autopilot` to use your own account instead.
385
390
  </details>
@@ -1 +1 @@
1
- const u=new Set;function i(e){if(e instanceof Error)return(e.message||e.name||"Error").slice(0,200);if(typeof e=="string")return e.slice(0,200)||"leerer Text geworfen";if(e===void 0)return"undefined geworfen (kein Grund mitgegeben)";if(e===null)return"null geworfen (kein Grund mitgegeben)";try{const n=JSON.stringify(e);return n&&n!=="{}"?n.slice(0,200):`${typeof e} ohne Inhalt geworfen`}catch{return`${typeof e} geworfen, nicht darstellbar`}}function c(e,n){return u.has(e)?!1:(u.add(e),console.error(`[aussetzer] ${e}: ${n}`),!0)}function l(e){return u.has(e)}function f(){return[...u]}function h(){u.clear()}const g="bedeutung-ohne-vektoren",E="bedeutung-ohne-dienst",m="bedeutung-ohne-fragevektor",p="bedeutung-abbruch",x="einbettung-beim-schreiben",d="versuch-laeuft-leer",s="cachly:aussetzer:",a=720*60*60;async function z(e,n,o){const r=c(n,o);if(!e)return r;try{const t=`${s}${n}`;await e.hincrby(t,"anzahl",1),await e.hset(t,{zuletzt:new Date().toISOString(),text:o.slice(0,500)}),await e.expire(t,a)}catch(t){c(`${n}-vermerk`,`der Aussetzer liess sich nicht vermerken (${t instanceof Error?t.message:String(t)}) \u2014 er steht nur in diesem Protokoll und ist nach einem Neustart weg`)}return r}async function k(e){if(!e)return null;try{const n=await e.keys(`${s}*`),o=[];for(const r of n){const t=await e.hgetall(r);!t||!t.anzahl||o.push({grund:r.slice(s.length),anzahl:Number(t.anzahl)||0,zuletzt:t.zuletzt??"",text:t.text??""})}return o.sort((r,t)=>t.anzahl-r.anzahl||r.grund.localeCompare(t.grund)),o}catch{return null}}export{a as AUSSETZER_TTL_SEKUNDEN,s as AUSSETZER_VORSATZ,E as OHNE_DIENST,m as OHNE_FRAGEVEKTOR,x as OHNE_SCHREIBVEKTOR,g as OHNE_VEKTOREN,p as SINNPFAD_ABBRUCH,d as VERSUCH_LEER,i as fehlerText,f as gemeldeteGruende,k as leseVermerke,c as meldeEinmal,z as meldeUndVermerke,l as schonGemeldet,h as setzeAussetzerZurueck};
1
+ const s=new Set;let u=!1;function l(){u=!0}function f(e){if(e instanceof Error)return(e.message||e.name||"Error").slice(0,200);if(typeof e=="string")return e.slice(0,200)||"leerer Text geworfen";if(e===void 0)return"undefined geworfen (kein Grund mitgegeben)";if(e===null)return"null geworfen (kein Grund mitgegeben)";try{const n=JSON.stringify(e);return n&&n!=="{}"?n.slice(0,200):`${typeof e} ohne Inhalt geworfen`}catch{return`${typeof e} geworfen, nicht darstellbar`}}function c(e,n){return s.has(e)?!1:(s.add(e),u||console.error(`[aussetzer] ${e}: ${n}`),!0)}function h(e){return s.has(e)}function g(){return[...s]}function E(){s.clear(),u=!1}const m="bedeutung-ohne-vektoren",p="bedeutung-ohne-dienst",x="bedeutung-ohne-fragevektor",d="bedeutung-abbruch",z="einbettung-beim-schreiben",k="versuch-laeuft-leer",a="cachly:aussetzer:",i=720*60*60;async function y(e,n,o){const r=c(n,o);if(!e)return r;try{const t=`${a}${n}`;await e.hincrby(t,"anzahl",1),await e.hset(t,{zuletzt:new Date().toISOString(),text:o.slice(0,500)}),await e.expire(t,i)}catch(t){c(`${n}-vermerk`,`der Aussetzer liess sich nicht vermerken (${t instanceof Error?t.message:String(t)}) \u2014 er steht nur in diesem Protokoll und ist nach einem Neustart weg`)}return r}async function S(e){if(!e)return null;try{const n=await e.keys(`${a}*`),o=[];for(const r of n){const t=await e.hgetall(r);!t||!t.anzahl||o.push({grund:r.slice(a.length),anzahl:Number(t.anzahl)||0,zuletzt:t.zuletzt??"",text:t.text??""})}return o.sort((r,t)=>t.anzahl-r.anzahl||r.grund.localeCompare(t.grund)),o}catch{return null}}export{i as AUSSETZER_TTL_SEKUNDEN,a as AUSSETZER_VORSATZ,p as OHNE_DIENST,x as OHNE_FRAGEVEKTOR,z as OHNE_SCHREIBVEKTOR,m as OHNE_VEKTOREN,d as SINNPFAD_ABBRUCH,k as VERSUCH_LEER,l as aussetzerLeise,f as fehlerText,g as gemeldeteGruende,S as leseVermerke,c as meldeEinmal,y as meldeUndVermerke,h as schonGemeldet,E as setzeAussetzerZurueck};
@@ -1,13 +1,13 @@
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.
1
+ import{zeitpunkt as A}from"./zeitmessung.js";const i={apiUrl:process.env.CACHLY_API_URL??"https://api.cachly.dev",jwt:process.env.CACHLY_JWT??"",model:process.env.CACHLY_EMBED_MODEL??""};function R(r){i.jwt=r,r&&!I&&d==="none"&&(d="cachly")}const h=Number(process.env.CACHLY_EMBED_TIMEOUT_MS??8e3),p=Number(process.env.CACHLY_EMBED_TIMEOUT_MAX_MS??45e3),g=12;function f(r,n){return n==="kurz"?h:Math.min(p,h+r.length*g)}function b(){return process.env.CACHLY_JWT?"cachly":process.env.OLLAMA_BASE_URL?"ollama":"none"}const I=!!process.env.CACHLY_EMBED_PROVIDER;let d=(process.env.CACHLY_EMBED_PROVIDER??b()).toLowerCase();async function y(r,n,s){const c=f(r,n);switch(d){case"cachly":{if(!i.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:
5
5
  openai \u2192 OPENAI_API_KEY
6
6
  gemini \u2192 GEMINI_API_KEY
7
- ollama \u2192 OLLAMA_BASE_URL (local, no key needed)`);const e=`${s.apiUrl}/api/v1/embed`,o={text:n};(a??s.model)&&(o.model=a??s.model);const t=process.env.CACHLY_ADMIN_KEY??"",i=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s.jwt}`,...t?{"X-Admin-Key":t}:{}},body:JSON.stringify(o),signal:AbortSignal.timeout(d)});if(!i.ok){const _=await i.text();let l=null;const m=Number(i.headers.get("retry-after"));if(Number.isFinite(m)&&m>=0)l=m;else try{const E=JSON.parse(_);typeof E.retry_after=="number"&&E.retry_after>=0&&(l=E.retry_after)}catch{}throw Object.assign(new Error(`Cachly embed API error ${i.status}: ${_.slice(0,200)}`),{status:i.status,retryAfterSek:l})}return(await i.json()).embedding}case"mistral":{const e=process.env.MISTRAL_API_KEY;if(!e)throw new Error("MISTRAL_API_KEY not set");const o=s.model!=="text-embedding-3-small"?s.model:"mistral-embed",t=await fetch("https://api.mistral.ai/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(`Mistral embedding error: ${t.statusText}`);const i=await t.json();if(!i.data?.[0]?.embedding)throw new Error("Mistral returned empty embedding response");return i.data[0].embedding}case"cohere":{const e=process.env.COHERE_API_KEY;if(!e)throw new Error("COHERE_API_KEY not set");const o=s.model!=="text-embedding-3-small"?s.model:"embed-english-v3.0",t=await fetch("https://api.cohere.com/v2/embed",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({model:o,texts:[n],input_type:"search_query",embedding_types:["float"]}),signal:AbortSignal.timeout(d)});if(!t.ok)throw new Error(`Cohere embedding error: ${t.statusText}`);return(await t.json()).embeddings.float[0]}case"ollama":{const e=process.env.OLLAMA_BASE_URL??"http://localhost:11434",o=a??(s.model!=="text-embedding-3-small"?s.model:"nomic-embed-text"),t=await fetch(`${e}/api/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:o,prompt:n}),signal:AbortSignal.timeout(d)});if(!t.ok)throw new Error(`Ollama embedding error: ${t.statusText}`);return(await t.json()).embedding}case"gemini":{const e=process.env.GEMINI_API_KEY;if(!e)throw new Error("GEMINI_API_KEY not set");const o=s.model!=="text-embedding-3-small"?s.model:"text-embedding-004",t=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${o}:embedContent?key=${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:`models/${o}`,content:{parts:[{text:n}]}}),signal:AbortSignal.timeout(d)});if(!t.ok)throw new Error(`Gemini embedding error: ${t.statusText}`);return(await t.json()).embedding.values}case"openai":{const e=process.env.OPENAI_API_KEY;if(!e)throw new Error(`OPENAI_API_KEY not set.
7
+ ollama \u2192 OLLAMA_BASE_URL (local, no key needed)`);const e=`${i.apiUrl}/api/v1/embed`,o={text:r};(s??i.model)&&(o.model=s??i.model);const t=process.env.CACHLY_ADMIN_KEY??"",a=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${i.jwt}`,...t?{"X-Admin-Key":t}:{}},body:JSON.stringify(o),signal:AbortSignal.timeout(c)});if(!a.ok){const _=await a.text();let E=null;const m=Number(a.headers.get("retry-after"));if(Number.isFinite(m)&&m>=0)E=m;else try{const u=JSON.parse(_);typeof u.retry_after=="number"&&u.retry_after>=0&&(E=u.retry_after)}catch{}throw Object.assign(new Error(`Cachly embed API error ${a.status}: ${_.slice(0,200)}`),{status:a.status,retryAfterSek:E})}return(await a.json()).embedding}case"mistral":{const e=process.env.MISTRAL_API_KEY;if(!e)throw new Error("MISTRAL_API_KEY not set");const o=i.model!=="text-embedding-3-small"?i.model:"mistral-embed",t=await fetch("https://api.mistral.ai/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({model:o,input:[r]}),signal:AbortSignal.timeout(c)});if(!t.ok)throw new Error(`Mistral embedding error: ${t.statusText}`);const a=await t.json();if(!a.data?.[0]?.embedding)throw new Error("Mistral returned empty embedding response");return a.data[0].embedding}case"cohere":{const e=process.env.COHERE_API_KEY;if(!e)throw new Error("COHERE_API_KEY not set");const o=i.model!=="text-embedding-3-small"?i.model:"embed-english-v3.0",t=await fetch("https://api.cohere.com/v2/embed",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({model:o,texts:[r],input_type:"search_query",embedding_types:["float"]}),signal:AbortSignal.timeout(c)});if(!t.ok)throw new Error(`Cohere embedding error: ${t.statusText}`);return(await t.json()).embeddings.float[0]}case"ollama":{const e=process.env.OLLAMA_BASE_URL??"http://localhost:11434",o=s??(i.model!=="text-embedding-3-small"?i.model:"nomic-embed-text"),t=await fetch(`${e}/api/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:o,prompt:r}),signal:AbortSignal.timeout(c)});if(!t.ok)throw new Error(`Ollama embedding error: ${t.statusText}`);return(await t.json()).embedding}case"gemini":{const e=process.env.GEMINI_API_KEY;if(!e)throw new Error("GEMINI_API_KEY not set");const o=i.model!=="text-embedding-3-small"?i.model:"text-embedding-004",t=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${o}:embedContent?key=${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:`models/${o}`,content:{parts:[{text:r}]}}),signal:AbortSignal.timeout(c)});if(!t.ok)throw new Error(`Gemini embedding error: ${t.statusText}`);return(await t.json()).embedding.values}case"openai":{const e=process.env.OPENAI_API_KEY;if(!e)throw new Error(`OPENAI_API_KEY not set.
8
8
 
9
9
  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
- 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,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};
12
+ CACHLY_EMBED_PROVIDER=cachly (server-side, no key needed)`);const o=i.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:r}),signal:AbortSignal.timeout(c)});if(!t.ok)throw new Error(`OpenAI embedding error: ${t.statusText}`);const a=await t.json();if(!a.data?.[0]?.embedding)throw new Error("OpenAI returned empty embedding response");return a.data[0].embedding}default:throw new Error(`Unknown CACHLY_EMBED_PROVIDER="${d}".
13
+ Supported: cachly (default), openai, mistral, cohere, ollama, gemini`)}}const w=3,C=4;function M(r){const n=r;if(typeof n?.status=="number")return n.status===429||n.status>=500;if(n?.name==="TimeoutError"||n?.name==="AbortError")return!1;if(/fetch failed/i.test(String(n?.message??"")))return!0;const s=n?.cause?.code??"";return["ECONNRESET","ECONNREFUSED","ETIMEDOUT","EAI_AGAIN","EPIPE","UND_ERR_SOCKET"].includes(s)}function O(r,n,s){if(n>=(s==="lang"?C:w)||!M(r))return null;const e=r?.retryAfterSek;if(typeof e=="number"&&Number.isFinite(e)&&e>=0){const o=e*1e3;return s==="kurz"?o<=2e3?o:null:Math.min(o,61e3)}return s==="lang"?Math.min(1e3*2**(n-1),8e3):250*2**(n-1)}function N(r,n){const s=`${n?.modell??""}\0${n?.geduld??"kurz"}\0${r}`,c=Date.now(),e=l.get(s);if(e&&e.bis>c)return e.vektor;const o=T(r,n);if(l.set(s,{bis:c+P,vektor:o}),l.size>v){const t=l.keys().next().value;t!==void 0&&l.delete(t)}return o.catch(()=>{l.get(s)?.vektor===o&&l.delete(s)}),o}const P=6e4,v=200,l=new Map;function Y(){l.clear()}async function T(r,n){const s=n?.geduld??"kurz";if(n?.modell&&d!=="cachly"&&d!=="ollama")throw new Error(`Anbieter "${d}" kann kein abweichendes Modell anfragen (verlangt: ${n.modell}).`);let c=0;for(;;){c++;try{A(`einbettung: Anfang (${r.length} Zeichen, Versuch ${c})`);const e=await y(r,s,n?.modell);return A("einbettung: fertig"),e}catch(e){const o=O(e,c,s);if(o===null)throw e;await new Promise(t=>setTimeout(t,o))}}}function k(){switch(d){case"cachly":return!!i.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 D(){const r={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(d==="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 n=r[d]??"CACHLY_JWT";return`CACHLY_EMBED_PROVIDER=${d} \u2192 requires ${n}`}export{d as EMBED_PROVIDER,N as computeEmbedding,i as embedConfig,D as embedProviderHint,k as hasEmbedProvider,M as istVoruebergehend,R as setEmbedJwt,Y as vergissEinbettungen,O as wiederholungMs,f as zeitlimitMs};
@@ -1,4 +1,4 @@
1
- function l(o){if(!o)return null;const n=o.split(`
2
- `),t=n.findIndex(r=>/first recall already works/i.test(r));if(t===-1)return null;const e=[];for(let r=t;r<n.length&&!(r>t&&n[r].trim()==="");r++)e.push(n[r]);return e.join(`
3
- `).trim()||null}function s(o,n){const t=n.trim();return["\u{1F3AF} Proof \u2014 your first recall already works.",` Top hit: **${o}** \u2014 ${t}`].join(`
4
- `)}export{l as extractFirstRecallProof,s as renderFirstRecallProof};
1
+ function l(t){if(!t)return null;const r=t.split(`
2
+ `),e=r.findIndex(n=>/first recall already works/i.test(n));if(e===-1)return null;const i=[];for(let n=e;n<r.length&&!(n>e&&r[n].trim()==="");n++)i.push(r[n]);return i.join(`
3
+ `).trim()||null}function c(t,r){const e=r.trim();return["\u{1F3AF} Proof \u2014 your first recall already works.",` Top hit: ${t} \u2014 ${e}`].join(`
4
+ `)}function s(t){if(!t)return null;const r=/\*\*💡\s+([^*]+)\*\*/.exec(t);if(!r)return null;const e=t.slice(r.index+r[0].length),i=/^>\s+(.+)$/m.exec(e);if(!i)return null;const o=r[1].trim(),n=i[1].trim();return!o||!n?null:{topic:o,what:n}}function u(t){return t.replace(/\*\*/g,"").replace(/`/g,"")}export{l as extractFirstRecallProof,s as extractTopHit,u as fuersTerminal,c as renderFirstRecallProof};
@@ -0,0 +1 @@
1
+ import{createHash as r}from"node:crypto";function a(t){return`cachly:brain_from_git:last_sha:${r("sha256").update(t).digest("hex").slice(0,32)}`}function s(t){return`cachly:brain_from_git:last_sha:${Buffer.from(t).toString("base64").slice(0,32)}`}export{s as alterStartpunktSchluessel,a as startpunktSchluessel};
@@ -3,10 +3,10 @@ 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
- `)}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
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($)},"the instruction file (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
10
10
 
11
11
  **Instance:** \`${l}\`
12
12