@cachly-dev/mcp-server 0.10.204 → 0.10.206
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/src/ambient-hooks.js +9 -9
- package/dist/src/brain-watch-hook.js +4 -7
- package/dist/src/handlers/fedbrain.js +35 -35
- package/dist/src/index.js +15 -15
- package/dist/src/tools.js +1 -1
- package/glama.json +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`)}function
|
|
3
|
-
`&&(
|
|
4
|
-
`,"utf-8"),await
|
|
5
|
-
`,"utf-8")),{sessionStartPath:
|
|
6
|
-
`)}function
|
|
7
|
-
`,c=async p=>{try{return await
|
|
8
|
-
`,"utf-8")}return{scriptPath:
|
|
9
|
-
`}export{
|
|
1
|
+
import{existsSync as H,readFileSync as R}from"node:fs";import{readFile as j,writeFile as T,chmod as L,mkdir as x}from"node:fs/promises";import{dirname as G,resolve as l}from"node:path";import{fileURLToPath as rt}from"node:url";import{CURSOR_FLAG as nt}from"./cursor-hook.js";import{COPILOT_FLAG as st,COPILOT_HOOK_EVENTS as it}from"./copilot-hook.js";import{CODEX_FLAG as ct,CODEX_HOOK_EVENTS as at}from"./codex-hook.js";import{GEMINI_FLAG as ut,GEMINI_HOOK_EVENTS as mt}from"./gemini-hook.js";import{istCachlyEintrag as M}from"./hook-zugang.js";const v="v5",qt="ambient-recall",S="cachly-ambient-einblendung.mjs";function U(t){return t.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}function C(t,o){return["#!/usr/bin/env node",`// cachly Ambient Recall \u2014 ${t} ${v}`,"// Pushes relevant memory into context automatically. Cross-platform Node hook","// (no shell script \u2014 runs identically on Windows/macOS/Linux). Never blocks","// the agent: every failure path exits 0 with no output (graceful degrade).",`// Runs the hook bundle next to this file (${S}) in this process.`,`process.env.CACHLY_BRAIN_INSTANCE_ID = '${U(o.instanceId)}';`,`process.env.CACHLY_HOOK_EVENT = '${U(t)}';`,`process.argv.splice(2, process.argv.length, '${U(t)}');`,"try {",` await import('./${S}');`,"} catch {"," process.exit(0);","}"].join(`
|
|
2
|
+
`)}function K(){const t=G(rt(import.meta.url));for(const o of[l(t,"..",$,S),l(t,"..","..",$,S)])if(H(o))return o;return null}function pt(t){return C("SessionStart",t)}function lt(t){return C("UserPromptSubmit",t)}function St(t){return C("PreToolUse",t)}function ft(t){return C("Stop",t)}const ht={SessionStart:30,UserPromptSubmit:10,PreToolUse:10,Stop:60},dt="Edit|Write|MultiEdit|NotebookEdit";function J(t,o){const e=(r,i,m)=>({...m?{matcher:m}:{},hooks:[{type:"command",command:`node "${i}"${o?` ${o(r)}`:""}`,timeout:ht[r]}]}),s={SessionStart:[e("SessionStart",t.sessionStart)],UserPromptSubmit:[e("UserPromptSubmit",t.userPromptSubmit)]};return t.preToolUse&&(s.PreToolUse=[e("PreToolUse",t.preToolUse,dt)]),t.stop&&(s.Stop=[e("Stop",t.stop)]),s}const B=".claude/hooks",bt=".claude/settings.json",F={SessionStart:"cachly-ambient-session-start.mjs",UserPromptSubmit:"cachly-ambient-prompt-submit.mjs",PreToolUse:"cachly-ambient-pre-tool.mjs",Stop:"cachly-ambient-stop.mjs"},gt=".claude/hooks/cachly-ambient-";function kt(t,o){const e=t.hooks??[];return e.length>0&&e.every(s=>{const r=s.command??"";return r.replace(/\\/g,"/").includes(gt)||o.has(r)||[...o].some(i=>r.includes(`"${i}"`))})}function Ot(t,o){const e={...t,hooks:{...t.hooks??{}}},s=e.hooks,r=J(o),i=new Set([o.sessionStart,o.userPromptSubmit,o.preToolUse,o.stop].filter(c=>!!c));for(const[c,n]of Object.entries(r)){const u=(Array.isArray(s[c])?s[c]:[]).filter(f=>!kt(f,i));s[c]=[...u,...n]}const m=JSON.stringify(e)!==JSON.stringify(t);return{settings:e,changed:m}}async function to(t,o,e,s={}){const r=l(t,B),i={instanceId:o,apiKey:e},m=["SessionStart","UserPromptSubmit","PreToolUse","Stop"],c={SessionStart:pt(i),UserPromptSubmit:lt(i),PreToolUse:St(i),Stop:ft(i)},n=a=>l(r,F[a]),u=K();if(!u)throw new Error(`cachly hook bundle ${S} missing from the package`);const f=R(u,"utf-8"),d=l(r,S),O=async a=>{try{return await j(a,"utf-8")}catch{return""}},E=l(t,bt),_=H(E);let b={};if(_){const a=await O(E);try{const g=a.charCodeAt(0)===65279?a.slice(1):a,P=g.trim()?JSON.parse(g):{};if(!w(P))throw new k("is not a JSON object");if(P.hooks!==void 0&&!w(P.hooks))throw new k('has a "hooks" field that is not an object');b=P}catch(g){const P=g instanceof k?g.message:/^\s*\/\/|\/\*/m.test(a)?"has comments, and cachly only rewrites plain JSON":"is not valid JSON";return{sessionStartPath:n("SessionStart"),promptSubmitPath:n("UserPromptSubmit"),preToolUsePath:n("PreToolUse"),stopPath:n("Stop"),bundlePath:d,scripts:"unchanged",settings:"skipped",grund:P}}}let p=!1,h=await O(d)===f;for(const a of m){const g=await O(n(a));g&&(p=!0),g!==c[a]+`
|
|
3
|
+
`&&(h=!1)}const D=h?"unchanged":p?"upgraded":"written";if(D!=="unchanged"){await x(r,{recursive:!0}),await T(d,f,"utf-8");for(const a of m)await T(n(a),c[a]+`
|
|
4
|
+
`,"utf-8"),await L(n(a),493).catch(()=>{})}const I=a=>s.portable?`$CLAUDE_PROJECT_DIR/${B}/${F[a]}`:n(a),{settings:ot,changed:et}=Ot(b,{sessionStart:I("SessionStart"),userPromptSubmit:I("UserPromptSubmit"),preToolUse:I("PreToolUse"),stop:I("Stop")});let y;return _?et?y="merged":y="unchanged":y="written",y!=="unchanged"&&(await x(l(t,".claude"),{recursive:!0}),await T(E,JSON.stringify(ot,null,2)+`
|
|
5
|
+
`,"utf-8")),{sessionStartPath:n("SessionStart"),promptSubmitPath:n("UserPromptSubmit"),preToolUsePath:n("PreToolUse"),stopPath:n("Stop"),bundlePath:d,scripts:D,settings:y}}const V=".cursor/hooks",Pt=".cursor/hooks.json",X="cachly-ambient-cursor.mjs",Tt={sessionStart:30,beforeSubmitPrompt:10,postToolUse:5};function N(t,o,e,s){return["#!/usr/bin/env node",`// cachly Ambient Recall \u2014 ${t} ${v}`,`// Einblendung fuer ${t}: ${e.join(", ")}.`,"// Blockiert nie: jeder Fehler endet mit Exit 0. Ruft das Buendel daneben",`// (${S}) in diesem Prozess.`,`process.env.CACHLY_BRAIN_INSTANCE_ID = '${U(s.instanceId)}';`,`process.argv.push('${o}');`,"try {",` await import('./${S}');`,"} catch {"," process.exit(0);","}"].join(`
|
|
6
|
+
`)}function _t(t){return N("Cursor",nt,["sessionStart","beforeSubmitPrompt","postToolUse"],t)}function yt(){const t=o=>[{command:`node ${V}/${X} ${o}`,timeout:Tt[o]}];return{sessionStart:t("sessionStart"),beforeSubmitPrompt:t("beforeSubmitPrompt"),postToolUse:t("postToolUse")}}function Et(t){return z(t,yt())}function z(t,o){const e={...t.hooks??{}};for(const[r,i]of Object.entries(o)){W(e[r],r);const m=(e[r]??[]).filter(c=>!M(c));e[r]=[...m,...i]}const s={...t,version:typeof t.version=="number"?t.version:1,hooks:e};return{datei:s,changed:JSON.stringify(s)!==JSON.stringify(t)}}function Y(t,o){const e={...t.hooks??{}};for(const[r,i]of Object.entries(o)){W(e[r],r);const m=(e[r]??[]).flatMap(c=>{const n=c?.hooks;if(!Array.isArray(n))return[c];const u=n.filter(f=>!M(f));return u.length===n.length?[c]:u.length?[{...c,hooks:u}]:[]});e[r]=[...m,...i]}const s={...t,hooks:e};return{datei:s,changed:JSON.stringify(s)!==JSON.stringify(t)}}async function A(t){const o=l(t.projectDir,t.hookDir),e=K();if(!e)throw new Error(`cachly hook bundle ${S} missing from the package`);const s=R(e,"utf-8"),r=l(o,S),i=l(o,t.skriptName),m=t.skript+`
|
|
7
|
+
`,c=async p=>{try{return await j(p,"utf-8")}catch{return""}},n=l(t.projectDir,t.configDatei),u=H(n)?await c(n):"",f=!u.trim();let d;try{const p=u.charCodeAt(0)===65279?u.slice(1):u,h=f?{}:JSON.parse(p);if(!w(h))throw new k("is not a JSON object");if(h.hooks!==void 0&&!w(h.hooks))throw new k('has a "hooks" field that is not an object');d=t.merge(h,i)}catch(p){const h=p instanceof k?p.message:/^\s*\/\/|\/\*/m.test(u)?"has comments, and cachly only rewrites plain JSON":"is not valid JSON";return{scriptPath:i,bundlePath:r,hooksPath:n,scripts:"unchanged",hooks:"skipped",grund:h}}await x(o,{recursive:!0});const O=await c(i),_=O===m&&await c(r)===s?"unchanged":O?"upgraded":"written";_!=="unchanged"&&(await T(r,s,"utf-8"),await T(i,m,"utf-8"),await L(i,493).catch(()=>{}));let b;if(f?b="written":d.changed?b="merged":b="unchanged",b!=="unchanged"){const p=/^([ \t]+)"/m.exec(u)?.[1]??2;await x(G(n),{recursive:!0}),await T(n,JSON.stringify(d.datei,null,p)+`
|
|
8
|
+
`,"utf-8")}return{scriptPath:i,bundlePath:r,hooksPath:n,scripts:_,hooks:b}}function w(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}class k extends Error{}function W(t,o){if(t!==void 0&&!Array.isArray(t))throw new k(`has a "hooks.${o}" entry that is not a list`)}async function oo(t,o){return A({projectDir:t,hookDir:V,skriptName:X,skript:_t({instanceId:o}),configDatei:Pt,merge:e=>Et(e)})}const Q=".github/hooks",It=".github/hooks/cachly-ambient.json",Z="cachly-ambient-copilot.mjs",xt={sessionStart:30,userPromptSubmitted:10,postToolUse:5};function Ut(t){return N("VS Code / Copilot",st,it,t)}function Ct(){const t=o=>[{type:"command",command:`node ${Q}/${Z} ${o}`,cwd:".",timeoutSec:xt[o]}];return{sessionStart:t("sessionStart"),userPromptSubmitted:t("userPromptSubmitted"),postToolUse:t("postToolUse")}}function Nt(t){return z(t,Ct())}async function eo(t,o){return A({projectDir:t,hookDir:Q,skriptName:Z,skript:Ut({instanceId:o}),configDatei:It,merge:e=>Nt(e)})}const At=".codex/hooks",wt=".codex/hooks.json",Ht="cachly-ambient-codex.mjs",$t={SessionStart:30,UserPromptSubmit:10};function Dt(t){return N("Codex",ct,at,t)}function Rt(t){const o=e=>[{hooks:[{type:"command",command:`node "${t}" ${e}`,timeout:$t[e]}]}];return{SessionStart:o("SessionStart"),UserPromptSubmit:o("UserPromptSubmit")}}function jt(t,o){return Y(t,Rt(o))}async function ro(t,o){return A({projectDir:t,hookDir:At,skriptName:Ht,skript:Dt({instanceId:o}),configDatei:wt,merge:(e,s)=>jt(e,s)})}const q=".gemini/hooks",Lt=".gemini/settings.json",tt="cachly-ambient-gemini.mjs",Gt={SessionStart:3e4,BeforeAgent:1e4},Mt={SessionStart:"cachly-briefing",BeforeAgent:"cachly-recall"};function vt(t){return N("Gemini CLI",ut,mt,t)}function Kt(){const t=o=>[{hooks:[{name:Mt[o],type:"command",command:`node ${q}/${tt} ${o}`,timeout:Gt[o]}]}];return{SessionStart:t("SessionStart"),BeforeAgent:t("BeforeAgent")}}function Jt(t){return Y(t,Kt())}async function no(t,o){return A({projectDir:t,hookDir:q,skriptName:tt,skript:vt({instanceId:o}),configDatei:Lt,merge:e=>Jt(e)})}const so=["SessionStart","UserPromptSubmit","Stop"],$="hooks";function io(){const t=`\${CLAUDE_PLUGIN_ROOT}/${$}/${S}`,o=J({sessionStart:t,userPromptSubmit:t,stop:t},e=>`${e} --plugin`);return JSON.stringify({hooks:o},null,2)+`
|
|
9
|
+
`}export{qt as AMBIENT_CLI_SUBCOMMAND,v as AMBIENT_HOOK_VERSION,B as CLAUDE_HOOK_DIR,bt as CLAUDE_SETTINGS_DATEI,wt as CODEX_HOOKS_DATEI,At as CODEX_HOOK_DIR,Ht as CODEX_SKRIPT,$t as CODEX_TIMEOUTS,It as COPILOT_HOOKS_DATEI,Q as COPILOT_HOOK_DIR,Z as COPILOT_SKRIPT,xt as COPILOT_TIMEOUTS,Pt as CURSOR_HOOKS_DATEI,V as CURSOR_HOOK_DIR,X as CURSOR_SKRIPT,Tt as CURSOR_TIMEOUTS,q as GEMINI_HOOK_DIR,Lt as GEMINI_SETTINGS_DATEI,tt as GEMINI_SKRIPT,Gt as GEMINI_TIMEOUTS_MS,S as HOOK_BUENDEL,$ as PLUGIN_HOOK_DIR,so as PLUGIN_HOOK_EVENTS,dt as PRE_TOOL_USE_MATCHER,J as buildAmbientSettingsHooks,Dt as buildCodexHook,Rt as buildCodexHooks,Ut as buildCopilotHook,Ct as buildCopilotHooks,_t as buildCursorHook,yt as buildCursorHooks,vt as buildGeminiHook,Kt as buildGeminiHooks,io as buildPluginHooksJson,St as buildPreToolUseHook,pt as buildSessionStartHook,ft as buildStopHook,lt as buildUserPromptSubmitHook,K as hookBuendelQuelle,to as installAmbientHooks,ro as installCodexHooks,eo as installCopilotHooks,oo as installCursorHooks,no as installGeminiHooks,Ot as mergeAmbientSettings,jt as mergeCodexHooks,Nt as mergeCopilotHooks,Et as mergeCursorHooks,Jt as mergeGeminiHooks};
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import{existsSync as
|
|
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()+`
|
|
1
|
+
import{existsSync as c}from"node:fs";import{readFile as u,writeFile as f}from"node:fs/promises";import{resolve as a}from"node:path";import{installClsPostCommitHook as h}from"./cls-hook.js";import{instanzIdFuerSkript as m}from"./git-ohne-shell.js";const s=/(?:#!\/bin\/sh\n)?# cachly brain_watch[\s\S]*?\nexit 0\n?/;function p(r){if(!s.test(r))return null;let t=r;for(let n=s.exec(t);n;n=s.exec(t)){const o=t.slice(0,n.index).replace(/\s+$/,""),i=t.slice(n.index+n[0].length).replace(/^\s*\n/,"");t=o+(o&&i.trim()?`
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`)}
|
|
3
|
+
`:"")+i}const e=t.trim();return e===""||e.startsWith("#!")&&!e.includes(`
|
|
4
|
+
`)?"":t.replace(/\s+$/,"")+`
|
|
5
|
+
`}async function w(r,t){if(m(t),!c(a(r,".git")))return{result:"skipped-no-git",hookPath:"",alterBlockEntfernt:!1};const e=a(r,".git","hooks","post-commit");let n="";try{n=await u(e,"utf-8")}catch{}const o=p(n);o!==null&&await f(e,o,"utf-8");const i=await h(r,t),l=o!==null;return{result:l&&i==="unchanged"?"upgraded":i,hookPath:e,alterBlockEntfernt:l}}export{s as BRAIN_WATCH_BLOCK_RE,w as installBrainWatchHook,p as ohneBrainWatchBlock};
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import{createHmac as he}from"node:crypto";import{ckgSlug as b,extractProblemConcept as me,ckgUpsertNode as T,ckgUpdateEdge as
|
|
2
|
-
`);const i=[{name:"InfraAgent",domains:["infra","k8s","docker","server","wireguard","helm"]},{name:"AuthAgent",domains:["auth","jwt","keycloak","oauth","oidc","token"]},{name:"DeployAgent",domains:["deploy","ci","pipeline","rsync","release"]},{name:"DatabaseAgent",domains:["db","gorm","migration","postgres","clickhouse","redis"]},{name:"DebugAgent",domains:["debug","panic","race","nil","fix","error"]},{name:"APIAgent",domains:["api","http","grpc","rest","fiber","web"]}],
|
|
3
|
-
`);const o=[];for(const _ of
|
|
4
|
-
`)}case"cls_ingest":{const{instance_id:w,source:c,payload:d}=
|
|
5
|
-
`)}if(c==="ci_outcome"){const
|
|
6
|
-
`)}if(c==="ide_diagnostic"){const
|
|
7
|
-
`)}return`\u274C Unknown CLS source: "${c}". Valid: git_commit, ci_outcome, ide_diagnostic`}case"cls_install_hooks":{const{instance_id:w,repo_path:c=".",hooks:d=["git","ci"]}=
|
|
8
|
-
`];if(be(w),s.includes("git")){const i=we(w),
|
|
9
|
-
`)}case"fedbrain_contribute":{const{instance_id:w,lesson_key:c,visibility:d="public"}=
|
|
10
|
-
`)}case"fedbrain_search":{const{instance_id:w,query:c,context_hints:d=[],limit:s=10}=
|
|
11
|
-
`);const a=r.map(o=>{const n=(o.domain_fingerprint??o.category??"").split(",").filter(Boolean),h=n.reduce((g,x)=>g+(
|
|
12
|
-
`];for(const o of a){const n=o.outcome==="success"?"\u2705":o.outcome==="failure"?"\u274C":"\u26A0\uFE0F",h=o.isGoldStandard?" \u{1F3C6} _Gold Standard_":!
|
|
13
|
-
`)}case"fedbrain_confirm":{const{instance_id:w,id:c,topic:d,outcome:s}=
|
|
14
|
-
`);const e=await A(w),i=new Date().toISOString(),
|
|
15
|
-
`)}case"fedbrain_status":{const{instance_id:w}=
|
|
16
|
-
`,`### \u{1F4E4} Contributed Lessons: ${d.length}`];if(
|
|
17
|
-
`)}case"brain_federate":{const{instance_id:w,source:c,domain:d,min_confidence:s=.6,dry_run:e=!1}=
|
|
18
|
-
`);let a=0,t=0,o=0,n=0,h=0,m=0;const p=[];for(const x of
|
|
19
|
-
`)}case"crystal_view":{const{instance_id:w,show_raw:c=!1}=
|
|
20
|
-
`);const e=R(s,null);if(!e)return"\u274C Memory Crystal data is corrupted. Re-create with `memory_crystalize()`.";const i=Math.floor((Date.now()-new Date(e.ts).getTime())/864e5),
|
|
21
|
-
`)}case"compact_recover":{const{instance_id:w,focus:c=""}=
|
|
1
|
+
import{createHmac as he}from"node:crypto";import{ckgSlug as b,extractProblemConcept as me,ckgUpsertNode as T,ckgUpdateEdge as J,ckgUpsertPersonNode as pe,ckgUpsertFileNode as ge,ckgRecordCollaboration as _e}from"../ckg.js";import{safeJsonParse as R}from"../utils.js";import{buildClsPostCommitHook as we}from"../cls-hook.js";import{alsShellWort as ye,beginntMitBindestrich as $e,gitLesen as ie,instanzIdFuerSkript as be,istCommitHash as ke,pruefeOrdner as Se}from"../git-ohne-shell.js";import{installBrainWatchHook as Ce}from"../brain-watch-hook.js";import{keywordSearch as xe,wortindexEntwerten as ve}from"../search.js";import{buildFirstContactReport as ae,suggestRecallQueries as je}from"../first-contact.js";import{commitAlsLektion as Oe,gitLogArgumente as Ne,leseCommits as Ie}from"../git-lektionen.js";import{VEKTOR_NACHTRAG as Ae}from"../bedeutung.js";import{VERDACHT_TAG as Le,fuerEigenenSpeicher as G,fuerWeitergabe as re,hinweise as V,istMarkiert as Re,markiert as K,weitergabeHinweis as ce,zaehlHinweise as H}from"../schreibtor.js";let De=null,Te=null,Y=0;const Je=10,le=[];function Me(){return Y<Je?(Y++,Promise.resolve()):new Promise(B=>le.push(B))}function Pe(){const B=le.shift();B?B():Y--}const Qe=new Set(["madc_deliberate","cls_ingest","cls_install_hooks","fedbrain_contribute","fedbrain_search","fedbrain_confirm","fedbrain_status","brain_federate","crystal_view","compact_recover","brain_from_git","brain_from_ci","brain_predict_failures","brain_contribute_signal","brain_import_meta","brain_watch"]);async function Xe(B,N,A,E){switch(B){case"madc_deliberate":{const{instance_id:w,topic:c}=N,d=await A(w),e=(await d.lrange(`cachly:lessons:${c}`,0,-1)).map(_=>{try{return JSON.parse(_)}catch{return null}}).filter(Boolean);if(e.length<2)return[`\u{1F5F3}\uFE0F **MADC: "${c}"**`,"",`Not enough history for deliberation (need \u2265 2 entries, found ${e.length}).`,"","Call `learn_from_attempts` with conflicting outcomes to trigger deliberation."].join(`
|
|
2
|
+
`);const i=[{name:"InfraAgent",domains:["infra","k8s","docker","server","wireguard","helm"]},{name:"AuthAgent",domains:["auth","jwt","keycloak","oauth","oidc","token"]},{name:"DeployAgent",domains:["deploy","ci","pipeline","rsync","release"]},{name:"DatabaseAgent",domains:["db","gorm","migration","postgres","clickhouse","redis"]},{name:"DebugAgent",domains:["debug","panic","race","nil","fix","error"]},{name:"APIAgent",domains:["api","http","grpc","rest","fiber","web"]}],f=c.split(":")[0]??"",r=i.filter(_=>_.domains.some($=>f===$||c.includes($))),u=r.length>0?r:i,l=new Map;for(const _ of u){let $=0;for(const v of _.domains){const j=[],S=d.scanStream({match:`cachly:ckg:node:${v}*`,count:50});await new Promise((k,O)=>{S.on("data",M=>j.push(...M)),S.on("end",k),S.on("error",O)}),$+=j.length}l.set(_.name,$)}const a=e.filter(_=>_.outcome==="success"||_.outcome==="partial"),t=e.filter(_=>_.outcome==="failure");if(t.length===0)return[`\u{1F5F3}\uFE0F **MADC: "${c}"**`,"",`No contradictions found \u2014 all ${a.length} entries have non-failure outcomes.`,"",`Use \`ckg_inspect(concept="${b(c)}")\` to explore the confidence graph.`].join(`
|
|
3
|
+
`);const o=[];for(const _ of u){const $=l.get(_.name)??0;let v,j;$<2?(v="abstain",j="insufficient domain coverage"):a.length>=t.length*2?(v="success",j=`${a.length}/${e.length} entries confirm success`):t.length>=a.length*2?(v="failure",j=`${t.length}/${e.length} entries confirm failure`):(v="abstain",j=`contested (${a.length} success vs ${t.length} failure)`),o.push({agent:_.name,vote:v,coverage:$,reason:j})}const n=o.filter(_=>_.vote==="success").length,h=o.filter(_=>_.vote==="failure").length,m=o.filter(_=>_.vote==="abstain").length;let p,y;n>0&&h===0?(p="unanimous_success",y=`\u2705 **Unanimous: SUCCESS** \u2014 ${n} agent(s) confirm, ${m} abstain`):h>0&&n===0?(p="unanimous_failure",y=`\u274C **Unanimous: FAILURE** \u2014 ${h} agent(s) confirm, ${m} abstain`):(p="contested",y=`\u26A0\uFE0F **CONTESTED** \u2014 ${n} success votes, ${h} failure votes, ${m} abstain`);const g=b(`resolution:${c}`),x={id:g,domain:"resolution",type:"resolution",count:1,ts:new Date().toISOString(),resolution:p,topic:c,votes:{success:n,failure:h,abstain:m}};if(await d.set(`cachly:ckg:node:${g}`,JSON.stringify(x)),p==="contested")await J(d,b(c),"contradicts",g,!1);else{if(((p==="unanimous_success"?"failure":"success")==="failure"?t:a).length>0){const v=await d.smembers(`cachly:ckg:idx:from:${b(c)}`);for(const j of v){const S=await d.get(j);if(S)try{const k=JSON.parse(S);k.edgeType==="fixes"&&k.confidence>.15&&p==="unanimous_failure"&&(k.confidence=.1,k.last_updated=new Date().toISOString(),await d.set(j,JSON.stringify(k)))}catch{}}}await d.del(`cachly:ckg:conflict:${b(c)}`)}const C=[`\u{1F5F3}\uFE0F **MADC Deliberation: "${c}"**`,"",`\u{1F4CA} Evidence: ${a.length} success/partial vs ${t.length} failure entries (${e.length} total)`,"",`**Voting agents (${u.length}):**`,...o.map(_=>{const $=_.vote==="success"?"\u2705":_.vote==="failure"?"\u274C":"\u2B1C",v="\u2593".repeat(Math.min(_.coverage,5))+"\u2591".repeat(Math.max(0,5-_.coverage));return` ${$} **${_.agent}** [${v}] ${_.coverage} CKG edges \u2014 ${_.reason}`}),"",y,""];return p==="unanimous_success"?C.push(`\u{1F527} Failure entries superseded \u2014 store confirmed lesson: \`learn_from_attempts(topic="${c}", outcome="success", ...)\``):p==="unanimous_failure"?C.push(`\u{1F6AB} Success claims unconfirmed \u2014 re-verify: \`recall_best_solution(topic="${c}")\``):C.push(`\u26A0\uFE0F Contested \u2014 run \`causal_trace\` before acting. Explore: \`ckg_inspect(concept="${b(c)}")\``),C.push("",`\u{1F4DD} Resolution node: \`cachly:ckg:node:${g}\``),C.join(`
|
|
4
|
+
`)}case"cls_ingest":{const{instance_id:w,source:c,payload:d}=N,s=G(d),e=s.felder,i=await A(w),f=new Date().toISOString(),r="cachly:cls:events";if(c==="git_commit"){const u=String(e.message??""),l=String(e.sha??""),a=Array.isArray(e.files)?e.files:[],t=/^fix/i.test(u)?"fix":/^feat/i.test(u)?"feat":/^refactor/i.test(u)?"refactor":/^test/i.test(u)?"test":"commit",o=`${t}:${b(u.slice(0,60))}`,n=b(o);await T(i,n,t,"commit");for(const p of a.slice(0,10)){const y=p.includes("auth")?"auth":p.includes("api")?"api":p.includes("infra")?"infra":p.includes("web")?"web":"code",g=b(`file:${y}`);await T(i,g,"file",y),await J(i,n,"co-occurs",g,!0)}const h={topic:o,outcome:"success",what_worked:u,what_failed:"",context:`CLS/git: sha=${l}`,severity:"minor",file_paths:a.slice(0,10),commands:l?[`git show ${l}`]:[],tags:K(["cls","git"],s.verdacht),depends_on:[],recall_count:0,ts:f,verified_at:f,confidence:.6,audit_trail:[{ts:f,action:"cls_git_commit"}],version:3};return await i.rpush(`cachly:lessons:${o}`,JSON.stringify(h)),await i.get(`cachly:lesson:best:${o}`)||await i.set(`cachly:lesson:best:${o}`,JSON.stringify(h)),await i.rpush(r,JSON.stringify({source:c,payload:{message:u,sha:l},ts:f})),await i.ltrim(r,-200,-1),["\u{1F4E8} **CLS Ingested: git_commit**","",`Commit \`${l.slice(0,8)||"?"}\`: ${u.slice(0,80)}`,`Concept: \`${n}\` (${t}) \xB7 Files: ${a.length}`,"",`\u{1F578}\uFE0F CKG: \`${n}\` + ${a.length} file edges \xB7 Lesson: \`${o}\``,`\u{1F4A1} Inspect: \`ckg_inspect(concept="${t}")\``,...V(s)].join(`
|
|
5
|
+
`)}if(c==="ci_outcome"){const u=String(e.status??""),l=String(e.prev_status??""),a=String(e.job??"unknown"),t=String(e.context??""),o=["failure","red","error"].includes(l)&&["success","green","passed"].includes(u),n=["success","green","passed"].includes(l)&&["failure","red","error"].includes(u),h=`ci:${b(a)}`,m=b(h);if(await T(i,m,"ci","job"),o){const y=b(`problem:${b(a)}`);await T(i,y,"problem","ci-failure"),await J(i,m,"fixes",y,!0);const g={topic:h,outcome:"success",what_worked:`CI job "${a}" went ${l} \u2192 ${u}`,what_failed:`Job "${a}" was failing`,context:`CLS/ci: ${t}`,severity:"major",file_paths:[],commands:[],tags:K(["cls","ci"],s.verdacht),depends_on:[],recall_count:0,ts:f,verified_at:f,confidence:.75,audit_trail:[{ts:f,action:"cls_ci_fixed"}],version:3};await i.rpush(`cachly:lessons:${h}`,JSON.stringify(g)),await i.set(`cachly:lesson:best:${h}`,JSON.stringify(g))}else if(n){const y=b(`cause:${b(a)}`);await T(i,y,"cause","ci-break"),await J(i,m,"causes",y,!1)}return await i.rpush(r,JSON.stringify({source:c,payload:{status:u,prev_status:l,job:a},ts:f})),await i.ltrim(r,-200,-1),["\u{1F4E8} **CLS Ingested: ci_outcome**","",`${o?"\u2705 Fixed":n?"\u{1F534} Broken":"\u{1F4CA} Recorded"}: \`${a}\` \u2014 ${l||"?"} \u2192 ${u}`,o?"\u{1F527} CKG `fixes` edge added (75% confidence)":n?"\u26A1 CKG `causes` edge added":"\u{1F4CA} State recorded",`\u{1F4A1} Lesson: \`${h}\` | Predict: \`brain_predict(context="${a}")\``,...V(o?s:{geschwaerzt:s.geschwaerzt,verdacht:[]})].join(`
|
|
6
|
+
`)}if(c==="ide_diagnostic"){const u=String(e.error??""),l=String(e.fix??""),a=String(e.file??""),t=me(u)??"unknown-error",o=`debug:${b(t)}`,n=b(o),h=b(`problem:${t}`);await T(i,n,"debug","diagnostic"),await T(i,h,"problem","compiler-error"),await J(i,n,"fixes",h,!0);const m={topic:o,outcome:"success",what_worked:l,what_failed:u,context:`CLS/ide: ${a}`,severity:"minor",file_paths:a?[a]:[],commands:[],tags:K(["cls","ide-diagnostic"],s.verdacht),depends_on:[],recall_count:0,ts:f,verified_at:f,confidence:.65,audit_trail:[{ts:f,action:"cls_ide_diagnostic"}],version:3};return await i.rpush(`cachly:lessons:${o}`,JSON.stringify(m)),await i.get(`cachly:lesson:best:${o}`)||await i.set(`cachly:lesson:best:${o}`,JSON.stringify(m)),await i.rpush(r,JSON.stringify({source:c,payload:{error:u.slice(0,60),fix:l.slice(0,60),file:a},ts:f})),await i.ltrim(r,-200,-1),["\u{1F4E8} **CLS Ingested: ide_diagnostic**","",`Error: \`${u.slice(0,80)}\``,`Fix: ${l.slice(0,100)}`,a?`File: \`${a}\``:"","",`\u{1F578}\uFE0F CKG: \`${n}\` \u2192 fixes \u2192 \`${h}\` | Lesson: \`${o}\``,...V(s)].filter(y=>y!=="").join(`
|
|
7
|
+
`)}return`\u274C Unknown CLS source: "${c}". Valid: git_commit, ci_outcome, ide_diagnostic`}case"cls_install_hooks":{const{instance_id:w,repo_path:c=".",hooks:d=["git","ci"]}=N,s=Array.isArray(d)?d:["git","ci"],e=[`\u{1F50C} **CLS Hook Installation Guide**
|
|
8
|
+
`];if(be(w),s.includes("git")){const i=we(w),f=ye(`${c}/.git/hooks/post-commit`);e.push("### Git post-commit hook"),e.push("**Quick install (run once per repo):**"),e.push("```sh"),e.push(`touch ${f}`),e.push(`grep -q 'cachly CLS' ${f} || cat >> ${f} << 'HOOK'`),e.push(i),e.push("HOOK"),e.push(`chmod +x ${f}`),e.push("```"),e.push("After install: every `git commit` automatically updates your brain's CKG."),e.push("")}return s.includes("ci")&&(e.push("### GitHub Actions CI outcome hook"),e.push("**Add at the end of each job** (after build/test steps):"),e.push("```yaml"),e.push("- name: cachly CLS \u2014 record CI outcome"),e.push(" if: always()"),e.push(" run: |"),e.push(' node -e "'),e.push(" const r=require('https');"),e.push(` const d=JSON.stringify({instance_id:'${w}',source:'ci_outcome',payload:{`),e.push(" status:'${{ job.status }}',prev_status:'unknown',job:'${{ github.job }}',"),e.push(" context:'github-actions run ${{ github.run_number }}'}});"),e.push(" r.request({hostname:'api.cachly.dev',path:'/api/v1/cls/ingest',method:'POST',"),e.push(" headers:{'Content-Type':'application/json','Authorization':'Bearer $CACHLY_JWT',"),e.push(" 'Content-Length':d.length}},()=>{}).end(d);"),e.push(' " 2>/dev/null || true'),e.push(" env:"),e.push(" CACHLY_JWT: ${{ secrets.CACHLY_JWT }}"),e.push("```"),e.push("")),e.push('\u{1F4A1} Once installed: `brain_search(query="cls")` to verify events are arriving.'),e.push('\u{1F4CA} Monitor CKG growth: `ckg_inspect(concept="ci")` or `ckg_inspect(concept="fix")`'),e.join(`
|
|
9
|
+
`)}case"fedbrain_contribute":{const{instance_id:w,lesson_key:c,visibility:d="public"}=N,s=await A(w),e=await s.get(`cachly:lesson:best:${c}`);if(!e)return`\u274C Lesson \`${c}\` not found. Store it first with \`learn_from_attempts\`.`;const i=R(e,null);if(!i)return`\u274C Lesson \`${c}\` data is corrupted. Re-store with \`learn_from_attempts\`.`;const f=re({topic:i.topic,what_worked:i.what_worked,what_failed:i.what_failed??"",tags:i.tags??[]},"die Commons");if(!f.ok)return f.meldung;if(Re(i))return`\u26D4 Tuersteher: Die Lektion \`${c}\` ist beim Speichern als verdaechtig markiert worden \u2014 NICHT an die Commons weitergegeben. Nichts wurde gesendet. Inhalt pruefen, dann mit \`learn_from_attempts\` ohne die Anweisung neu speichern.`;const r={...i,...f.felder},u=[r.topic.split(":")[0],...r.tags??[]].filter(Boolean),l=[...new Set(u)].sort().join(","),a=`${r.topic}:${r.outcome}:${r.what_worked}`,t=he("sha256",`cachly-fedbrain:${w}`).update(a).digest("hex").slice(0,16),o={cert_id:t,lesson_key:c,visibility:d,domain_fingerprint:l,contributed_at:new Date().toISOString(),confirm_count:0,trust_score:r.outcome==="success"?.85:.5};await s.set(`cachly:fedbrain:cert:${t}`,JSON.stringify(o)),await s.sadd("cachly:fedbrain:contributed",t);let n;try{await E("/api/v1/syndication/contribute",{method:"POST",body:JSON.stringify({topic:r.topic,outcome:r.outcome,what_worked:r.what_worked,what_failed:r.what_failed??"",severity:r.severity??"major",cert_id:t,domain_fingerprint:l,visibility:d})}),n="\u2705 Contributed to global commons"}catch{n="\u{1F4E6} Stored locally (commons API unavailable \u2014 will sync when online)"}return[`\u{1F310} **FedBrain Contribute: "${c}"**`,"",`\u{1F4DC} Certificate: \`${t}\``,`\u{1F3F7}\uFE0F Domain fingerprint: ${u.slice(0,6).map(h=>`\`${h}\``).join(", ")}`,`\u{1F512} Visibility: ${d}`,"",n,...f.geschwaerzt.length?[ce(f.geschwaerzt)]:[],"","\u{1F4A1} At 10 independent confirms \u2192 \u{1F3C6} Gold Standard",`\u{1F50D} Search: \`fedbrain_search(query="${r.topic.split(":").slice(-1)[0]}")\``].join(`
|
|
10
|
+
`)}case"fedbrain_search":{const{instance_id:w,query:c,context_hints:d=[],limit:s=10}=N,e=await A(w),i=await e.smembers("cachly:fedbrain:contributed"),f=new Map;for(const o of i.slice(0,30)){const n=await e.get(`cachly:fedbrain:cert:${o}`);if(n)try{const h=JSON.parse(n);for(const m of(h.domain_fingerprint??"").split(",").filter(Boolean))f.set(m,(f.get(m)??0)+1)}catch{}}for(const o of Array.isArray(d)?d:[])f.set(o.toLowerCase(),(f.get(o.toLowerCase())??0)+2);let r=[],u=!1;try{const o=new URLSearchParams({q:c,limit:String(Math.min(s*2,50))});r=(await E(`/api/v1/syndication/search?${o}`)).results??[]}catch{u=!0;const o=[],n=e.scanStream({match:"cachly:lesson:best:*",count:200});await new Promise((h,m)=>{n.on("data",p=>o.push(...p)),n.on("end",h),n.on("error",m)});for(const h of o.slice(0,60)){const m=await e.get(h);if(m)try{const p=JSON.parse(m),y=`${p.topic} ${p.what_worked??""} ${p.what_failed??""}`.toLowerCase();c.toLowerCase().split(/\s+/).some(g=>g.length>2&&y.includes(g))&&r.push({id:h.split(":").pop()??h,topic:p.topic,category:p.topic.split(":")[0],outcome:p.outcome,what_worked:p.what_worked??"",severity:p.severity??"major",confirm_count:0,created_at:p.ts??new Date().toISOString()})}catch{}}}const l=u?" \u2014 \u26A0\uFE0F Commons unreachable, local fallback (this machine only, not confirmed by the network)":"";if(r.length===0)return[`\u{1F310} **FedBrain Search: "${c}"**${l}`,"",'No results. Contribute: `fedbrain_contribute(lesson_key="fix:...")`'].join(`
|
|
11
|
+
`);const a=r.map(o=>{const n=(o.domain_fingerprint??o.category??"").split(",").filter(Boolean),h=n.reduce((g,x)=>g+(f.get(x)??0),0),m=f.size>0?h/Math.max(1,f.size+n.length):0,p=Math.min(1,o.confirm_count/10),y=m*.4+p*.4+(o.outcome==="success"?.2:0);return{...o,weightedScore:y,isGoldStandard:!u&&o.confirm_count>=10}}).sort((o,n)=>n.weightedScore-o.weightedScore).slice(0,s),t=[`\u{1F310} **FedBrain Search: "${c}"** \u2014 ${a.length} result${a.length!==1?"s":""} (context-weighted)${l}
|
|
12
|
+
`];for(const o of a){const n=o.outcome==="success"?"\u2705":o.outcome==="failure"?"\u274C":"\u26A0\uFE0F",h=o.isGoldStandard?" \u{1F3C6} _Gold Standard_":!u&&o.confirm_count>=3?` \u2713${o.confirm_count}`:"",m=Math.round(o.weightedScore*100);t.push(`${n}${h} **\`${o.topic}\`** [ctx: ${m}%]`),o.what_worked&&t.push(` \u2705 ${o.what_worked.slice(0,150)}`),o.what_failed&&t.push(` \u274C ${o.what_failed.slice(0,80)}`),t.push(` _${o.confirm_count} confirm${o.confirm_count!==1?"s":""} | id: \`${o.id}\`_`,"")}if(f.size>0){const o=[...f.entries()].sort((n,h)=>h[1]-n[1]).slice(0,5).map(([n,h])=>`\`${n}\`(${h})`).join(", ");t.push(`\u{1F3AF} Your context: ${o}`)}return t.push('\u{1F4A1} Confirm a result: `fedbrain_confirm(id="<id>", topic="<topic>", outcome="worked")`'),t.join(`
|
|
13
|
+
`)}case"fedbrain_confirm":{const{instance_id:w,id:c,topic:d,outcome:s}=N;if(!c)return["\u274C **FedBrain Confirm** needs the lesson `id` from `fedbrain_search` results.",'Run `fedbrain_search(query="...")`, copy the id shown next to a result,','then: `fedbrain_confirm(id="<id>", topic="<topic>", outcome="worked")`.'].join(`
|
|
14
|
+
`);const e=await A(w),i=new Date().toISOString(),f=JSON.stringify({id:c,topic:d,outcome:s,ts:i});await e.rpush("cachly:fedbrain:confirmations",f),await e.ltrim("cachly:fedbrain:confirmations",-200,-1);const r=s==="worked",u=s==="partially_worked";d&&await J(e,b(d),"fixes",b(`syndicated:${d}`),r,u);let l;try{await E(`/api/v1/syndication/${encodeURIComponent(c)}/confirm`,{method:"POST"}),l="\u2705 Confirmation propagated to global commons"}catch{await e.rpush("cachly:fedbrain:pending_confirms",f),await e.ltrim("cachly:fedbrain:pending_confirms",-50,-1),l="\u{1F4E6} Queued locally (API unavailable \u2014 will propagate on next online session)"}return[`${r?"\u2705":u?"\u26A0\uFE0F":"\u274C"} **FedBrain Confirm: "${d??c}"** \u2192 ${s}`,"",l,"",d?`\u{1F578}\uFE0F CKG confidence ${r||u?"boosted":"reduced"} for \`${b(d)}\``:"\u{1F578}\uFE0F Local CKG unchanged (pass `topic` to also update your own confidence graph)","\u{1F4A1} Your confirmation helps other brains worldwide.",'\u{1F4CA} Status: `fedbrain_status(instance_id="...")`'].join(`
|
|
15
|
+
`)}case"fedbrain_status":{const{instance_id:w}=N,c=await A(w),d=await c.smembers("cachly:fedbrain:contributed"),s=await c.lrange("cachly:fedbrain:confirmations",-10,-1),e=await c.llen("cachly:fedbrain:pending_confirms"),i=s.map(u=>{try{return JSON.parse(u)}catch{return null}}).filter(Boolean),f=[];for(const u of d.slice(0,15)){const l=await c.get(`cachly:fedbrain:cert:${u}`);if(l)try{const a=JSON.parse(l);f.push({cert_id:a.cert_id,lesson_key:a.lesson_key,confirm_count:a.confirm_count??0,trust_score:a.trust_score??.5,isGold:(a.confirm_count??0)>=10})}catch{}}const r=[`\u{1F310} **FedBrain Status**
|
|
16
|
+
`,`### \u{1F4E4} Contributed Lessons: ${d.length}`];if(f.length>0)for(const u of f){const l=u.isGold?" \u{1F3C6} Gold Standard":"",a="\u2588".repeat(Math.min(10,u.confirm_count))+"\u2591".repeat(Math.max(0,10-u.confirm_count));r.push(` \`${u.lesson_key}\` [${a}] \xD7${u.confirm_count}${l}`)}else r.push(' _None yet. Contribute with `fedbrain_contribute(lesson_key="fix:...")`_');if(r.push("",`### \u{1F4E5} Recent Confirmations: ${i.length}`),i.length>0)for(const u of i.slice(-5)){const l=u.outcome==="worked"?"\u2705":u.outcome==="partially_worked"?"\u26A0\uFE0F":"\u274C";r.push(` ${l} \`${u.topic}\` \u2014 ${u.outcome} (${new Date(u.ts).toLocaleDateString("de-DE")})`)}else r.push(" _None yet. Confirm syndicated lessons with `fedbrain_confirm`_");return e>0&&r.push("",`\u26A0\uFE0F ${e} confirmation${e!==1?"s":""} pending propagation`),r.push("","---",'**Contribute:** `fedbrain_contribute(lesson_key="fix:...")`','**Search:** `fedbrain_search(query="...")`','**Confirm:** `fedbrain_confirm(id="...", topic="...", outcome="worked")`'),r.join(`
|
|
17
|
+
`)}case"brain_federate":{const{instance_id:w,source:c,domain:d,min_confidence:s=.6,dry_run:e=!1}=N;if(w===c)return"\u274C Source and destination cannot be the same brain.";const i=await A(w),f=await A(c),r=d==="*"?"cachly:ckg:node:*":`cachly:ckg:node:${d}*`,u=[],l=f.scanStream({match:r,count:100});if(await new Promise((x,C)=>{l.on("data",_=>u.push(..._)),l.on("end",x),l.on("error",C)}),u.length===0)return[`\u{1F9E0} **brain_federate: "${d}"**`,"",`No CKG nodes found in source brain for domain \`${d}\`.`,"The source brain may not have knowledge in this area yet.",`Try: \`fedbrain_search(query="${d}")\` to find global commons knowledge instead.`].join(`
|
|
18
|
+
`);let a=0,t=0,o=0,n=0,h=0,m=0;const p=[];for(const x of u){const C=await f.get(x);if(!C)continue;let _;try{_=JSON.parse(C)}catch{continue}e||await i.set(x,C),a++;const $=await f.smembers(`cachly:ckg:idx:from:${_.id}`);for(const S of $){const k=await f.get(S);if(!k)continue;let O;try{O=JSON.parse(k)}catch{continue}if(O.confidence<s){n++;continue}e||(await i.set(S,k),await i.sadd(`cachly:ckg:idx:from:${O.from}`,S),await i.sadd(`cachly:ckg:idx:to:${O.to}`,S)),t++}const v=`cachly:lesson:best:${_.id}`,j=await f.get(v);if(j){const S=R(j,null);if(!S||typeof S!="object")continue;const k=G(S);k.geschwaerzt.length&&h++,k.verdacht.length&&m++;const O=k.verdacht.length?{...k.felder,tags:K(k.felder.tags,k.verdacht)}:k.felder;if(e||await i.set(v,JSON.stringify(O)),o++,p.length<8){const M=O.outcome==="success"?"\u2705":O.outcome==="failure"?"\u274C":"\u26A0\uFE0F";p.push(` ${M} \`${O.topic}\` \u2014 ${(O.what_worked??"").slice(0,80)}`)}}}if(!e){const x=JSON.stringify({source:c,domain:d,transferred_at:new Date().toISOString(),nodes:a,edges:t,lessons:o});await i.rpush("cachly:fedbrain:federations",x),await i.ltrim("cachly:fedbrain:federations",-50,-1)}const g=[`\u{1F9E0} **brain_federate: "${d}"**${e?" (DRY RUN \u2014 no writes)":""}`,"",`\u{1F4E4} Source: \`${c}\``,`\u{1F4E5} Destination: \`${w}\``,`\u{1F50D} Domain filter: \`${d}\` | min_confidence: ${s}`,"","### Transfer Summary",` \u{1F578}\uFE0F CKG nodes: ${a}`,` \u{1F517} CKG edges: ${t} (${n} skipped, confidence < ${s})`,` \u{1F4DA} Lessons: ${o}`,...H(h,m,`${o} kopierten Lektionen`),""];return p.length>0&&(g.push("### Sample lessons transferred:",...p),o>p.length&&g.push(` _... and ${o-p.length} more_`),g.push("")),e?g.push("\u{1F4A1} Run without `dry_run: true` to apply the transfer."):(g.push(`\u2705 Transfer complete. Your brain now has the \`${d}\` knowledge from \`${c}\`.`),g.push(`\u{1F50D} Explore: \`ckg_inspect(concept="${d}")\` | \`recall_best_solution(topic="${d}:...")\``)),g.join(`
|
|
19
|
+
`)}case"crystal_view":{const{instance_id:w,show_raw:c=!1}=N,d=await A(w),s=await d.get("cachly:crystal:latest");if(!s)return["\u{1F48E} **Memory Crystal: not yet created**","","No crystal found. Create one with `memory_crystalize()` to compress your accumulated wisdom.","","\u{1F4A1} Tip: run `memory_crystalize` monthly for best results."].join(`
|
|
20
|
+
`);const e=R(s,null);if(!e)return"\u274C Memory Crystal data is corrupted. Re-create with `memory_crystalize()`.";const i=Math.floor((Date.now()-new Date(e.ts).getTime())/864e5),f=i<=7?"\u{1F7E2}":i<=30?"\u{1F7E1}":"\u{1F534}",r=[`\u{1F48E} **Memory Crystal: ${e.label}**`,"",`\u{1F4C5} Created: ${new Date(e.ts).toLocaleDateString("de-DE")} (${i}d ago ${f})`,`\u{1F4CA} Compressed from: ${e.created_from}`,`\u{1F5C2}\uFE0F Categories: ${e.categories.slice(0,10).map(l=>`\`${l}\``).join(", ")}${e.categories.length>10?` +${e.categories.length-10} more`:""}`,"",`**\u{1F511} Top patterns (${e.top_patterns.length}):**`];for(const l of e.top_patterns)r.push(` \u2022 **${l.category}** (${l.count}\xD7): ${l.insight.slice(0,110)}`);i>30&&r.push("",`\u26A0\uFE0F Crystal is ${i}d old \u2014 run \`memory_crystalize()\` to refresh it.`),c&&r.push("","```json",JSON.stringify(e,null,2),"```");const u=await d.get("cachly:crystal:team:latest").catch(()=>null);if(u){const l=R(u,null);if(l&&l.patterns?.length){const a=Math.floor((Date.now()-new Date(l.ts).getTime())/864e5);r.push("","---",`\u{1F4A0} **Team Crystal: ${l.label}** _(${a}d ago \xB7 ${l.contributors} contributors)_`,"_Fixes multiple teammates independently converged on \u2014 the team-wide layer:_");for(const t of l.patterns.slice(0,5))r.push(` \u2022 \u{1F9E9} **${t.concept}** \u2014 ${t.author_count} people (${t.authors.map(o=>`@${o}`).join(", ")}): ${t.convergent_fix.slice(0,90)}`)}}return r.push("",'\u{1F4A1} Refresh: `memory_crystalize()` \xB7 `team_crystallize()` | Recover: `compact_recover(instance_id="...")`'),r.join(`
|
|
21
|
+
`)}case"compact_recover":{const{instance_id:w,focus:c=""}=N,d=await A(w),s=[`\u{1F501} **Compact Recovery Briefing**
|
|
22
22
|
`];s.push(`> *Call this first after any context limit hit. Reconstructs where you left off.*
|
|
23
|
-
`);const e=await d.get("cachly:crystal:latest");if(e){const t=R(e,null);if(t){s.push(`### \u{1F48E} Memory Crystal: ${t.label}`),s.push(`Compressed from ${t.session_count} sessions, ${t.lesson_count} lessons.`);const o=c?t.top_patterns.filter(n=>n.category.toLowerCase().includes(c.toLowerCase())||n.insight.toLowerCase().includes(c.toLowerCase())).slice(0,4):t.top_patterns.slice(0,4);for(const n of o)s.push(` \u2022 **${n.category}**: ${n.insight.slice(0,100)}`);s.push("")}}const i=await d.get("cachly:session:last");if(i){const t=R(i,null);t&&(s.push("### \u{1F550} Last Session"),t.focus&&s.push(`Focus: _${t.focus}_`),t.summary&&s.push(`Summary: ${t.summary.slice(0,300)}`),s.push(""))}const
|
|
24
|
-
`)}case"brain_from_git":{const w=Date.now(),{instance_id:c,repo_path:d=".",limit:s=100,branch:e="HEAD",since:i="",incremental:
|
|
23
|
+
`);const e=await d.get("cachly:crystal:latest");if(e){const t=R(e,null);if(t){s.push(`### \u{1F48E} Memory Crystal: ${t.label}`),s.push(`Compressed from ${t.session_count} sessions, ${t.lesson_count} lessons.`);const o=c?t.top_patterns.filter(n=>n.category.toLowerCase().includes(c.toLowerCase())||n.insight.toLowerCase().includes(c.toLowerCase())).slice(0,4):t.top_patterns.slice(0,4);for(const n of o)s.push(` \u2022 **${n.category}**: ${n.insight.slice(0,100)}`);s.push("")}}const i=await d.get("cachly:session:last");if(i){const t=R(i,null);t&&(s.push("### \u{1F550} Last Session"),t.focus&&s.push(`Focus: _${t.focus}_`),t.summary&&s.push(`Summary: ${t.summary.slice(0,300)}`),s.push(""))}const f=await d.get("cachly:session:handoff");if(f){const t=R(f,null);if(t){if(s.push("### \u{1F4CB} Handoff (from last window)"),t.context_summary&&s.push(`Context: ${t.context_summary.slice(0,200)}`),t.remaining_tasks?.length){s.push("Remaining tasks:");for(const o of t.remaining_tasks.slice(0,5))s.push(` \u2022 ${o}`)}t.instructions&&s.push(`\u26A0\uFE0F Instructions: ${t.instructions.slice(0,200)}`),t.blocked_on&&s.push(`\u{1F6A7} Blocked on: ${t.blocked_on}`),s.push("")}}const r=await d.get("cachly:ctx:wip-registry");if(r){const t=R(r,null);t?.content&&(s.push("### \u{1F527} WIP Registry"),s.push(t.content.slice(0,400)),s.push(""))}const u=[],l=d.scanStream({match:"cachly:roadmap:*",count:100});await new Promise((t,o)=>{l.on("data",n=>u.push(...n)),l.on("end",t),l.on("error",o)});const a=[];for(const t of u.slice(0,30)){const o=await d.get(t);if(o)try{const n=JSON.parse(o);(n.status==="in_progress"||n.status==="blocked")&&a.push({title:n.title??t,status:n.status,priority:n.priority})}catch{}}if(a.length>0){s.push("### \u{1F6A7} Open Items");for(const t of a.slice(0,5))s.push(` \u2022 [${t.status}] ${t.title}`);s.push("")}if(c){const t=[],o=d.scanStream({match:"cachly:lesson:best:*",count:200});await new Promise((h,m)=>{o.on("data",p=>t.push(...p)),o.on("end",h),o.on("error",m)});const n=[];for(const h of t){const m=await d.get(h);if(m)try{const p=JSON.parse(m);p.topic.toLowerCase().includes(c.toLowerCase())&&p.what_worked&&n.push({topic:p.topic,what_worked:p.what_worked})}catch{}}if(n.length>0){s.push(`### \u{1F4A1} Relevant Lessons for "${c}"`);for(const h of n.slice(0,4))s.push(` \u2022 **${h.topic}**: ${h.what_worked.slice(0,100)}`);s.push("")}}return s.length<=3&&s.push("_No brain data found. Start accumulating knowledge with `learn_from_attempts` and `session_start`._"),s.push("---","\u{1F9E0} Brain is ready. Continue your work \u2014 full context restored."),s.join(`
|
|
24
|
+
`)}case"brain_from_git":{const w=Date.now(),{instance_id:c,repo_path:d=".",limit:s=100,branch:e="HEAD",since:i="",incremental:f=!0}=N,r=await A(c),{resolve:u}=await import("node:path"),l=u(d),a=Math.max(1,Math.floor(Math.min(Number(s)||100,500)));if(typeof e!="string"||$e(e))return'\u274C Ungueltiger `branch`: darf nicht mit "-" beginnen.';await Me();try{try{if(!Se(l))throw new Error("kein Ordner");ie(l,["rev-parse","--git-dir"],{stderr:"pipe"})}catch{return`\u274C Not a git repository: \`${l}\`. Pass \`repo_path\` pointing to a git checkout.`}const t=`cachly:brain_from_git:last_sha:${Buffer.from(l).toString("base64").slice(0,32)}`;let o="",n=!1;f!==!1&&!i&&(o=await r.get(t)??"",ke(o)||(o=""),n=!!o);const m=(n?`${o}..HEAD`:"")||e||"HEAD",p=Ne(m,a,i);let y="";try{y=ie(l,p,{stderr:"pipe",timeoutMs:6e4})}catch(I){return`\u274C git log failed: ${I.message}. Check \`repo_path\` and \`branch\`.`}const g=Ie(y);if(g.length===0)return n?`\u2705 brain_from_git: Brain is up to date \u2014 no new commits since last run (last SHA: \`${o.slice(0,8)}\`).`:ae({repoDir:l,revRange:m,processed:0,ingested:0,skipped:0,durationMs:Date.now()-w,isIncremental:!1,instanceId:c,categories:[],suggestedQueries:[],emptyReason:`No commits found in \`${l}\` on branch \`${e}\`${i?` since ${i}`:""}.`});const x=new Date().toISOString();let C=0,_=0;const $=new Map,v=new Map,j=[];let S=null;const k=g.length,O=Math.max(1,Math.floor(k/10));let M=0;process.stderr.write(`
|
|
25
25
|
\u{1F9E0} brain_from_git: processing ${k} commits from ${l}...
|
|
26
|
-
`);let
|
|
27
|
-
`),
|
|
26
|
+
`);let F=0,Q=0;for(let I=0;I<g.length;I++){const{commit:L,geschwaerzt:de,verdacht:ue,lektion:P}=Oe(g[I]);if(de&&F++,ue&&Q++,I-M>=O&&(process.stderr.write(` \u23F3 Processing ${I}/${k} commits (${C} lessons so far)...
|
|
27
|
+
`),M=I),!P){_++;continue}const{topic:D,category:z,outcome:q,severity:U}=P;$.set(z,($.get(z)??0)+1),v.set(U,(v.get(U)??0)+1),j.push(D),(!S||z==="fix"&&!S.topic.startsWith("fix:"))&&(S={topic:D,subject:L.subject});const te=P.file_paths,oe={topic:D,outcome:q,severity:U,what_worked:P.what_worked,what_failed:P.what_failed,context:P.context,author:P.author,file_paths:te,commands:P.commands,tags:P.tags,visibility:"team",depends_on:[],recall_count:0,ts:x,verified_at:x,confidence:.55,audit_trail:[{ts:x,action:"brain_from_git",sha:L.sha.slice(0,8)}],version:3};await r.get(`cachly:lesson:best:${D}`)||(await r.set(`cachly:lesson:best:${D}`,JSON.stringify(oe),"EX",90*86400),await r.rpush(`cachly:lessons:${D}`,JSON.stringify(oe)),await r.ltrim(`cachly:lessons:${D}`,-100,-1),await r.expire(`cachly:lessons:${D}`,90*86400),await r.sadd(Ae,D).catch(()=>{})),await r.rpush("cachly:lessons:brain_from_git:all",JSON.stringify({topic:D,sha:L.sha.slice(0,8),subject:L.subject.slice(0,60)})),await r.ltrim("cachly:lessons:brain_from_git:all",-500,-1),await r.expire("cachly:lessons:brain_from_git:all",90*86400);const se=b(D);if(await T(r,se,z,"git-derived"),L.author)try{const W=await pe(r,L.author,z);await J(r,W,"authored",se,q==="success",q==="partial");for(const fe of te.slice(0,8)){const ne=await ge(r,fe);await J(r,W,"touched",ne,!0),await _e(r,ne,W)}}catch{}C++}process.stderr.write(` \u2705 brain_from_git complete: ${C}/${k} commits ingested
|
|
28
28
|
|
|
29
|
-
`),C>0&&ve(),g.length>0&&g[0]?.sha&&await r.set(t,g[0].sha,"EX",2160*3600),De={fixes:$.get("fix")??0,features:$.get("feat")??0,refactors:$.get("refactor")??0,total:C};let X=null;if(S&&C>0)try{const I=await xe(r,["cachly:lesson:best:*"],S.subject,1);if(I.length>0){const L=R(I[0].content,{});X={query:S.subject.slice(0,80),topic:L.topic??I[0].key.replace("cachly:lesson:best:",""),snippet:(L.what_worked??"").slice(0,120)||S.subject.slice(0,120)}}}catch{}const Z=ae({repoDir:l,revRange:m,processed:g.length,ingested:C,skipped:_,durationMs:Date.now()-w,isIncremental:n,lastSha:o,instanceId:c,categories:[...$.entries()].sort((I,L)=>L[1]-I[1]),severities:[...v.entries()].sort((I,L)=>L[1]-I[1]),proof:X,suggestedQueries:
|
|
30
|
-
`):Z}finally{Pe()}}case"brain_from_ci":{const{instance_id:w,outcomes:c}=
|
|
31
|
-
`)}case"brain_predict_failures":{const{instance_id:w,context:c,top_k:d=5,format:s="detailed"}=
|
|
32
|
-
`);const l=new Set,a=
|
|
33
|
-
`];t.push(`> Pre-deploy failure analysis based on ${
|
|
29
|
+
`),C>0&&ve(),g.length>0&&g[0]?.sha&&await r.set(t,g[0].sha,"EX",2160*3600),De={fixes:$.get("fix")??0,features:$.get("feat")??0,refactors:$.get("refactor")??0,total:C};let X=null;if(S&&C>0)try{const I=await xe(r,["cachly:lesson:best:*"],S.subject,1);if(I.length>0){const L=R(I[0].content,{});X={query:S.subject.slice(0,80),topic:L.topic??I[0].key.replace("cachly:lesson:best:",""),snippet:(L.what_worked??"").slice(0,120)||S.subject.slice(0,120)}}}catch{}const Z=ae({repoDir:l,revRange:m,processed:g.length,ingested:C,skipped:_,durationMs:Date.now()-w,isIncremental:n,lastSha:o,instanceId:c,categories:[...$.entries()].sort((I,L)=>L[1]-I[1]),severities:[...v.entries()].sort((I,L)=>L[1]-I[1]),proof:X,suggestedQueries:je(j,c)}),ee=H(F,Q,`${g.length} Commits`);return ee.length?[Z,"",...ee].join(`
|
|
30
|
+
`):Z}finally{Pe()}}case"brain_from_ci":{const{instance_id:w,outcomes:c}=N,d=await A(w),s=Date.now();let e=0,i=0,f=0,r=0,u=0;const l=c.length;for(const a of c){const t=G({job:String(a.job??"unknown"),context:String(a.context??"")});t.geschwaerzt.length&&r++;const o=String(a.status??""),n=String(a.prev_status??""),h=t.felder.job,m=t.felder.context,p=["failure","red","error"].includes(n)&&["success","green","passed"].includes(o),y=["success","green","passed"].includes(n)&&["failure","red","error"].includes(o),g=`ci:${b(h)}`,x=b(g);if(await T(d,x,"ci","job"),p){const _=b(`problem:${b(h)}`);await T(d,_,"problem","ci-failure"),await J(d,x,"fixes",_,!0);const $={topic:g,outcome:"success",what_worked:`CI job "${h}" went ${n} \u2192 ${o}`,what_failed:`Job "${h}" was failing`,context:`brain_from_ci: ${m}`,severity:"major",file_paths:[],commands:[],tags:K(["brain_from_ci","ci"],t.verdacht),depends_on:[],recall_count:0,ts:s,verified_at:s,confidence:.65,audit_trail:[{ts:s,action:"brain_from_ci_fixed"}],version:3};await d.rpush(`cachly:lessons:${g}`,JSON.stringify($)),await d.ltrim(`cachly:lessons:${g}`,-100,-1),await d.set(`cachly:lesson:best:${g}`,JSON.stringify($)),t.verdacht.length&&u++,e++}else if(y){const _=b(`cause:${b(h)}`);await T(d,_,"cause","ci-break"),await J(d,x,"causes",_,!1),i++}else f++;const C=`cachly:cls:${w}`;await d.rpush(C,JSON.stringify({source:"ci_outcome",payload:{status:o,prev_status:n,job:h},ts:s})),await d.ltrim(C,-200,-1)}return Te={fixes:e,breaks:i,stable:f,total:l},[`\u{1F4E5} **brain_from_ci**: Ingested ${l} outcomes \u2014 ${e} fixes learned, ${i} breaks noted, ${f} stable`,"",e>0?`\u2705 ${e} fix lesson${e!==1?"s":""} written (confidence 0.65) \u2014 CKG \`fixes\` edges added`:"",i>0?`\u{1F534} ${i} break${i!==1?"s":""} noted \u2014 CKG \`causes\` edges added`:"",f>0?`\u{1F4CA} ${f} stable outcome${f!==1?"s":""} recorded`:"","",'\u{1F4A1} Explore: `brain_search(query="ci")` | `brain_predict(context="<job-name>")`',...H(r,u,`${l} CI-Ergebnissen`)].filter(Boolean).join(`
|
|
31
|
+
`)}case"brain_predict_failures":{const{instance_id:w,context:c,top_k:d=5,format:s="detailed"}=N,e=await A(w),i=c.toLowerCase().replace(/[^a-z0-9\s\-_:.]/g," ").split(/\s+/).filter(n=>n.length>2),f=[];for(const n of i.slice(0,8)){const h=[],m=e.scanStream({match:`cachly:ckg:node:*${n}*`,count:50});await new Promise((p,y)=>{m.on("data",g=>h.push(...g)),m.on("end",p),m.on("error",y)});for(const p of h.slice(0,5)){const y=await e.get(p);if(!y)continue;const g=R(y,null);if(!g)continue;const x=await e.smembers(`cachly:ckg:idx:from:${g.id}`);for(const C of x.slice(0,20)){const _=await e.get(C);if(!_)continue;const $=R(_,null);if(!$||$.edgeType!=="causes"&&$.edgeType!=="degrades_under")continue;const v=await e.smembers(`cachly:ckg:idx:from:${$.to}`);let j;for(const S of v.slice(0,10)){const k=await e.get(S);if(!k)continue;const O=R(k,null);if(O&&O.edgeType==="fixes"){const M=await e.get(`cachly:lesson:best:${O.from}`);if(M){j=R(M,null)?.what_worked?.slice(0,120);break}}}f.push({concept:g.id,failure:$.to.replace(/-/g," "),probability:$.confidence,fix:j,source:"ckg"})}}}const r=[],u=e.scanStream({match:"cachly:lesson:best:*",count:300});await new Promise((n,h)=>{u.on("data",m=>r.push(...m)),u.on("end",n),u.on("error",h)});for(const n of r.slice(0,100)){const h=await e.get(n);if(h)try{const m=JSON.parse(h);if(m.outcome!=="failure"&&m.outcome!=="partial"||!m.what_failed)continue;const p=`${m.topic} ${m.what_failed}`.toLowerCase(),y=i.filter(x=>p.includes(x)).length/Math.max(1,i.length);if(y<.15)continue;const g=m.severity==="critical"?.15:m.severity==="major"?.05:0;f.push({concept:m.topic,failure:m.what_failed.slice(0,80),probability:Math.min(.97,(m.confidence??.5)*y*1.5+g),fix:m.what_worked?.slice(0,120),topic:m.topic,source:"lesson"})}catch{}}if(f.length===0)return[`\u{1F52E} **Failure Prediction: "${c}"**`,"","No known failure patterns found for this context.",'\u{1F4A1} The brain learns from every `learn_from_attempts(outcome="failure")` call.',`\u{1F50D} Try: \`brain_predict(context="${c}")\` for broader predictions.`].join(`
|
|
32
|
+
`);const l=new Set,a=f.filter(n=>{const h=n.failure.slice(0,40);return l.has(h)?!1:(l.add(h),!0)}).sort((n,h)=>h.probability-n.probability).slice(0,Number(d)),t=[`\u{1F52E} **Failure Prediction for: "${c}"**
|
|
33
|
+
`];t.push(`> Pre-deploy failure analysis based on ${f.length} patterns. Ranked by probability.
|
|
34
34
|
`);for(let n=0;n<a.length;n++){const h=a[n],m=Math.round(h.probability*100),p="\u2588".repeat(Math.round(m/10))+"\u2591".repeat(10-Math.round(m/10)),y=m>=70?"\u{1F534}":m>=40?"\u{1F7E1}":"\u{1F7E2}";t.push(`${y} **${n+1}. ${h.failure}**`),t.push(` Probability: ${p} **${m}%** (${h.source==="ckg"?"CKG causal edge":"lesson history"})`),s==="detailed"&&h.fix&&t.push(` \u2705 Pre-loaded fix: _${h.fix}_`),s==="detailed"&&h.topic&&t.push(` \u{1F4DA} Lesson: \`${h.topic}\``),t.push("")}const o=a.filter(n=>n.probability>=.6);return o.length>0?t.push(`\u26A0\uFE0F **${o.length} high-risk failure${o.length>1?"s":""} detected** (\u226560% probability). Review fixes before proceeding.`):t.push("\u2705 No high-risk failures detected. Proceed with caution and monitor closely."),t.push("",'\u{1F4A1} After deploy: `learn_from_attempts(topic="deploy:...", outcome="success|failure")` to improve future predictions.'),t.join(`
|
|
35
|
-
`)}case"brain_contribute_signal":{const{instance_id:w,topic_category:c,outcome:d,confidence:s=.5}=
|
|
36
|
-
`)}case"brain_import_meta":{const{instance_id:w,category:c,limit:d=20}=
|
|
37
|
-
`);let i=0;const
|
|
38
|
-
`)}case"brain_watch":{const{instance_id:w="",project_dir:c=".",api_key:d}=
|
|
39
|
-
`):[`\u{1F9E0} **brain_watch ${{written:"\u2705 Hook installed (new)",upgraded:"\u{1F504} Hook upgraded to latest version",appended:"\u{1F4CE} Hook appended to existing post-commit script",unchanged:"\u2713 Hook already up to date \u2014 nothing changed"}[i]??i}**`,"",`Hook path: \`${
|
|
35
|
+
`)}case"brain_contribute_signal":{const{instance_id:w,topic_category:c,outcome:d,confidence:s=.5}=N;if(!c?.trim())throw new Error("topic_category is required");if(!["success","failure","partial"].includes(d))throw new Error("outcome must be success, failure, or partial");const e=re({topic_category:c.trim()},"die Commons");if(!e.ok)return e.meldung;const i=e.felder.topic_category,f=s>=.75?"high":s>=.5?"medium":"low";let r="\u{1F4E6} Signal stored locally (commons API unavailable)";try{await E("/api/v1/federation/signals",{method:"POST",body:JSON.stringify({topic_category:i.toLowerCase(),outcome:d,confidence:s})}),r="\u2705 Signal contributed to the global commons (no raw data shared)"}catch{const u=await A(w),l=`cachly:fed:outbox:${Date.now()}`;await u.set(l,JSON.stringify({topic_category:i,outcome:d,bucket:f,ts:new Date().toISOString()}),"EX",3600*24*7).catch(()=>{})}return[`\u{1F512} **Brain Contribute Signal: \`${i}\`**`,"",`\u{1F4CA} Outcome: **${d}** \xB7 Confidence bucket: **${f}**`,"\u{1F6E1}\uFE0F Privacy: topic category only \u2014 no lesson text, no org identity","",r,...e.geschwaerzt.length?[ce(e.geschwaerzt)]:[],"","\u{1F4A1} When \u2265 k orgs contribute the same pattern, a meta-lesson appears in `brain_import_meta`."].join(`
|
|
36
|
+
`)}case"brain_import_meta":{const{instance_id:w,category:c,limit:d=20}=N;let s=[],e=3;try{const a=new URLSearchParams;c&&a.set("category",c),a.set("limit",String(Math.min(d,200)));const t=await E(`/api/v1/federation/meta?${a.toString()}`);s=t.meta_lessons??[],e=t.k_threshold??3}catch{return"\u274C Could not reach the global commons API. Try again later."}if(s.length===0)return["\u{1F310} **Brain Import Meta-Lessons**","",`No meta-lessons available yet (k-threshold: ${e} signals required).`,"","\u{1F4A1} Contribute signals with `brain_contribute_signal` to help build the commons."].join(`
|
|
37
|
+
`);let i=0;const f=new Set;s=s.map(a=>{const t=G({topic_category:a.topic_category,dominant_outcome:a.dominant_outcome});return t.geschwaerzt.length&&i++,t.verdacht.length&&f.add(t.felder.topic_category),{...a,...t.felder}});const r=await A(w);let u=0;for(const a of s){const t=`cachly:lesson:best:meta:${a.topic_category}`;await r.get(t)||(await r.set(t,JSON.stringify({topic:`meta:${a.topic_category}`,outcome:a.dominant_outcome,what_worked:a.contributor_count!=null?`Meta-pattern from ${a.contributor_count} independent orgs`:`Meta-pattern from ${a.signal_count} signals`,what_failed:"",recall_count:0,ts:a.derived_at,state:"meta",...f.has(a.topic_category)?{tags:[Le]}:{},avg_confidence:a.avg_confidence,signal_count:a.signal_count,audit_trail:[{ts:new Date().toISOString(),action:"imported_meta"}]})),u++)}const l=[`\u{1F310} **Brain Import Meta-Lessons** (k \u2265 ${e})`,"","| Topic Category | Outcome | Confidence | Signals |","|---|---|---|---|"];for(const a of s.slice(0,15)){const t=(a.avg_confidence*100).toFixed(0)+"%";l.push(`| \`${a.topic_category}\` | ${a.dominant_outcome} | ${t} | ${a.signal_count} |`)}return s.length>15&&l.push(`| _\u2026${s.length-15} more_ | | | |`),l.push("",`\u2705 **${u}** new meta-lessons imported into local Brain.`),u<s.length&&l.push(`_(${s.length-u} already present \u2014 not overwritten)_`),l.push(...H(i,f.size,`${s.length} Kategorienamen`)),l.join(`
|
|
38
|
+
`)}case"brain_watch":{const{instance_id:w="",project_dir:c=".",api_key:d}=N,{resolve:s}=await import("node:path"),e=s(c),{result:i,hookPath:f,alterBlockEntfernt:r}=await Ce(e,w);return i==="skipped-no-git"?["\u26A0\uFE0F **brain_watch: no git repository found**","",`No \`.git\` directory in \`${e}\`.`,"Pass `project_dir` pointing to a git checkout."].join(`
|
|
39
|
+
`):[`\u{1F9E0} **brain_watch ${{written:"\u2705 Hook installed (new)",upgraded:"\u{1F504} Hook upgraded to latest version",appended:"\u{1F4CE} Hook appended to existing post-commit script",unchanged:"\u2713 Hook already up to date \u2014 nothing changed"}[i]??i}**`,"",`Hook path: \`${f}\``,`Instance: \`${w||"(none \u2014 set CACHLY_BRAIN_INSTANCE_ID or pass instance_id)"}\``,...r?["\u{1F9F9} Removed the old brain_watch block from this file (it could hold your key in plain text)."]:[],...d?["\u2139\uFE0F The api_key you passed was not written into the hook."]:[],"","Every future commit will automatically teach your Brain \u2014 the same hook `init` installs.","It reads your key when it runs: `$CACHLY_JWT` or `~/.cachly/credentials.json`. No key is stored in the project.","",'\u{1F4A1} Verify: `git commit --allow-empty -m "test brain_watch"` then `smart_recall(query="test")`'].join(`
|
|
40
40
|
`)}default:return null}}export{Qe as FEDBRAIN_TOOL_NAMES,Te as _lastBrainFromCiCounts,De as _lastBrainFromGitCounts,Xe as handleFedbrainTool};
|
package/dist/src/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{setzeClientKennung as Pt}from"./herkunft.js";import{jwtExpiryMs as Nt,checkJwt as Ht,handleApiError as Mt,diagnoseAuth as Se,planAuthHeal as De,readClientCredentialsFromEnv as Dt,buildClientCredentialsBody as Ut,clientCredentialsTokenUrl as Jt}from"./auth.js";import{cachlyUrl as j}from"./cachly-url.js";import{nutzungsSchluessel as zt}from"./werkzeug-nutzung.js";import{istLieferung as Ft,lieferSchluessel as Wt,tokenDerAntwort as Yt,hatTreffer as Kt,trefferSchluessel as Ue}from"./geliefert.js";import{notify as Je}from"./notifier.js";import{fileURLToPath as ze}from"node:url";import{createRequire as qt}from"node:module";import{execFile as Ae}from"node:child_process";const Gt=process.argv[1]!=null&&(process.argv[1]===ze(import.meta.url)||process.argv[1].endsWith("/dist/index.js")||process.argv[1].endsWith("/src/index.ts"));import{Server as Fe}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Vt}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as Zt}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{CallToolRequestSchema as We,ErrorCode as ie,ListPromptsRequestSchema as Ye,ListResourceTemplatesRequestSchema as Ke,ListResourcesRequestSchema as qe,ListToolsRequestSchema as Ge,McpError as te}from"@modelcontextprotocol/sdk/types.js";import{Redis as Ve}from"ioredis";let x=process.env.CACHLY_API_URL??"https://api.cachly.dev",y=Be()??"";le(y);const js=process.env.CACHLY_EMBED_MODEL??"",D=(()=>{try{const e=qt(import.meta.url);for(const t of["../../package.json","../package.json"])try{const s=e(t);if(s.name==="@cachly-dev/mcp-server"&&s.version)return s.version}catch{}}catch{}return"0.10.100"})(),Qt=Number(process.env.CACHLY_PROVISION_TIMEOUT_MS??9e4);let P=xe(process.env.CACHLY_BRAIN_INSTANCE_ID);function oe(){return y||Be()||""}function F(){return xe(process.env.CACHLY_BRAIN_INSTANCE_ID)||ut()||""}let Z=0,de=null,Ze=!1;async function Xt(){let e=[];try{V.getClientCapabilities()?.roots&&(e=(await V.listRoots(void 0,{timeout:3e3})).roots)}catch{}return Tn({wurzeln:e,env:process.env,cwd:process.cwd(),dateiPfad:ze})}function re(){return Ze?gt(process.env):!1}function Ce(e,t,s){!e||!re()||kn({instanzId:e,vomHook:s,verbindung:H,ausGit:n=>je("brain_from_git",n,H,N),projektOrdner:t?async()=>t:Xt,einbetten:n=>et(n,{geduld:"lang"}),hatEinbettung:mo,einbettenZweit:n=>et(n,{geduld:"lang",modell:go}),melde:n=>S("brain_from_git",{...y?{api_key:y}:{},instance_id:e,total:n,auto:"startwissen"}),startvorrat:n=>Pe("brain_seed_starter",n,H,N),meldeStartvorrat:n=>S("brain_seed_starter",{...y?{api_key:y}:{},instance_id:e,auto:!0},{seeded_count:n,auto:!0})})}function Te(){return re()&&En()}const eo=7e3,to=12e3,oo=18e4;let ve=null;function Ee(e){return ve||(ve=no(e).finally(()=>{ve=null})),ve}async function no(e){try{if(!y){const t=Date.now()+e;for(;!Le()&&vn({})&&Date.now()<t;)await new Promise(o=>setTimeout(o,hn));const s=Le();if(!s)return!1;y=s,le(s);const n=ut();n&&!P&&(P=n,Z=0),await ue(s),n&&await pe(n),S("instant_trial_started",{tool:"sessionstart-hook",...n?{instance_id:n}:{}})}if(re()&&mt()){const t=yn();t&&(Oe(t.instanzId,re(),Te()),Ce(t.instanzId,t.projekt||void 0,t.vomHook))}}catch{}return!!y}function so(){if(!gt(process.env))return;const e=Date.now()+oo,t=setInterval(()=>{if(Date.now()>e){clearInterval(t);return}y&&!mt()||Ee(0)},500);t.unref(),Ee(0)}async function io(){if(!y)return"";try{const e=await fetch(`${x}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${y}`,"Content-Type":"application/json"},signal:AbortSignal.timeout(12e3)});if(e.ok){const t=await e.json(),s=t.instance?.id??t.instance_id;if(s)return s}else fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${y}`},body:JSON.stringify({event:"auto_provision_failed",status:e.status,version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}catch{fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"auto_provision_failed",status:0,reason:"network_error",version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}return""}async function Qe(){if(P)return P;if(!y)return"";if(de)return de;const e=Date.now();if(Z>0&&e-Z<3e4)return"";Z=e,de=(async()=>{try{const t=await fetch(`${x}/api/v1/instances`,{headers:{Authorization:`Bearer ${y}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(t.ok){const n=(await t.json())?.data??[],o=n.find(r=>r.status==="running")??n.find(r=>r.status==="provisioning");if(o)return P=o.id,Z=0,P;const c=await io();if(c)return P=c,Z=0,Oe(c,re(),Te()),pe(c),Ce(c),P}}catch{}return""})();try{return await de}finally{de=null}}let Ie=0;const ro=6e4;let ae="";async function ue(e){try{const{writeFile:t,mkdir:s,readFile:n}=await import("node:fs/promises"),{existsSync:o}=await import("node:fs"),{resolve:c,dirname:r}=await import("node:path"),a=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!a)return;const u=c(a,".claude","mcp.json");let m={};if(o(u))try{m=JSON.parse(await n(u,"utf-8"))}catch{}m.mcpServers??={};const l=m.mcpServers.cachly;if(l)l.env??={},l.env.CACHLY_JWT=e;else{const w={};w.CACHLY_JWT=e,m.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:w}}await s(r(u),{recursive:!0}),await t(u,JSON.stringify(m,null,2),"utf-8");const g=[c(a,".cursor","mcp.json"),c(a,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(g.map(async w=>{if(o(w))try{const v=await n(w,"utf-8"),b=JSON.parse(v),p=b?.mcpServers?.cachly;p?.env&&(p.env.CACHLY_JWT=e,await t(w,JSON.stringify(b,null,2),"utf-8"))}catch{}}))}catch{}}async function pe(e){if(e){dt(e,{apiKey:y});try{const{writeFile:t,readFile:s}=await import("node:fs/promises"),{existsSync:n}=await import("node:fs"),{resolve:o}=await import("node:path"),c=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!c)return;const r=[o(c,".claude","mcp.json"),o(c,".cursor","mcp.json"),o(c,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(r.map(async a=>{if(n(a))try{const u=JSON.parse(await s(a,"utf-8")),m=u?.mcpServers?.cachly;m?.env&&(m.env.CACHLY_BRAIN_INSTANCE_ID=e,await t(a,JSON.stringify(u,null,2),"utf-8"))}catch{}}))}catch{}}}async function ao(){try{const e=await fetch(`${x}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${y}`},body:JSON.stringify({name:"cachly-mcp-selfheal",scope:"read_write"}),signal:AbortSignal.timeout(8e3)});if(!e.ok)return!1;const t=await e.json();return t.key?(y=t.key,le(t.key),ue(t.key),S("auth_self_healed",{reason:"near_expiry_refresh"}),!0):!1}catch{return!1}}async function Re(){const e=Se(y),t=De(e);if(t==="none")return ae="",!0;if(t==="refresh"){const s=Date.now();return s-Ie>=ro&&(Ie=s,await ao())?(ae="",!0):(ae=e.message,e.usable)}return ae=e.message,!1}function ce(e,t){const s=(r,a)=>{try{t?.(r,a)}catch{}},n=r=>{r?s(!1,r.code??r.message):s(!0)},o=zo(e);if(!o){s(!1,"keine-http-adresse");return}const c=Fo(o);try{process.platform==="win32"?Ae("cmd",["/c","start","",c],{windowsHide:!0},n):process.platform==="darwin"?Ae("open",[o],n):Ae("xdg-open",[o],n)}catch(r){s(!1,r instanceof Error?r.message:"unknown")}}let G=null;async function co(){try{const e=await fetch(`${x}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({}),signal:AbortSignal.timeout(8e3)});if(e.ok){const t=await e.json(),s=t.verification_uri||j("/device","ambient-signin"),n=`${s}${s.includes("?")?"&":"?"}code=${encodeURIComponent(t.user_code)}`;return{deviceCode:t.device_code,userCode:t.user_code,verifyUrl:n,pollInterval:(t.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}}catch{}try{const t=await fetch("https://auth.cachly.dev/realms/cachly/protocol/openid-connect/auth/device",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"client_id=cachly-cli&scope=openid",signal:AbortSignal.timeout(8e3)});if(!t.ok)return null;const s=await t.json();return{deviceCode:s.device_code,userCode:s.user_code,verifyUrl:s.verification_uri_complete,pollInterval:(s.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}catch{return null}}async function lo(e){if(Date.now()>e.deadline)return"expired";const t=async()=>{const n=await fetch(`${x}/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:e.deviceCode}),signal:AbortSignal.timeout(8e3)});return n.ok?n.json():null},s=async()=>(await fetch("https://auth.cachly.dev/realms/cachly/protocol/openid-connect/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`client_id=cachly-cli&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=${e.deviceCode}`,signal:AbortSignal.timeout(8e3)})).json();try{let n=await t().catch(()=>null);if(n||(n=await s().catch(()=>null)),!n)return"pending";if(n.access_token){let o=n.access_token;try{const c=await fetch(`${x}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({name:"cachly-mcp-smithery",scope:"read_write"}),signal:AbortSignal.timeout(8e3)});if(c.ok){const r=await c.json();r.key&&(o=r.key)}}catch{}return y=o,le(o),G=null,S("device_flow_completed"),ue(o),Q(o),Z=0,await Qe(),P&&pe(P),"done"}return n.error==="slow_down"&&(e.pollInterval=Math.min(e.pollInterval+2e3,15e3)),"pending"}catch{return"pending"}}async function Xe(e){if(e.polling)return"pending";e.polling=!0;try{return await lo(e)}finally{e.polling=!1}}function uo(e,t=Xe,s=o=>G===o,n=po){const o=async()=>{if(!s(e))return;let c="pending";try{c=await t(e)}catch{}if(c!=="done"){if(c==="expired"){s(e)&&(G=null);return}s(e)&&n(o,e.pollInterval)}};n(o,e.pollInterval)}function po(e,t){const s=setTimeout(e,t);typeof s.unref=="function"&&s.unref()}import{setEmbedJwt as le,computeEmbedding as et,hasEmbedProvider as mo,EMBED_PROVIDER as tt}from"./embeddings.js";import{ZWEIT_MODELL as go}from"./rangfolge-stellschrauben.js";import{tokenize as fo,splitMultiQuery as ho,levenshtein as yo,recencyBoost as bo,extractTimestamp as vo,STOPWORDS as wo,katakanaToRomaji as xo,arabicLightStem as _o,expandCrossLingual as $o,CROSS_LINGUAL_MAP as ko,ZERO_RESULTS_LOG as So,zeroResultsTotal as Ao}from"./search.js";const ne=new Map;function Co(e){return e<=1?200:null}async function H(e){if(!e)throw new te(ie.InvalidRequest,`\u23F3 Your Brain instance is still being set up.
|
|
2
|
+
import{setzeClientKennung as Nt}from"./herkunft.js";import{jwtExpiryMs as Pt,checkJwt as Ht,handleApiError as Mt,diagnoseAuth as Se,planAuthHeal as De,readClientCredentialsFromEnv as Dt,buildClientCredentialsBody as Ut,clientCredentialsTokenUrl as Jt}from"./auth.js";import{cachlyUrl as j}from"./cachly-url.js";import{nutzungsSchluessel as zt}from"./werkzeug-nutzung.js";import{istLieferung as Ft,lieferSchluessel as Wt,tokenDerAntwort as Yt,hatTreffer as Kt,trefferSchluessel as Ue}from"./geliefert.js";import{notify as Je}from"./notifier.js";import{fileURLToPath as ze}from"node:url";import{createRequire as qt}from"node:module";import{execFile as Ae}from"node:child_process";const Gt=process.argv[1]!=null&&(process.argv[1]===ze(import.meta.url)||process.argv[1].endsWith("/dist/index.js")||process.argv[1].endsWith("/src/index.ts"));import{Server as Fe}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Vt}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as Zt}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{CallToolRequestSchema as We,ErrorCode as ie,ListPromptsRequestSchema as Ye,ListResourceTemplatesRequestSchema as Ke,ListResourcesRequestSchema as qe,ListToolsRequestSchema as Ge,McpError as te}from"@modelcontextprotocol/sdk/types.js";import{Redis as Ve}from"ioredis";let x=process.env.CACHLY_API_URL??"https://api.cachly.dev",y=Be()??"";le(y);const js=process.env.CACHLY_EMBED_MODEL??"",D=(()=>{try{const e=qt(import.meta.url);for(const t of["../../package.json","../package.json"])try{const s=e(t);if(s.name==="@cachly-dev/mcp-server"&&s.version)return s.version}catch{}}catch{}return"0.10.100"})(),Qt=Number(process.env.CACHLY_PROVISION_TIMEOUT_MS??9e4);let N=xe(process.env.CACHLY_BRAIN_INSTANCE_ID);function oe(){return y||Be()||""}function F(){return xe(process.env.CACHLY_BRAIN_INSTANCE_ID)||ut()||""}let Z=0,de=null,Ze=!1;async function Xt(){let e=[];try{V.getClientCapabilities()?.roots&&(e=(await V.listRoots(void 0,{timeout:3e3})).roots)}catch{}return Tn({wurzeln:e,env:process.env,cwd:process.cwd(),dateiPfad:ze})}function re(){return Ze?gt(process.env):!1}function Ce(e,t,s){!e||!re()||kn({instanzId:e,vomHook:s,verbindung:H,ausGit:n=>je("brain_from_git",n,H,P),projektOrdner:t?async()=>t:Xt,einbetten:n=>et(n,{geduld:"lang"}),hatEinbettung:mo,einbettenZweit:n=>et(n,{geduld:"lang",modell:go}),melde:n=>S("brain_from_git",{...y?{api_key:y}:{},instance_id:e,total:n,auto:"startwissen"}),startvorrat:n=>Ne("brain_seed_starter",n,H,P),meldeStartvorrat:n=>S("brain_seed_starter",{...y?{api_key:y}:{},instance_id:e,auto:!0},{seeded_count:n,auto:!0})})}function Te(){return re()&&En()}const eo=7e3,to=12e3,oo=18e4;let ve=null;function Ee(e){return ve||(ve=no(e).finally(()=>{ve=null})),ve}async function no(e){try{if(!y){const t=Date.now()+e;for(;!Le()&&vn({})&&Date.now()<t;)await new Promise(o=>setTimeout(o,hn));const s=Le();if(!s)return!1;y=s,le(s);const n=ut();n&&!N&&(N=n,Z=0),await ue(s),n&&await pe(n),S("instant_trial_started",{tool:"sessionstart-hook",...n?{instance_id:n}:{}})}if(re()&&mt()){const t=yn();t&&(Oe(t.instanzId,re(),Te()),Ce(t.instanzId,t.projekt||void 0,t.vomHook))}}catch{}return!!y}function so(){if(!gt(process.env))return;const e=Date.now()+oo,t=setInterval(()=>{if(Date.now()>e){clearInterval(t);return}y&&!mt()||Ee(0)},500);t.unref(),Ee(0)}async function io(){if(!y)return"";try{const e=await fetch(`${x}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${y}`,"Content-Type":"application/json"},signal:AbortSignal.timeout(12e3)});if(e.ok){const t=await e.json(),s=t.instance?.id??t.instance_id;if(s)return s}else fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${y}`},body:JSON.stringify({event:"auto_provision_failed",status:e.status,version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}catch{fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"auto_provision_failed",status:0,reason:"network_error",version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}return""}async function Qe(){if(N)return N;if(!y)return"";if(de)return de;const e=Date.now();if(Z>0&&e-Z<3e4)return"";Z=e,de=(async()=>{try{const t=await fetch(`${x}/api/v1/instances`,{headers:{Authorization:`Bearer ${y}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(t.ok){const n=(await t.json())?.data??[],o=n.find(r=>r.status==="running")??n.find(r=>r.status==="provisioning");if(o)return N=o.id,Z=0,N;const c=await io();if(c)return N=c,Z=0,Oe(c,re(),Te()),pe(c),Ce(c),N}}catch{}return""})();try{return await de}finally{de=null}}let Ie=0;const ro=6e4;let ae="";async function ue(e){try{const{writeFile:t,mkdir:s,readFile:n}=await import("node:fs/promises"),{existsSync:o}=await import("node:fs"),{resolve:c,dirname:r}=await import("node:path"),a=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!a)return;const u=c(a,".claude","mcp.json");let m={};if(o(u))try{m=JSON.parse(await n(u,"utf-8"))}catch{}m.mcpServers??={};const l=m.mcpServers.cachly;if(l)l.env??={},l.env.CACHLY_JWT=e;else{const w={};w.CACHLY_JWT=e,m.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:w}}await s(r(u),{recursive:!0}),await t(u,JSON.stringify(m,null,2),"utf-8");const g=[c(a,".cursor","mcp.json"),c(a,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(g.map(async w=>{if(o(w))try{const v=await n(w,"utf-8"),b=JSON.parse(v),p=b?.mcpServers?.cachly;p?.env&&(p.env.CACHLY_JWT=e,await t(w,JSON.stringify(b,null,2),"utf-8"))}catch{}}))}catch{}}async function pe(e){if(e){dt(e,{apiKey:y});try{const{writeFile:t,readFile:s}=await import("node:fs/promises"),{existsSync:n}=await import("node:fs"),{resolve:o}=await import("node:path"),c=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!c)return;const r=[o(c,".claude","mcp.json"),o(c,".cursor","mcp.json"),o(c,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(r.map(async a=>{if(n(a))try{const u=JSON.parse(await s(a,"utf-8")),m=u?.mcpServers?.cachly;m?.env&&(m.env.CACHLY_BRAIN_INSTANCE_ID=e,await t(a,JSON.stringify(u,null,2),"utf-8"))}catch{}}))}catch{}}}async function ao(){try{const e=await fetch(`${x}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${y}`},body:JSON.stringify({name:"cachly-mcp-selfheal",scope:"read_write"}),signal:AbortSignal.timeout(8e3)});if(!e.ok)return!1;const t=await e.json();return t.key?(y=t.key,le(t.key),ue(t.key),S("auth_self_healed",{reason:"near_expiry_refresh"}),!0):!1}catch{return!1}}async function Re(){const e=Se(y),t=De(e);if(t==="none")return ae="",!0;if(t==="refresh"){const s=Date.now();return s-Ie>=ro&&(Ie=s,await ao())?(ae="",!0):(ae=e.message,e.usable)}return ae=e.message,!1}function ce(e,t){const s=(r,a)=>{try{t?.(r,a)}catch{}},n=r=>{r?s(!1,r.code??r.message):s(!0)},o=zo(e);if(!o){s(!1,"keine-http-adresse");return}const c=Fo(o);try{process.platform==="win32"?Ae("cmd",["/c","start","",c],{windowsHide:!0},n):process.platform==="darwin"?Ae("open",[o],n):Ae("xdg-open",[o],n)}catch(r){s(!1,r instanceof Error?r.message:"unknown")}}let G=null;async function co(){try{const e=await fetch(`${x}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({}),signal:AbortSignal.timeout(8e3)});if(e.ok){const t=await e.json(),s=t.verification_uri||j("/device","ambient-signin"),n=`${s}${s.includes("?")?"&":"?"}code=${encodeURIComponent(t.user_code)}`;return{deviceCode:t.device_code,userCode:t.user_code,verifyUrl:n,pollInterval:(t.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}}catch{}try{const t=await fetch("https://auth.cachly.dev/realms/cachly/protocol/openid-connect/auth/device",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"client_id=cachly-cli&scope=openid",signal:AbortSignal.timeout(8e3)});if(!t.ok)return null;const s=await t.json();return{deviceCode:s.device_code,userCode:s.user_code,verifyUrl:s.verification_uri_complete,pollInterval:(s.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}catch{return null}}async function lo(e){if(Date.now()>e.deadline)return"expired";const t=async()=>{const n=await fetch(`${x}/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:e.deviceCode}),signal:AbortSignal.timeout(8e3)});return n.ok?n.json():null},s=async()=>(await fetch("https://auth.cachly.dev/realms/cachly/protocol/openid-connect/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`client_id=cachly-cli&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=${e.deviceCode}`,signal:AbortSignal.timeout(8e3)})).json();try{let n=await t().catch(()=>null);if(n||(n=await s().catch(()=>null)),!n)return"pending";if(n.access_token){let o=n.access_token;try{const c=await fetch(`${x}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({name:"cachly-mcp-smithery",scope:"read_write"}),signal:AbortSignal.timeout(8e3)});if(c.ok){const r=await c.json();r.key&&(o=r.key)}}catch{}return y=o,le(o),G=null,S("device_flow_completed"),ue(o),Q(o),Z=0,await Qe(),N&&pe(N),"done"}return n.error==="slow_down"&&(e.pollInterval=Math.min(e.pollInterval+2e3,15e3)),"pending"}catch{return"pending"}}async function Xe(e){if(e.polling)return"pending";e.polling=!0;try{return await lo(e)}finally{e.polling=!1}}function uo(e,t=Xe,s=o=>G===o,n=po){const o=async()=>{if(!s(e))return;let c="pending";try{c=await t(e)}catch{}if(c!=="done"){if(c==="expired"){s(e)&&(G=null);return}s(e)&&n(o,e.pollInterval)}};n(o,e.pollInterval)}function po(e,t){const s=setTimeout(e,t);typeof s.unref=="function"&&s.unref()}import{setEmbedJwt as le,computeEmbedding as et,hasEmbedProvider as mo,EMBED_PROVIDER as tt}from"./embeddings.js";import{ZWEIT_MODELL as go}from"./rangfolge-stellschrauben.js";import{tokenize as fo,splitMultiQuery as ho,levenshtein as yo,recencyBoost as bo,extractTimestamp as vo,STOPWORDS as wo,katakanaToRomaji as xo,arabicLightStem as _o,expandCrossLingual as $o,CROSS_LINGUAL_MAP as ko,ZERO_RESULTS_LOG as So,zeroResultsTotal as Ao}from"./search.js";const ne=new Map;function Co(e){return e<=1?200:null}async function H(e){if(!e)throw new te(ie.InvalidRequest,`\u23F3 Your Brain instance is still being set up.
|
|
3
3
|
|
|
4
4
|
This usually resolves in a few seconds \u2014 just call the tool again and it will connect automatically.
|
|
5
5
|
|
|
6
6
|
If it keeps happening:
|
|
7
7
|
\u2022 Run \`list_instances\` to check your instances, or
|
|
8
8
|
\u2022 Set CACHLY_BRAIN_INSTANCE_ID in your MCP config, or
|
|
9
|
-
\u2022 Reach us at support@cachly.dev.`);const t=ne.get(e);return t||_n(To,e,()=>Eo(e))}const To=new Map;async function Eo(e){W("verbindung: Instanz abfragen");let t=await
|
|
9
|
+
\u2022 Reach us at support@cachly.dev.`);const t=ne.get(e);return t||_n(To,e,()=>Eo(e))}const To=new Map;async function Eo(e){W("verbindung: Instanz abfragen");let t=await P(`/api/v1/instances/${e}`);if(W(`verbindung: Instanz ${t.status}`),t=await xn(t,()=>P(`/api/v1/instances/${e}`),{fristMs:Qt,melde:r=>W(`verbindung: Instanz ${r.status}`)}),t.status!=="running"){fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...y?{Authorization:`Bearer ${y}`}:{}},body:JSON.stringify({event:"instance_not_reachable",instance_id:e,status:t.status,version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{});let r;throw t.status==="provisioning"?r=`\u23F3 Brain instance "${t.name}" is still starting up.
|
|
10
10
|
|
|
11
11
|
First-time provisioning typically takes 1\u20133 minutes. Please retry in a moment \u2014 the instance will be ready soon.`:t.status==="failed"?r=`\u274C Brain instance "${t.name}" failed to start.
|
|
12
12
|
|
|
@@ -18,11 +18,11 @@ Update your payment method at: ${j("/billing","upgrade")}`:t.status==="pending_p
|
|
|
18
18
|
Complete your checkout at: ${j("/instances","upgrade")}`:r=`Brain instance "${t.name}" is not reachable (status: ${t.status}).
|
|
19
19
|
|
|
20
20
|
\u2022 View your instance at: ${j("/instances","instance-error")}
|
|
21
|
-
\u2022 Run \`get_api_status\` for a full diagnostic.`,new te(ie.InvalidRequest,r)}if(!t.host||!t.port)throw new te(ie.InternalError,`Instance "${t.name}" is running but has no host/port \u2014 contact support@cachly.dev.`);let s,n=t.tls_enabled!==!1;try{const r=await
|
|
21
|
+
\u2022 Run \`get_api_status\` for a full diagnostic.`,new te(ie.InvalidRequest,r)}if(!t.host||!t.port)throw new te(ie.InternalError,`Instance "${t.name}" is running but has no host/port \u2014 contact support@cachly.dev.`);let s,n=t.tls_enabled!==!1;try{const r=await P(`/api/v1/instances/${e}/connection`);s=r.password??void 0,n=r.tls_enabled!==!1,W("verbindung: Zugangsdaten da")}catch(r){const a=r instanceof Error?r.message:String(r);if(a.includes("401")||a.includes("403")||a.includes("Unauthorized"))throw new te(ie.InvalidRequest,"API key rejected \u2014 run `cachly setup` to refresh your credentials.")}const o=new Ve({host:t.host,port:t.port,password:s||void 0,commandTimeout:8e3,...n?{tls:{}}:{},lazyConnect:!0,enableReadyCheck:!0,connectTimeout:8e3,retryStrategy:Co,maxRetriesPerRequest:1,keepAlive:15e3}),c=()=>{ne.delete(e),o.disconnect()};o.on("error",c),o.on("end",c);try{await o.connect()}catch(r){o.disconnect();const a=r instanceof Error?r.message:String(r);throw fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...y?{Authorization:`Bearer ${y}`}:{}},body:JSON.stringify({event:"redis_connect_failed",instance_id:e,host:t.host,port:t.port,error:a,version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{}),new te(ie.InternalError,`Could not reach Brain instance "${t.name}" (${t.host}:${t.port}).
|
|
22
22
|
|
|
23
23
|
\u2022 Check your network connection
|
|
24
24
|
\u2022 Run \`get_api_status\` to verify instance status
|
|
25
|
-
\u2022 Technical detail: ${a}`)}return ne.set(e,o),W("verbindung: Valkey verbunden"),o}async function
|
|
25
|
+
\u2022 Technical detail: ${a}`)}return ne.set(e,o),W("verbindung: Valkey verbunden"),o}async function P(e,t={},s=!1){s||De(Se(y))!=="none"&&await Re(),Ht(y);const n=Number(process.env.CACHLY_API_TIMEOUT_MS??15e3),o=await fetch(`${x}${e}`,{...t,signal:AbortSignal.timeout(n),headers:{"Content-Type":"application/json",Authorization:`Bearer ${y}`,...t.headers}});if(!o.ok){if(o.status===401&&!s&&(Ie=0,await Re()))return P(e,t,!0);const r=(await o.json().catch(()=>({error:o.statusText}))).error??o.statusText;Mt(o.status,r)}if(o.status!==204)return o.json()}import{handleBrainTool as Io}from"./handlers/brain.js";import{handleContextTool as Ro}from"./handlers/context.js";import{handleInstanceTool as jo}from"./handlers/instances.js";import{handleCacheTool as Bo}from"./handlers/cache.js";import{handleTeamTool as Lo}from"./handlers/team.js";import{handleRoadmapTool as Oo}from"./handlers/roadmap.js";import{handleAdvancedTool as No}from"./handlers/advanced.js";import{handleSyndicateTool as Po}from"./handlers/syndicate.js";import{handleFedbrainTool as je,_lastBrainFromGitCounts as we}from"./handlers/fedbrain.js";import{extractFirstRecallProof as Ho,renderFirstRecallProof as Mo}from"./first-recall-proof.js";import{installClsPostCommitHook as ot,CLS_HOOK_VERSION as nt}from"./cls-hook.js";import{CLAUDE_MD_MARKER_START as st,CLAUDE_MD_MARKER_END as it,EDITOR_FILES as me,ANWEISUNGS_DATEIEN as Do,setzeAnweisungsblock as Uo}from"./projektdateien.js";import{uninstallBefehl as Jo}from"./uninstall.js";import{gitLesen as rt}from"./git-ohne-shell.js";import{browserAdresse as zo,fuerCmd as Fo}from"./browser-adresse.js";import{installAmbientHooks as at,installCursorHooks as Wo,installCopilotHooks as Yo,installCodexHooks as Ko,installGeminiHooks as qo,AMBIENT_HOOK_VERSION as ct,COPILOT_HOOKS_DATEI as Go,CODEX_HOOKS_DATEI as Vo,GEMINI_SETTINGS_DATEI as Zo}from"./ambient-hooks.js";import{hookHauptlauf as Qo,auffrischenHauptlauf as Xo,startwissenImportHauptlauf as en}from"./ambient-hook.js";import{STARTWISSEN_IMPORT as tn}from"./startwissen-hook.js";import{rahmeAntwort as on}from"./antwort-rahmen.js";import{appendLedgerEntry as nn,readLedger as lt,defaultLedgerPath as sn,reportLedgerEntry as rn}from"./ambient-ledger.js";import{resolveApiKey as Be,saveApiKey as Q,saveInstanceId as dt,readSavedApiKey as Le,readInstanceId as ut}from"./credentials.js";import{KEYCLOAK_BASIS as pt,istTestSchluessel as an,waehleTestSchluessel as cn,starteKeycloakAnmeldung as ln,warteAufKeycloakAnmeldung as dn,uebernimm as un,brainImKonto as pn,erfolgsText as mn,fehlerText as gn,ersetzeSchluessel as fn}from"./uebernahme.js";import{WARTE_TAKT_MS as hn,auftragLiegt as mt,nimmAuftrag as yn,sichereKonto as bn,sperreLiegt as vn,startwissenEingeschaltet as gt}from"./konto-anlegen.js";import{sichereZugang as wn,echterWert as xe}from"./zugang.js";import{zeitpunkt as W}from"./zeitmessung.js";import{warteAufLaufendeInstanz as xn,gemeinsamerAufbau as _n}from"./instanz-warten.js";import{merkeNeuesBrain as Oe,startetLautLetztemBlick as $n}from"./leeres-brain.js";import{starteStartwissen as kn,startwissenGestartet as Sn,beanspruchStartwissen as An,holeStartwissenHinweis as Cn,waehleProjektOrdner as Tn,startvorratErlaubt as En}from"./startwissen.js";import{eigeneFassung as In,pruefeNeueFassung as Rn,holeNeueFassungHinweis as jn}from"./neue-fassung.js";import{beiStdinEnde as Bn}from"./stdin-ende.js";import{merkeWerkzeugAufruf as Ln,starteBrandWachhund as On}from"./brand-wachhund.js";import{sichtbareWerkzeuge as Nn,VERTEILER as ft}from"./werkzeug-auswahl.js";import{buildLessonsMarkdown as Pn,buildLessonsJsonl as Hn,vonRohLektion as Mn}from"./brain-export.js";import{detectEditor as Dn}from"./editor.js";import{milestoneSent as ht,markMilestoneSent as yt}from"./funnel-milestones.js";import{kostprobeUebrig as Un,kostprobeVerbrauchen as Jn,kostprobeHinweis as zn,schrankeNachKostproben as Fn}from"./kostprobe.js";import{netBalance as Wn}from"./ambient-recall.js";import{handleShareTool as Ne}from"./handlers/share.js";import{handleVizTool as Yn}from"./handlers/viz.js";import{commitArt as Kn,istRueckbau as qn,zaehleLektionen as Gn}from"./commit-art.js";import{TOOLS as ge}from"./tools.js";let bt=!1,_e=!1;function vt(){return Dn()}function Vn(e){if(!e)return null;const t=e.match(/\*\*💡\s+([^*]+)\*\*/),s=e.match(/^>\s+(.+)$/m);if(!t||!s)return null;const n=t[1].trim(),o=s[1].trim();return!n||!o?null:{topic:n,what:o}}function Zn(e){try{const t=e.split(".");if(t.length!==3)return;const s=JSON.parse(Buffer.from(t[1],"base64url").toString("utf-8"));if(!s.sub)return;let n=2166136261;for(let o=0;o<s.sub.length;o++)n^=s.sub.charCodeAt(o),n=n*16777619>>>0;return n.toString(16).padStart(8,"0")+s.sub.length.toString(16).padStart(4,"0")}catch{return}}function S(e,t,s){if(process.env.CACHLY_NO_TELEMETRY==="1")return;const n=y?Zn(y):void 0;fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:e,version:D,editor:vt(),...y?{jwt:y}:{},...n?{user_fingerprint:n}:{},...s?{metrics:s}:{},...t}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}function Qn(e,t){return rn({apiUrl:x,jwt:y,instanceId:e},t)}async function Xn(e){if(!bt&&process.env.CACHLY_NO_TELEMETRY!=="1"){bt=!0;try{await fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"first_call_no_jwt",version:D,editor:vt(),tool:e}),signal:AbortSignal.timeout(3e3)})}catch{}}}const es=new Set(["causal_trace","brain_predict","brain_plan","brain_predict_failures","team_learn","team_confirm","team_recall","team_synthesize","team_crystallize","global_learn","global_recall"]),ts={causal_trace:"Causal root-cause tracing \u2014 follow the failure chain to the real cause, not just the symptom.",brain_predict:"Predictive risk \u2014 your Brain warns you what will break *before* you run it.",brain_plan:"Generative planning \u2014 turn a goal into an ordered, risk-aware plan from your own history.",brain_predict_failures:"Failure prediction \u2014 catch CI/build breakage before it happens.",team_learn:"Team Brain \u2014 one shared memory across your whole team.",team_confirm:"Team Brain \u2014 peer + senior review that raises lesson trust.",team_recall:"Team Brain \u2014 recall everything your teammates have already solved.",team_synthesize:"Team Brain \u2014 synthesize collective knowledge across authors.",team_crystallize:"Team Brain \u2014 compress your team's wisdom into a shareable crystal.",global_learn:"Team Brain \u2014 contribute to your organization's shared memory.",global_recall:"Team Brain \u2014 recall across your entire organization."},wt=j("/billing","upgrade"),xt=new Map;async function os(e){const t=xt.get(e);if(t&&t.expiresAt>Date.now())return t.info;try{const n=((await P(`/api/v1/instances/${e}`))?.tier??"free").toLowerCase(),o={tier:n,isFree:n==="free"||n===""};return xt.set(e,{info:o,expiresAt:Date.now()+6e4}),o}catch{return{tier:"unknown",isFree:!1}}}async function ns(e,t){if(!es.has(e)||!t)return null;const{isFree:s}=await os(t);if(!s)return null;const n=ts[e]??"A Premium intelligence feature.";if(Un(e)){const o=Jn(e);return{kostprobe:zn(e,o,wt)}}return{sperre:Fn(e,n,wt)}}async function ss(e,t){try{await(await H(e)).hincrby(zt(e),t,1)}catch{}}async function is(e,t,s){if(Ft(t))try{const n=await H(e),o=Kt(s);await n.incrby(Wt(e),o?Yt(s):0),await n.hincrby(Ue(e),"abrufe",1),o&&await n.hincrby(Ue(e),"treffer",1)}catch{}}async function rs(e){const t=await co();return t?(G=t,S("device_flow_started",{tool:e}),ce(t.verifyUrl,(s,n)=>{if(s){S("device_browser_opened",{stelle:"tool"});return}S("device_browser_failed",{reason:n??"unknown",stelle:"tool"}),process.stderr.write(`
|
|
26
26
|
cachly: could not open a browser (${n??"unknown"}).
|
|
27
27
|
cachly: open this yourself to finish signing in:
|
|
28
28
|
cachly: ${t.verifyUrl}
|
|
@@ -31,7 +31,7 @@ cachly: code ${t.userCode}
|
|
|
31
31
|
`)}),uo(t),["\u{1F9E0} **cachly AI Brain \u2014 the user must sign in once.**","","**Show the following link and code to the user verbatim \u2014 they cannot","continue without them.**","",`\u{1F449} **${t.verifyUrl}**`,"",`Code: **${t.userCode}**`,"","A browser may have opened automatically with the code pre-filled. If it","did not, the link above is the whole step.","","Once signed in, the Brain activates on its own \u2014 no further action, no","restart. The next request arrives brain-powered.","",`\u2728 ${ge.length} MCP tools \xB7 GDPR \xB7 EU servers \xB7 free tier, no credit card`].join(`
|
|
32
32
|
`)):["\u{1F9E0} **cachly AI Brain \u2014 Setup required**","","Run the setup wizard once in your terminal:"," ```"," npx @cachly-dev/mcp-server@latest autopilot"," ```","",`Or get your API key at: ${j("/setup-ai","ambient-signin")}`,"","\u2728 Free tier includes: 1 Brain instance, persistent memory, semantic search."].join(`
|
|
33
33
|
`)}async function as(e){if(!e)return!0;if(Sn(e))return!1;try{return await An(await H(e),"sitzungsstart")}catch{return!0}}async function z(e,t){if(!y&&await Ee(eo))return z(e,t);if(!y){if(Xn(e),G){const i=await Xe(G);return i==="done"?z(e,t):i==="expired"?(S("device_flow_failed",{reason:"timeout"}),G=null,"\u231B **Authentication timed out.** Please call any tool again to restart the sign-in flow."):["\u23F3 **Signing you in\u2026**","",`Finish in your browser: **${G.verifyUrl}**`,`Code: **${G.userCode}**`,"","This completes automatically once you sign in \u2014 no need to come back here."].join(`
|
|
34
|
-
`)}return wn({schluessel:y,konfigurierteInstanz:
|
|
34
|
+
`)}return wn({schluessel:y,konfigurierteInstanz:N,aufrufInstanz:t.instance_id,werkzeugName:e,holeSofortTest:async()=>{W("sofort-test: Anfang");const i=await bn({apiUrl:x,version:D,fristMs:to}),d=i.art==="angelegt"?i.test:i.art==="vorhanden"&&i.instanzId?{apiKey:i.apiKey,instanzId:i.instanzId}:null;return W(`sofort-test: ${d?"Brain angelegt":"kein Test"}`),d&&Oe(d.instanzId,re(),Te()),d},ablagen:{setzeSchluessel:i=>{y=i},setEmbedJwt:le,saveApiKey:i=>Q(i),persistApiKeyToConfig:ue,merkeInstanz:i=>{N=i,Z=0},persistInstanceIdToConfig:pe},meldeEreignis:S,werkzeug:()=>z(e,t),anmelden:()=>rs(e),neuesBrain:Ce})}if(!t.instance_id){const i=await Qe();i&&(t={...t,instance_id:i})}const s=await ns(e,t.instance_id);let n="";if(s!==null){if("sperre"in s)return S("premium_gate_hit",{tool:e,instance_id:t.instance_id??""}),s.sperre;n=s.kostprobe,S("premium_taste_used",{tool:e,instance_id:t.instance_id??""})}typeof t.instance_id=="string"&&t.instance_id&&ss(t.instance_id,e),W(`werkzeug ${e}: Zugang und Tarif geklaert`);const o=await Io(e,t,H,P);if(W(`werkzeug ${e}: Brain-Werkzeug fertig`),o!==null){typeof t.instance_id=="string"&&t.instance_id&&is(t.instance_id,e,String(o??"")),!_e&&y&&(_e=!0,ht("first_call_success")||(yt("first_call_success"),S("first_call_success",{tool:e,instance_id:t.instance_id??N??""})));const i=t.instance_id??N??"",d=y?{api_key:y,instance_id:i}:{instance_id:i};if(e==="recall_best_solution")S("recall_best_solution",d);else if(e==="learn_from_attempts")S("learn_from_attempts",d);else if(e==="session_start"){S("session_start",d,{born_at:void 0,recalls_total:void 0,starter_seeded:!1});const h=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),T=h.includes("Welcome! Your AI Brain is live.");if(!$n(i)){if(!T&&h.length>100)S("recall_best_solution",d);else if(T&&t.workspace_path&&await as(i))try{const E=await je("brain_from_git",{instance_id:i,repo_path:t.workspace_path,limit:50},H,P);if(E!==null){S("brain_from_git",{...d,...we??{}}),S("recall_best_solution",d);let C="";if((we?.total??0)===0)try{const O=await Ne("brain_seed_starter",{instance_id:i},H,P);O&&(S("brain_seed_starter",{...d,auto:!0},{seeded_count:16,auto:!0}),C=`
|
|
35
35
|
---
|
|
36
36
|
`+String(O))}catch{}const I=String(E),$=we?.total??0,k=$>0?`
|
|
37
37
|
\u2705 **Brain bootstrapped from git \u2014 ${$} lesson${$===1?"":"s"} loaded.** Your AI already knows your history.`:"";if(I||C||k)return String(o)+k+`
|
|
@@ -42,13 +42,13 @@ cachly: code ${t.userCode}
|
|
|
42
42
|
> Run \`brain_from_git(instance_id="`+i+'", repo_path="'+String(t.workspace_path)+'")` manually to seed it.\n> Or try `brain_seed_starter` to load 16 universal engineering lessons instantly.'}}}else if(e==="session_end")S("session_end",d);else if(e==="smart_recall"){const h=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),T=h.length>50&&!h.includes("No lessons found")&&!h.includes("no lessons")&&!h.includes("No matches found");if(S("smart_recall",d,{hit:T,topic:String(t.query??"").slice(0,80)}),T&&S("recall_best_solution",d),ae&&typeof o=="string")return`> \u26A0\uFE0F **Brain auth degraded** \u2014 ${ae.split(`
|
|
43
43
|
`)[0]}
|
|
44
44
|
|
|
45
|
-
${o}`}return o}const c=await Ro(e,t,H,
|
|
45
|
+
${o}`}return o}const c=await Ro(e,t,H,P);if(c!==null)return!_e&&y&&(_e=!0,ht("first_call_success")||(yt("first_call_success"),S("first_call_success",{tool:e,instance_id:t.instance_id??N??""}))),c;const r=await jo(e,t,H,P);if(r!==null)return r;const a=await Bo(e,t,H,P);if(a!==null)return a;const u=i=>n?i+n:i,m=await Lo(e,t,H,P);if(m!==null)return u(m);const l=await Oo(e,t,H,P);if(l!==null)return l;const g=await No(e,t,H,P);if(g!==null)return u(g);const w=await Po(e,t,H,P);if(w!==null){if(e==="brain_predict"){const i=t.instance_id??N??"";S("brain_predict",y?{api_key:y,instance_id:i}:{instance_id:i})}return u(w)}const v=await Ne(e,t,H,P);if(v!==null)return v;const b=await Yn(e,t,H,P);if(b!==null)return b;const p=await je(e,t,H,P);if(p!==null){const i=t.instance_id??N??"",d=y?{api_key:y,instance_id:i}:{instance_id:i};if(e==="brain_from_git"){const h=we;S("brain_from_git",{...d,...h??{}},h?{fixes:h.fixes,features:h.features,refactors:h.refactors,total:h.total}:void 0)}else e==="brain_predict_failures"&&S("brain_predict_failures",d);return p}switch(e){case"get_api_status":{let i="unknown";try{const E=await fetch(`${x}/health`,{signal:AbortSignal.timeout(8e3)});if(E.ok){const A=await E.json();i=`${A.status??"ok"} (db: ${A.db??"?"})`}else i=`HTTP ${E.status}`}catch(E){i=`unreachable: ${E.message}`}if(!y)return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${x}`,` \u{1F493} Health: ${i}`," \u{1F511} Auth: \u274C CACHLY_JWT not set","",`\u{1F4A1} Get your API token at ${j("/instances","api-status")} \u2192 Settings \u2192 API Token`].join(`
|
|
46
46
|
`);let d="\u274C invalid JWT format";try{const E=y.split(".");if(E.length===3){const A=JSON.parse(Buffer.from(E[1],"base64url").toString("utf-8")),C=A.sub??"(unknown)",I=A.iss??"(unknown)",$=I.includes("keycloak")?"Keycloak":"OIDC",k=A.exp?new Date(A.exp*1e3):null,O=k?k<new Date:!1;d=["\u2705 JWT decoded",` Sub (user ID): ${C}`,` Provider: ${$}`,` Issuer: ${I}`,` Expires: ${k?k.toISOString():"never"} ${O?"\u26A0\uFE0F EXPIRED \u2013 get a new token!":"\u2705"}`].join(`
|
|
47
|
-
`)}}catch{d="\u274C JWT decode failed \u2013 check CACHLY_JWT format"}let h="";try{const A=(await
|
|
47
|
+
`)}}catch{d="\u274C JWT decode failed \u2013 check CACHLY_JWT format"}let h="";try{const A=(await P("/api/v1/instances")).data??[];if(A.length===0)h=`
|
|
48
48
|
|
|
49
49
|
\u{1F9E0} **Brain Instances:** none \u2014 create one at ${j("/instances","api-status")}`;else{const C=[`
|
|
50
50
|
|
|
51
|
-
\u{1F9E0} **Brain Instances:**`];for(const I of A){const $=I.status==="running"?"\u{1F7E2}":I.status==="provisioning"?"\u{1F7E1}":"\u{1F534}",k=I.id===
|
|
51
|
+
\u{1F9E0} **Brain Instances:**`];for(const I of A){const $=I.status==="running"?"\u{1F7E2}":I.status==="provisioning"?"\u{1F7E1}":"\u{1F534}",k=I.id===N?" \u2190 active":"";if(C.push(` ${$} **${I.name}** (\`${I.id}\`) \xB7 ${I.status}${k}`),I.status==="running"&&I.host){const O=ne.get(I.id);if(O)try{await O.ping(),C.push(" \u{1F493} Redis: connected")}catch{C.push(" \u26A0\uFE0F Redis: pooled but ping failed \u2014 will reconnect on next use")}else C.push(" \u{1F4A4} Redis: not connected yet (connects on first tool use)")}else I.status==="provisioning"?C.push(" \u23F3 Still provisioning \u2014 check back in ~30 s"):I.status!=="running"&&C.push(` \u274C Not reachable (status: ${I.status})`)}h=C.join(`
|
|
52
52
|
`)}}catch(E){h=`
|
|
53
53
|
|
|
54
54
|
\u{1F9E0} **Brain Instances:** could not fetch \u2014 ${E.message}`}await Re();const T=Se(y),L=T.state==="long_lived"?"\u{1F6E1}\uFE0F Self-healing: \u2705 long-lived API key (won't expire silently)":T.state==="healthy"?`\u{1F6E1}\uFE0F Self-healing: \u2705 token valid${T.expiresInMs?` (${Math.round(T.expiresInMs/36e5)}h left)`:""}`:T.state==="near_expiry"?"\u{1F6E1}\uFE0F Self-healing: \u267B\uFE0F token near expiry \u2014 auto-refresh attempted":`\u{1F6E1}\uFE0F Self-healing: \u26A0\uFE0F ${T.message.split(`
|
|
@@ -60,7 +60,7 @@ ${o}`}return o}const c=await Ro(e,t,H,N);if(c!==null)return!_e&&y&&(_e=!0,ht("fi
|
|
|
60
60
|
- AFTER a fix, deploy, or discovery: call learn_from_attempts so the knowledge persists.
|
|
61
61
|
- BEFORE a risky op (deploy, migration, dependency bump): call brain_predict.
|
|
62
62
|
|
|
63
|
-
The Brain instance id comes from the CACHLY_BRAIN_INSTANCE_ID environment variable.`,kt={tools:{},resources:{},prompts:{}},St=async()=>{const{katalog:e,unbekannteKernnamen:t}=
|
|
63
|
+
The Brain instance id comes from the CACHLY_BRAIN_INSTANCE_ID environment variable.`,kt={tools:{},resources:{},prompts:{}},St=async()=>{const{katalog:e,unbekannteKernnamen:t}=Nn(ge);return t.length>0&&console.error(`cachly: ${t.length} Kernwerkzeug(e) gibt es gar nicht: ${t.join(", ")}`),{tools:e}};async function At(){return{resources:[]}}async function Ct(){return{resourceTemplates:[]}}async function Tt(){return{prompts:[]}}function cs(e){e.setRequestHandler(Ge,St),e.setRequestHandler(We,Rt),e.setRequestHandler(qe,At),e.setRequestHandler(Ke,Ct),e.setRequestHandler(Ye,Tt)}function ls(){const e=new Fe({name:"cachly-mcp",version:D},{capabilities:kt,instructions:$t});return cs(e),Et(e),e}function Et(e){const t=e.oninitialized;e.oninitialized=()=>{try{const s=e.getClientVersion();Nt(s?.name,s?.version)}catch{}t?.()}}const V=new Fe({name:"cachly-mcp",version:D},{capabilities:kt,instructions:$t});Et(V),V.setRequestHandler(Ge,St),V.setRequestHandler(qe,At),V.setRequestHandler(Ke,Ct),V.setRequestHandler(Ye,Tt);let Pe=null,fe=!1,X=null,It=0;async function ds(e){if(!fe){if(X){await X;return}X=(async()=>{fe=!0,Pe=e;try{await z("session_start",{instance_id:e,focus:"auto (MCP session)",workspace_path:process.cwd()})}catch{}finally{X=null}})(),await X,process.env.CACHLY_AUTO_INDEX!=="false"&&(async()=>{const t=await H(e),s=await t.get(`cachly:index:last_indexed:${e}`),n=1440*60*1e3;(!s||Date.now()-parseInt(s,10)>n)&&(await t.set(`cachly:index:last_indexed:${e}`,String(Date.now()),"EX",9e4),await z("index_project",{instance_id:e,dir:process.cwd(),max_files:150,ttl:86400*7,namespace:"cachly:sem:code",hintergrund:!0}))})().catch(()=>{})}}async function He(){if(!(!fe||!Pe)){fe=!1;try{await z("session_end",{instance_id:Pe,summary:`Auto-ended after ${It} tool call(s). Session was started automatically.`,files_changed:[],lessons_learned:0})}catch{}}}const Rt=async e=>{let{name:t,arguments:s}=e.params;if(t===ft){const o=s??{},c=typeof o.tool=="string"?o.tool:"";if(!c)return{content:[{type:"text",text:'cachly_tool braucht das Feld "tool" \u2014 den Namen des Werkzeugs.'}],isError:!0};const r=ge.find(a=>a.name===c);if(!r)return{content:[{type:"text",text:`Kein Werkzeug namens "${c}". Die Liste steht in der Beschreibung von ${ft}.`}],isError:!0};if(o.describe===!0)return{content:[{type:"text",text:JSON.stringify({name:r.name,description:r.description,inputSchema:r.inputSchema},null,2)}]};t=c,s=o.arguments??{}}const n=new Set(["session_start","session_start_summary","session_end","auto_learn_session"]);if(!n.has(t)&&!fe&&!X){const o=xe(s?.instance_id)||N||xe(process.env.CACHLY_BRAIN_INSTANCE_ID);o&&await ds(o).catch(()=>{})}else X&&await X.catch(()=>{});n.has(t)||It++;try{Ln(),W(`werkzeug ${t}: Anfang`);const o=await z(t,s??{});return W(`werkzeug ${t}: Antwort fertig`),{content:[{type:"text",text:on(t,o)+Cn()+jn(t)}]}}catch(o){if(o instanceof _t)return{content:[{type:"text",text:o.message}],isError:!0};if(o instanceof te)throw o;const c=o.message??String(o);throw Je("cachly","tool_error",{tool:t,error:c}).catch(()=>{}),new te(ie.InternalError,c)}};V.setRequestHandler(We,Rt),process.on("SIGTERM",async()=>{await He().catch(()=>{});for(const[,e]of ne)await e.quit().catch(()=>{});process.exit(0)}),process.on("SIGINT",async()=>{await He().catch(()=>{});for(const[,e]of ne)await e.quit().catch(()=>{});process.exit(0)}),process.on("unhandledRejection",e=>{const t=e instanceof Error?e.message:String(e);process.stderr.write(`[cachly-mcp] unhandledRejection: ${t}
|
|
64
64
|
`)}),process.on("uncaughtException",e=>{process.stderr.write(`[cachly-mcp] uncaughtException: ${e?.stack??String(e)}
|
|
65
65
|
`)}),process.stdout.on("error",()=>{}),process.stdin.on("error",()=>{});function us(e,t){const s=Object.entries(t).map(([n,o])=>`${n}=${o}`);return e==="codex"?{befehl:`codex mcp add cachly ${s.map(n=>`--env ${n}`).join(" ")} -- npx -y @cachly-dev/mcp-server@latest`,wo:"~/.codex/config.toml"}:e==="gemini"?{befehl:`gemini mcp add -s project ${s.map(n=>`-e ${n}`).join(" ")} cachly npx -- -y @cachly-dev/mcp-server@latest`,wo:".gemini/settings.json"}:null}const jt="https://api.cachly.dev";function se(e,t,s={}){const n={CACHLY_BRAIN_INSTANCE_ID:t};return s.includeApiKey&&(n.CACHLY_JWT=e),x&&x!==jt&&(n.CACHLY_API_URL=x),n}function ps(e,t,s){return s==="continue"?JSON.stringify({experimental:{modelContextProtocolServers:[{transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:se(e,t)}]}},null,2):s==="zed"?JSON.stringify({context_servers:{cachly:{command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:se(e,t)},settings:{}}}},null,2):Bt(s)?JSON.stringify({servers:{cachly:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:se(e,t)}}},null,2):JSON.stringify({mcpServers:{cachly:{command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:se(e,t)}}},null,2)}function Bt(e){return me[e]===".vscode/mcp.json"}function he(e,t){an(e)||Q(e,t)}async function Lt(e,t,s,n,o,c={}){const r={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:se(t,s)};if(!o.existsSync(e))return ps(t,s,n);let a={};try{a=JSON.parse(await o.readFile(e,"utf-8"))}catch{try{const{rename:g}=await import("node:fs/promises");await g(e,e+".bak"),process.stderr.write(`\u26A0\uFE0F ${e} was not valid JSON \u2014 backed up to ${e}.bak
|
|
66
66
|
`)}catch{}}if(n==="continue"){const g=a.experimental??{},w=g.modelContextProtocolServers??[];let v;for(const p of w){const i=p.env??{};if(i.CACHLY_JWT){v=i.CACHLY_JWT;break}}v&&he(v,c);const b=w.filter(p=>{const i=p.env??{};return!i.CACHLY_JWT&&!i.CACHLY_BRAIN_INSTANCE_ID});return b.push({transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:r.env}),a.experimental={...g,modelContextProtocolServers:b},JSON.stringify(a,null,2)}if(n==="zed"){const g=a.context_servers??{},v=g.cachly?.command?.env?.CACHLY_JWT;return v&&he(v,c),g.cachly={command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:r.env},settings:{}},a.context_servers=g,JSON.stringify(a,null,2)}if(Bt(n)){const g=a.mcpServers??void 0,v=g?.cachly?.env?.CACHLY_JWT;v&&he(v,c),g&&"cachly"in g&&(delete g.cachly,Object.keys(g).length===0&&delete a.mcpServers);const b=a.servers??{},p=b.cachly,i=p?.env?.CACHLY_JWT;return i&&he(i,c),b.cachly=p?.envFile?{type:"stdio",...r,envFile:p.envFile}:{type:"stdio",...r},a.servers=b,JSON.stringify(a,null,2)}const u=a.mcpServers??{},l=u.cachly?.env?.CACHLY_JWT;return l&&he(l,c),u.cachly=r,a.mcpServers=u,JSON.stringify(a,null,2)}function ms(e){return`${st}
|
|
@@ -135,7 +135,7 @@ ${it}`}async function Ot(e,t){const{existsSync:s}=await import("node:fs"),{resol
|
|
|
135
135
|
\u{1F4E4} Exporting your Brain...
|
|
136
136
|
|
|
137
137
|
`);try{let m=[],l="";const g=await fetch(`${x}/api/v1/instances/${u}/export`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(12e4)});if(g.ok){const v=await g.json();m=(v.lessons??[]).map(Mn).filter(b=>b!==null),v.complete===!1&&(l=v.note??"the server reported an incomplete read")}else if(g.status===404){const v=await fetch(`${x}/api/v1/instances/${u}/memory`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(8e3)});if(!v.ok)throw new Error(`memory HTTP ${v.status}`);m=((await v.json()).top_lessons??[]).map(p=>({topic:p.topic,outcome:p.outcome,severity:p.severity,tags:p.tags,whatWorked:p.what_worked,ts:p.ts,author:p.author,recallCount:p.recall_count})),l="this server has no /export endpoint yet, so this is the DASHBOARD SUMMARY: at most 50 lessons, each shortened to 120 characters. Update the server for a full export."}else throw new Error(`export HTTP ${g.status}`);m.length===0&&(console.log(` No lessons in this Brain yet \u2014 nothing to export.
|
|
138
|
-
`),process.exit(0)),await t(r,{recursive:!0});const w=[];if(c==="md"||c==="both"){const v=s(r,"lessons.md");await e(v,
|
|
138
|
+
`),process.exit(0)),await t(r,{recursive:!0});const w=[];if(c==="md"||c==="both"){const v=s(r,"lessons.md");await e(v,Pn(m),"utf-8"),w.push(`${m.length} lesson${m.length===1?"":"s"} \u2192 ${v}`)}if(c==="jsonl"||c==="both"){const v=s(r,"lessons.jsonl");await e(v,Hn(m),"utf-8"),w.push(`${m.length} lesson${m.length===1?"":"s"} \u2192 ${v}`)}l?(console.log("\u26A0\uFE0F Export INCOMPLETE \u2014 this is not your whole Brain:"),console.log(` ${l}`),console.log("")):console.log("\u2705 Export complete:");for(const v of w)console.log(` ${v}`);console.log("")}catch(m){console.log(`
|
|
139
139
|
\u274C Could not export your Brain: ${m.message}
|
|
140
140
|
`),process.exit(1)}process.exit(0)}if(process.argv[2]==="invite"){const e=oe();e||(console.log(`
|
|
141
141
|
\u26A0\uFE0F No cachly key found (environment or ~/.cachly/credentials.json).`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
|
|
@@ -222,7 +222,7 @@ Usage: npx @cachly-dev/mcp-server@latest init --instance-id <uuid> --api-key <ck
|
|
|
222
222
|
`),process.exit(1));const v=us(l,se(m,u));if(v)Q(m),console.log(`
|
|
223
223
|
\u{1F449} Register the MCP server once (writes ${v.wo}):`),console.log(` ${v.befehl}`);else{const i=me[l]??".mcp.json",d=o(g,i);await s(c(d),{recursive:!0});const{existsSync:h}=await import("node:fs"),T=h(d),L=T?await n(d,"utf-8").catch(()=>""):"";Q(m);const E=await Lt(d,m,u,l,{readFile:n,existsSync:h});E!==L?(await t(d,E,"utf-8"),console.log(`
|
|
224
224
|
\u2705 ${T?"Updated":"Written"}: ${i}`)):console.log(`
|
|
225
|
-
\u2713 Already configured: ${i} (no change)`)}const b=await Ot(g,u);for(const[i,d]of Object.entries(b)){const h=d==="updated"?"\u2705 Updated":d==="appended"?"\u2705 Appended to":"\u2705 Written",T=i.split(/[\\/]/).pop()??i;console.log(`${h}: ${T}`)}try{const i=await ot(g,u);i==="written"?console.log("\u2705 Written: .git/hooks/post-commit (CLS hook)"):i==="upgraded"?console.log(`\u2705 Upgraded: .git/hooks/post-commit (CLS hook \u2192 ${nt})`):i==="appended"?console.log("\u2705 Appended: .git/hooks/post-commit (CLS hook)"):i==="unchanged"&&console.log("\u2713 CLS hook already current in .git/hooks/post-commit")}catch{}if(l==="claude")try{const i=await at(g,u),d=i.scripts==="written"?"\u2705 Written":i.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${ct})`:"\u2713 Unchanged";console.log(`${d}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),i.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):i.settings==="merged"?console.log("\u2705 Merged: .claude/settings.json (Ambient Recall hooks wired)"):console.log("\u2713 Ambient Recall hooks already wired in .claude/settings.json")}catch{}(l==="cursor"||l==="copilot"||l==="codex"||l==="gemini")&&await ye(l,g,u,"");const p=((Date.now()-e)/1e3).toFixed(1);console.log(`
|
|
225
|
+
\u2713 Already configured: ${i} (no change)`)}const b=await Ot(g,u);for(const[i,d]of Object.entries(b)){const h=d==="updated"?"\u2705 Updated":d==="appended"?"\u2705 Appended to":"\u2705 Written",T=i.split(/[\\/]/).pop()??i;console.log(`${h}: ${T}`)}try{const i=await ot(g,u);i==="written"?console.log("\u2705 Written: .git/hooks/post-commit (CLS hook)"):i==="upgraded"?console.log(`\u2705 Upgraded: .git/hooks/post-commit (CLS hook \u2192 ${nt})`):i==="appended"?console.log("\u2705 Appended: .git/hooks/post-commit (CLS hook)"):i==="unchanged"&&console.log("\u2713 CLS hook already current in .git/hooks/post-commit")}catch{}if(l==="claude")try{const i=await at(g,u);if(i.settings==="skipped")console.log(`\u26A0\uFE0F .claude/settings.json ${i.grund??"is not valid JSON"} \u2014 left untouched, Ambient Recall hooks not wired`);else{const d=i.scripts==="written"?"\u2705 Written":i.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${ct})`:"\u2713 Unchanged";console.log(`${d}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),i.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):i.settings==="merged"?console.log("\u2705 Merged: .claude/settings.json (Ambient Recall hooks wired)"):console.log("\u2713 Ambient Recall hooks already wired in .claude/settings.json")}}catch{}(l==="cursor"||l==="copilot"||l==="codex"||l==="gemini")&&await ye(l,g,u,"");const p=((Date.now()-e)/1e3).toFixed(1);console.log(`
|
|
226
226
|
\u{1F9E0} Cachly AI Brain configured for ${l==="claude"?"Claude Code":l}! (${p}s)`),console.log(v?` Run the \`mcp add\` line above, then restart ${l} \u2014 the \`cachly\` MCP tools will appear.`:" Restart your editor \u2014 the `cachly` MCP tools will appear."),console.log(" Re-run `init` anytime \u2014 it's idempotent (only writes what changed)."),console.log(`
|
|
227
227
|
\u{1F4DB} Add a live badge to your README:`),console.log(` npx @cachly-dev/mcp-server@latest badge
|
|
228
228
|
`),process.exit(0)}if(process.argv[2]==="status"){const e=oe(),t=F();(!e||!t)&&(console.log(`
|
|
@@ -312,7 +312,7 @@ Could not create an instance automatically. Opening ${j("/instances",u)} \u2026
|
|
|
312
312
|
`)}catch{}}try{const f=await ot(process.cwd(),i.id);f==="written"?console.log(`
|
|
313
313
|
\u2705 CLS git hook installed \u2014 your brain will learn from every commit.`):f==="upgraded"?console.log(`
|
|
314
314
|
\u2705 CLS git hook upgraded to ${nt}.`):f==="appended"&&console.log(`
|
|
315
|
-
\u2705 CLS git hook appended to existing post-commit.`)}catch{}if(I.includes("claude"))try{const f=await at(process.cwd(),i.id),_=f.scripts==="written"?"\u2705 Written":f.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${ct})`:"\u2713 Unchanged";console.log(`${_}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),f.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):f.settings==="merged"?console.log("\u2705 Merged: .claude/settings.json (Ambient Recall hooks wired)"):console.log("\u2713 Ambient Recall hooks already wired in .claude/settings.json")}catch{}I.includes("cursor")&&await ye("cursor",process.cwd(),i.id," "),I.includes("copilot")&&await ye("copilot",process.cwd(),i.id," "),(n(o(L,".codex"))||n(o(d,".codex")))&&await ye("codex",process.cwd(),i.id," "),(n(o(L,".gemini"))||n(o(d,".gemini")))&&await ye("gemini",process.cwd(),i.id," "),y=b;const Me=Math.round((Date.now()-a)/1e3);if(k.length>0&&S("setup_config_write_failed",{instance_id:i.id,failed:k.length,succeeded:O}),S("setup_completed",{instance_id:i.id,elapsed_s:Me,config_failures:k.length}),k.length>0&&O===0){console.log(`
|
|
315
|
+
\u2705 CLS git hook appended to existing post-commit.`)}catch{}if(I.includes("claude"))try{const f=await at(process.cwd(),i.id);if(f.settings==="skipped")console.log(`\u26A0\uFE0F .claude/settings.json ${f.grund??"is not valid JSON"} \u2014 left untouched, Ambient Recall hooks not wired`);else{const _=f.scripts==="written"?"\u2705 Written":f.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${ct})`:"\u2713 Unchanged";console.log(`${_}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),f.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):f.settings==="merged"?console.log("\u2705 Merged: .claude/settings.json (Ambient Recall hooks wired)"):console.log("\u2713 Ambient Recall hooks already wired in .claude/settings.json")}}catch{}I.includes("cursor")&&await ye("cursor",process.cwd(),i.id," "),I.includes("copilot")&&await ye("copilot",process.cwd(),i.id," "),(n(o(L,".codex"))||n(o(d,".codex")))&&await ye("codex",process.cwd(),i.id," "),(n(o(L,".gemini"))||n(o(d,".gemini")))&&await ye("gemini",process.cwd(),i.id," "),y=b;const Me=Math.round((Date.now()-a)/1e3);if(k.length>0&&S("setup_config_write_failed",{instance_id:i.id,failed:k.length,succeeded:O}),S("setup_completed",{instance_id:i.id,elapsed_s:Me,config_failures:k.length}),k.length>0&&O===0){console.log(`
|
|
316
316
|
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`),console.log("\u2551 \u26A0\uFE0F Setup incomplete \u2014 no editor config was written \u2551"),console.log("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),console.log(`
|
|
317
317
|
Your Brain instance exists, but no editor knows about it yet.`),console.log(" Failed writes:");for(const f of k)console.log(` \u2022 ${f.file} \u2014 ${f.reason}`);console.log(`
|
|
318
318
|
Fix the permissions above and re-run, or configure manually:`),console.log(` CACHLY_JWT=${b.slice(0,12)}\u2026 CACHLY_BRAIN_INSTANCE_ID=${i.id}`),console.log(` Docs: ${j("/docs/mcp",u)}
|
|
@@ -336,10 +336,10 @@ Could not create an instance automatically. Opening ${j("/instances",u)} \u2026
|
|
|
336
336
|
\u2705 Brain learned from your commits.
|
|
337
337
|
`),await new Promise(a=>setTimeout(a,300))}catch(r){console.error(`
|
|
338
338
|
\u274C learn-git failed: ${r.message}
|
|
339
|
-
`),process.exit(1)}process.exit(0)}if(process.argv[2]==="ambient-recall"&&await Qo(process.argv.slice(3),process.argv[1]),process.argv[2]==="ambient-auffrischen"&&await Xo(),process.argv[2]===tn&&await en(process.argv[3]??""),process.argv[2]==="ambient-credit"){try{const e=Math.round(Number(process.argv[3]));if(Number.isFinite(e)&&e>0){const t=Math.min(e,2e4),s=process.argv.slice(4).join(" ").slice(0,200)||void 0,n={ts:new Date().toISOString(),event:"credit",injected:0,prevented:t,note:s};await nn(n),await Qn(process.env.CACHLY_BRAIN_INSTANCE_ID??
|
|
339
|
+
`),process.exit(1)}process.exit(0)}if(process.argv[2]==="ambient-recall"&&await Qo(process.argv.slice(3),process.argv[1]),process.argv[2]==="ambient-auffrischen"&&await Xo(),process.argv[2]===tn&&await en(process.argv[3]??""),process.argv[2]==="ambient-credit"){try{const e=Math.round(Number(process.argv[3]));if(Number.isFinite(e)&&e>0){const t=Math.min(e,2e4),s=process.argv.slice(4).join(" ").slice(0,200)||void 0,n={ts:new Date().toISOString(),event:"credit",injected:0,prevented:t,note:s};await nn(n),await Qn(process.env.CACHLY_BRAIN_INSTANCE_ID??N,n),console.log(`\u2705 ambient credit recorded: ${t} tokens${s?` (${s})`:""}`)}else console.error("Usage: npx @cachly-dev/mcp-server@latest ambient-credit <tokens-saved> [note]")}catch{}process.exit(0)}if(process.argv[2]==="ambient-stats"){const e=await lt(),t=Wn(e),s=e.slice(-5);if(console.log(`
|
|
340
340
|
\u{1F9E0} Ambient Recall \u2014 net-token ledger
|
|
341
341
|
`),console.log(` Turns recorded: ${e.length}`),console.log(` Injected tokens: ${t.injected}`),console.log(` Prevented tokens: ${t.prevented} (agent-reported via ambient-credit)`),console.log(` NET: ${t.net>=0?"+":""}${t.net} tokens`),s.length>0){console.log(`
|
|
342
|
-
Last entries:`);for(const n of s){const o=n.prevented>0?`+${n.prevented} prevented`:`-${n.injected} injected`;console.log(` \u2022 ${n.ts.slice(0,19)} ${n.event}: ${o}${n.note?` (${n.note})`:""}`)}}console.log(""),process.exit(0)}if(process.argv[2]==="uninstall"){const{homedir:e,tmpdir:t}=await import("node:os"),{resolve:s}=await import("node:path"),{createInterface:n}=await import("node:readline/promises"),o=process.argv.slice(3),r={projekt:s((a=>{const u=o.indexOf(`--${a}`);return u!==-1?o[u+1]:void 0})("project-dir")??"."),heim:process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??e(),tmp:t(),schluessel:oe(),instanz:F(),apiUrl:x,istTty:process.stdin.isTTY===!0&&process.stdout.isTTY===!0,ausgabe:a=>console.log(a),frage:async a=>{const u=n({input:process.stdin,output:process.stdout});try{return/^(y|yes|j|ja)$/i.test((await u.question(a)).trim())}finally{u.close()}}};process.exit(await Jo(o,r))}if(process.argv[2]==="doctor"){const{checkNodeVersion:e,checkCredential:t,checkApiReachable:s,checkAuthAccepted:n,checkInstance:o,checkVectorCoverage:c,inspectAmbientHooks:r,checkHooks:a,checkLedger:u,renderDoctorReport:m,doctorExitCode:l}=await import("./doctor.js"),g=[e(),t(y),await s(x),await n(x,y),o(F()||
|
|
342
|
+
Last entries:`);for(const n of s){const o=n.prevented>0?`+${n.prevented} prevented`:`-${n.injected} injected`;console.log(` \u2022 ${n.ts.slice(0,19)} ${n.event}: ${o}${n.note?` (${n.note})`:""}`)}}console.log(""),process.exit(0)}if(process.argv[2]==="uninstall"){const{homedir:e,tmpdir:t}=await import("node:os"),{resolve:s}=await import("node:path"),{createInterface:n}=await import("node:readline/promises"),o=process.argv.slice(3),r={projekt:s((a=>{const u=o.indexOf(`--${a}`);return u!==-1?o[u+1]:void 0})("project-dir")??"."),heim:process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??e(),tmp:t(),schluessel:oe(),instanz:F(),apiUrl:x,istTty:process.stdin.isTTY===!0&&process.stdout.isTTY===!0,ausgabe:a=>console.log(a),frage:async a=>{const u=n({input:process.stdin,output:process.stdout});try{return/^(y|yes|j|ja)$/i.test((await u.question(a)).trim())}finally{u.close()}}};process.exit(await Jo(o,r))}if(process.argv[2]==="doctor"){const{checkNodeVersion:e,checkCredential:t,checkApiReachable:s,checkAuthAccepted:n,checkInstance:o,checkVectorCoverage:c,inspectAmbientHooks:r,checkHooks:a,checkLedger:u,renderDoctorReport:m,doctorExitCode:l}=await import("./doctor.js"),g=[e(),t(y),await s(x),await n(x,y),o(F()||N),await c(x,y,F()||N),a(r(process.cwd())),u(await lt(),sn())];console.log(m(g)),process.exit(l(g))}if(process.argv[2]==="cls-ingest"){try{const e=process.argv[3];(!e||!y)&&process.exit(0);let t;try{t=JSON.parse(e)}catch{process.exit(0)}const s=t.instance_id??N;(!s||!t.source)&&process.exit(0),await z("cls_ingest",{instance_id:s,source:t.source,payload:t.payload??{}})}catch{}process.exit(0)}if(!y){const e=Dt();if(e)try{const t=await fetch(Jt(e),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:Ut(e),signal:AbortSignal.timeout(8e3)});if(t.ok){const s=await t.json();s.access_token&&(y=s.access_token,le(s.access_token),S("m2m_auth_completed",{grant:"client_credentials",client_id:e.clientId}),process.stderr.write(`\u{1F916} cachly: authenticated via client_credentials (M2M, headless).
|
|
343
343
|
`))}else process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth failed (${t.status}). Check CACHLY_CLIENT_ID / CACHLY_CLIENT_SECRET.
|
|
344
344
|
`),S("m2m_auth_failed",{status:t.status})}catch(t){process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth error: ${t.message}
|
|
345
345
|
`),S("m2m_auth_failed",{reason:"network"})}}const hs=["demo","share","publish","health","autosetup","setup","autopilot","init","digest","invite","badge","join","upgrade","bench","tool-specs","openapi","ambient-credit","ambient-stats","doctor","uninstall"];if(!y&&!hs.includes(process.argv[2]??""))if(!process.argv[2]&&process.stdout.isTTY===!0&&Gt){const n=`
|
|
@@ -362,7 +362,7 @@ Could not create an instance automatically. Opening ${j("/instances",u)} \u2026
|
|
|
362
362
|
\u{1F9E0} cachly: no API key yet \u2014 the first cachly tool call creates a test Brain on EU servers, no sign-up.
|
|
363
363
|
(Own account: npx @cachly-dev/mcp-server@latest autopilot)
|
|
364
364
|
|
|
365
|
-
`);else{const e=
|
|
365
|
+
`);else{const e=Pt(y);if(e!==null){const t=Math.floor((e-Date.now())/6e4);t<=0?process.stderr.write(`
|
|
366
366
|
\u26A0\uFE0F cachly: CACHLY_JWT expired ${Math.abs(t)} minute(s) ago.
|
|
367
367
|
All tool calls will fail. Get a fresh token at ${j("/setup-ai","jwt-expiry")}
|
|
368
368
|
|
package/dist/src/tools.js
CHANGED
|
@@ -7,4 +7,4 @@ Layer 3 \u2014 Autopilot: generates a copilot-instructions.md / .github/copilot-
|
|
|
7
7
|
and save lessons AFTER \u2014 fully automatic, zero manual effort.
|
|
8
8
|
|
|
9
9
|
Returns the copilot-instructions.md content + provider-specific .mcp.json snippet.
|
|
10
|
-
Optionally writes copilot-instructions.md directly to the project directory.`,inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cachly instance to use as the AI brain"},project_dir:{type:"string",description:"Absolute path to the project root. If provided, puts the cachly block into .github/copilot-instructions.md (and CLAUDE.md, .cursor/rules/cachly.mdc, .windsurfrules when that editor is in use). Text outside the cachly markers is kept."},embed_provider:{type:"string",enum:["openai","mistral","cohere","ollama","gemini"],description:"Embedding provider to use for smart_recall / semantic search. Default: openai. Use ollama for fully local/free setup."},project_description:{type:"string",description:"Short description of the project (used in the generated instructions)"}},required:[]}},{name:"cache_stream_set",description:"Cache a list of string chunks (e.g. LLM token stream) via Redis RPUSH. Each chunk is stored as a separate list element under cachly:stream:{key}. Replay with cache_stream_get.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},key:{type:"string",description:"Cache key"},chunks:{type:"array",items:{type:"string"},description:"Ordered list of string chunks"},ttl:{type:"number",description:"TTL in seconds for the stored list (optional)"}},required:["key","chunks"]}},{name:"cache_stream_get",description:"Retrieve a previously cached stream as an ordered list of string chunks. Returns null on cache miss (key absent or empty list). Stored under cachly:stream:{key}.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},key:{type:"string",description:"Cache key"}},required:["key"]}},{name:"cache_org_stats",description:"Show shared cache statistics for an org namespace. Scans all keys under org:{org_id}:sem:* and reports how many entries are shared. Use this to verify org-sharing is working and to monitor cross-instance cache utilization. Also aggregates org-wide ROI via the Cachly API: total cache hits, hits in the last 24h, estimated total and projected monthly USD savings across all org instances, plus a per-instance breakdown. Zero-config: no API changes required \u2014 any cache_set call with org_id writes to this namespace.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},org_id:{type:"string",description:'Org ID to inspect (e.g. "acme", "my-company")'}},required:["org_id"]}},{name:"set_cost_per_call",description:"Set the assumed cost per avoided LLM API call (USD) for this instance. This is used to compute accurate ROI savings estimates in cache_stats. The default ($0.002) is calibrated for a small model (gpt-5.5-mini class). Set your actual model cost for accurate numbers: claude-opus-4.8 \u2192 $0.02, gpt-5.5 \u2192 $0.015, claude-sonnet-4.6 \u2192 $0.009, claude-haiku-4.5 \u2192 $0.001. After updating, cache_stats will show savings computed from your real cost. Use list_instances to find your instance_id.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},cost_per_call_usd:{type:"number",description:"Cost per LLM API call in USD. Common values: 0.02 (claude-opus-4.8), 0.015 (gpt-5.5), 0.009 (claude-sonnet-4.6), 0.002 (gpt-5.5-mini), 0.001 (claude-haiku-4.5)."}},required:["cost_per_call_usd"]}},{name:"memory_consolidate",description:"Cognitive memory consolidation \u2014 the weekly garbage collector for your AI Brain. Scans all lessons, detects contradictions (same topic with conflicting outcomes), names possible duplicates by meaning (same content under a different topic, cosine \u2265 0.80), flags stale entries (not recalled in 90+ days), and computes a health score. Never merges or deletes a lesson; link two with `ersetzt` on learn_from_attempts. Run weekly or when brain_doctor reports > 20 lessons. Like git gc for knowledge.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},dry_run:{type:"boolean",description:"If true, report what would change without writing (default: false)"},stale_days:{type:"number",description:"Lessons not recalled in this many days are flagged stale (default: 90)"}},required:[]}},{name:"brain_diff",description:'git log for your AI Brain \u2014 see exactly what changed since a point in time. Returns a structured changelog: new lessons added, lessons updated (outcome changed), lessons recalled (hit count increased), and lessons that decayed. Perfect for weekly reviews: "What did my AI learn this week?" Example: brain_diff(instance_id="...", since="7d") \u2192 "12 new \xB7 4 updated \xB7 2 stale"',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},since:{type:"string",description:'Time window: "1d", "7d", "30d", or ISO-8601 date (default: "7d")'},format:{type:"string",enum:["summary","detailed"],description:"Output format (default: summary)"}},required:[]}},{name:"causal_trace",description:'Root Cause Analysis through memory: given a problem description, traces the causal chain from root cause through intermediate failures to the current symptom, then surfaces the exact solution that worked before. Read-only \u2014 does not modify any stored data. Requires prior learning: brain must have lessons stored via learn_from_attempts or brain_from_git. Returns an ordered chain of concepts with confidence scores plus the matching solution; returns an empty chain with a message if no causal path is found. Example: causal_trace(problem="auth breaks after restart") \u2192 "Root: k8s:namespace-terminating \u2192 keycloak:jwks-race \u2192 Solution: PollUntilContextTimeout 3min". Use recall_best_solution for direct topic lookup, syndicate_search for community patterns, and causal_trace when you have a symptom and need the full root-cause chain.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},problem:{type:"string",description:"Describe the problem or error you are seeing right now"},max_depth:{type:"number",description:"Max causal chain depth to trace (default: 5)"},tags:{type:"array",items:{type:"string"},description:"Optional: narrow search to these tags"}},required:["problem"]}},{name:"knowledge_decay",description:'Confidence scoring for every lesson in your Brain \u2014 because old knowledge rots. Computes a decay score (0\u2013100%) per lesson based on age, recall frequency, and outcome. Lessons recalled recently score high. Lessons from 90 days ago never recalled score low. Returns a ranked list with visual confidence bars: "\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591 40%". Use this before a big refactor to know which lessons to trust and which to re-validate.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},min_age_days:{type:"number",description:"Only include lessons older than N days (default: 0 = all)"},show_top:{type:"number",description:"Number of entries to return, sorted by lowest confidence first (default: 20)"}},required:[]}},{name:"autopilot",description:'Generate a CLAUDE.md / copilot-instructions.md that makes any AI self-managing forever. Writes a configuration file to disk \u2014 will overwrite an existing file at the target path. No auth required beyond a valid instance_id. The generated file instructs Claude, Cursor, Copilot, Windsurf, or Gemini to automatically call session_start at window open, learn_from_attempts after every fix, and session_end before closing \u2014 without being asked. Returns the generated file content as a string and the path where it was written. Use style="minimal" for just the three hooks; style="full" for the complete ruleset with examples. One command. Every AI. Always on. Use setup_ai_memory instead if you want an interactive one-shot setup that also creates an instance.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},editor:{type:"string",enum:["claude","cursor","copilot","windsurf","gemini","continue","all"],description:"Target editor (default: claude)"},project_name:{type:"string",description:"Your project name (used in generated instructions)"},style:{type:"string",enum:["minimal","full"],description:"minimal = just the hooks, full = full ruleset with examples (default: full)"}},required:[]}},{name:"syndicate",description:'Contribute a verified lesson to the GLOBAL Cachly Knowledge Commons \u2014 a privacy-preserving shared brain where every AI instance can learn from the discoveries of every other. Your contributor identity is a one-way HMAC hash: completely anonymous. The lesson is immediately searchable by any other AI using syndicate_search. This is how individual knowledge becomes collective intelligence. Call this AFTER every learn_from_attempts that is worth sharing universally (critical bugs, deployment gotchas, architecture discoveries). If a lesson with the same topic already exists in the commons, it is updated in place (idempotent). Returns { key, confirm_count, scope } confirming the stored lesson. Use scope="org" to keep the lesson private to your organisation. Do NOT use for secrets or PII \u2014 content is stored in a shared knowledge base.',inputSchema:{type:"object",properties:{topic:{type:"string",description:'Topic key in category:keyword format (e.g. "fix:clickhouse-ipv6", "deploy:docker-compose")'},outcome:{type:"string",enum:["success","failure","partial"],description:"Result of the attempt (default: success)"},what_worked:{type:"string",description:"Exact approach, command, or fix that worked. File paths are stripped automatically."},what_failed:{type:"string",description:"What failed or was wrong \u2014 helps others avoid the same trap."},severity:{type:"string",enum:["critical","major","minor"],description:"How severe the issue was (default: minor)"},tags:{type:"array",items:{type:"string"},description:"Up to 10 keywords for better discoverability"},scope:{type:"string",enum:["public","org"],description:'Visibility: "public" = global commons (default), "org" = private to your org only'}},required:["topic","what_worked"]}},{name:"syndicate_search",description:'Search the GLOBAL Cachly Knowledge Commons for solutions contributed by the entire community. Returns lessons ranked by confirm_count (trust score) then recency. Use this BEFORE debugging any unknown issue \u2014 someone in the global brain likely solved it already. Example: syndicate_search(q="clickhouse localhost connection refused") \u2192 "fix: use 127.0.0.1 not localhost when IPv6 is disabled \xB7 confirmed by 47 instances"',inputSchema:{type:"object",properties:{q:{type:"string",description:"Free-text search query (leave empty for most recent lessons)"},category:{type:"string",description:'Filter by category prefix: "fix", "deploy", "debug", "infra", "api", "web"'},scope:{type:"string",enum:["public","org"],description:'"public" = global commons (default), "org" = public + your org-private lessons'},limit:{type:"number",description:"Max results to return (default: 20, max: 50)"}},required:[]}},{name:"syndicate_stats",description:"Show the health of the global Knowledge Commons: total lessons, total confirms, top categories, most-trusted lessons, growth in the last 7 days, and top contributors (anonymous scores). Use for weekly reviews or to explore what the community knows.",inputSchema:{type:"object",properties:{},required:[]}},{name:"syndicate_trending",description:"Show the TRENDING lessons in the global Knowledge Commons \u2014 those with the fastest confirmation velocity in the last 7 days (confirm_count / age_in_days). Use this at the start of a session or weekly review to see what the community is actively validating. Lessons need at least 2 independent confirms to appear here.",inputSchema:{type:"object",properties:{limit:{type:"number",description:"Max results (default: 10, max: 50)"}},required:[]}},{name:"brain_marketplace",description:'Browse the Domain Brain marketplace \u2014 curated, installable packs of high-trust community lessons, grouped by domain (Kubernetes, Auth, Database, React, Payments, \u2026). Each brain is built from verified, community-confirmed lessons in the global Knowledge Commons. Use at onboarding or when starting work in an unfamiliar domain to bootstrap your Brain instantly. Install one with brain_install(slug="..."). Example: brain_marketplace() \u2192 "\u2638\uFE0F Kubernetes Incident Brain \xB7 42 lessons \xB7 install: brain_install(slug=\\"k8s\\")".',inputSchema:{type:"object",properties:{min_confirms:{type:"number",description:"Only count lessons with at least this many community confirmations (default: 1)"}},required:[]}},{name:"brain_install",description:'Install a Domain Brain into your local Brain \u2014 pulls its curated, high-trust lessons so they surface in smart_recall immediately, even offline. Idempotent and non-destructive: it NEVER overrides your own lessons (only prior installs of the same brain). Re-run anytime to pull updates. Browse available brains first with brain_marketplace(). Example: brain_install(slug="k8s") \u2192 "\u{1F4E6} Installed: Kubernetes Incident Brain \xB7 42 lessons merged".',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},slug:{type:"string",description:'Domain brain slug from brain_marketplace (e.g. "k8s", "auth", "db")'},min_confirms:{type:"number",description:"Only install lessons with at least this many community confirmations (default: 1)"},limit:{type:"number",description:"Max lessons to install (default: 200, max: 500)"},dry_run:{type:"boolean",description:"Preview what would be installed without writing anything (default: false)"}},required:["slug"]}},{name:"brain_search",description:"BM25+ full-text search over ALL brain data: lessons, context entries, session history, CKG nodes, roadmap items. Unlike smart_recall (which focuses on lessons + context), brain_search casts a wider net. Use when smart_recall returns nothing or when you want to find anything the brain knows about a topic.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},query:{type:"string",description:"What to search for"},limit:{type:"number",description:"Max results (default: 15)"}},required:["query"]}},{name:"ckg_inspect",description:"Inspect the Causal Knowledge Graph (CKG) for a concept. Shows all typed edges (fixes, requires, co-occurs, causes) with Bayesian confidence scores. Use to understand what the brain knows about a topic and which fixes have the highest confidence. Also shows related concepts via graph traversal.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},concept:{type:"string",description:'Concept to inspect, e.g. "fix:clickhouse-ipv6" or "docker"'},max_hops:{type:"number",description:"Traversal depth (default: 2)"}},required:["concept"]}},{name:"brain_predict",description:'READ-ONLY \u2014 no side effects, no writes, no external network calls. Predictive Pre-fetch Engine (PPE): given your current context, reads the CKG in your Redis instance to predict likely failures and return the highest-confidence fixes. "Pre-load" means results are returned inline \u2014 nothing is cached or persisted. Requires a valid instance_id (your Redis brain). No rate limits. Call at session start when working on a specific feature or debugging area. Set scope="org" to widen prediction across your whole organisation \u2014 surfaces cross-team risks ("failed 3\xD7 across 2 other teams") from the Org Knowledge Graph, so an incident in one team becomes a vaccine for yours.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},context:{type:"string",description:`What you're working on, e.g. "upgrading Keycloak from 21 to 24"`},top_k:{type:"number",description:"Max predictions to return (default: 5)"},scope:{type:"string",enum:["instance","org","org+commons"],description:'Scope: "instance" (default) = this brain, "org" = warnings from failures in other teams of your organisation, "org+commons" = plus public lessons. Falls back to "instance" without an org.'}},required:["context"]}},{name:"brain_plan",description:'READ-ONLY \u2014 no side effects, no writes, no external network calls. Generative planning layer on top of the CKG: given a task you are ABOUT to do (e.g. "upgrade Postgres 14\u219216", "add Stripe webhooks"), returns an ordered action plan grounded in your own proven lessons \u2014 the failure modes most likely to bite (ranked by confidence), the concrete steps that fixed them before (with commands), and a pre-flight checklist. Where brain_predict answers "what might fail?", brain_plan answers "what should I do, in what order?". Requires a valid instance_id (your Redis brain). Call before starting non-trivial work.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},task:{type:"string",description:'The change you are about to make, e.g. "migrate auth from sessions to JWT"'},top_k:{type:"number",description:"Max items per section (default: 5)"}},required:["task"]}},{name:"brain_conflicts",description:"READ-ONLY \u2014 list every unresolved belief_conflict (a previously confirmed fix now contradicted by a failure) plus the agents currently writing to this Brain (last 1h). This is the arbitration inbox for multi-agent teams: when several AI sessions share one Brain, contradictory writes surface here instead of silently overwriting each other. Resolve any listed conflict with brain_resolve_conflict.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"}},required:[]}},{name:"brain_resolve_conflict",description:'Arbitrate a contested topic by picking the winning side. winner="success" reaffirms the fix (the contradicting failure stops blocking recall); winner="failure" retires the fix (its CKG fixes-edges decay to ~0 and the losing lesson is archived). Human-in-the-loop resolution is the strongest possible confidence signal. List open conflicts first with brain_conflicts.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},topic:{type:"string",description:'The contested topic, e.g. "fix:jwks-rotation"'},winner:{type:"string",enum:["success","failure"],description:"Which side wins the arbitration"},resolved_by:{type:"string",description:'Who resolved it (agent name or "human"); default "human"'}},required:["topic","winner"]}},{name:"brain_confirm_ci",description:"Close the CI feedback loop: tell the Brain whether a CI job passed or failed and which topics it covered. The Brain adjusts lesson confidence automatically \u2014 confirmed failures get +15%, false positives (brain predicted failure but CI passed) get \u221210%. Called automatically by cachly-action at the end of every pipeline. Also use manually after a deploy to confirm or refute the brain's last prediction.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},job_status:{type:"string",enum:["success","failure","cancelled"],description:"Outcome of the CI job"},topics:{type:"array",items:{type:"string"},description:'Topics touched by this CI run (e.g. ["auth:jwt", "deploy:k8s"])'},scan_topics:{type:"array",items:{type:"string"},description:"Topics the brain predicted would fail (from the scan response). Used to detect false positives."},source:{type:"string",description:'Optional: "github_actions", "gitlab_ci", etc.'}},required:["job_status","topics"]}},{name:"brain_briefing",description:"Push-based Brain warning: instead of waiting for you to ask, the Brain proactively checks whether the file you just opened, the PR you are about to raise, or the deploy you are about to run matches any known failure pattern \u2014 and surfaces warnings BEFORE something breaks. Call this on file_open (with the file path as context), pr_open (with the PR title/body), or deploy (with a short description of what is being deployed). Returns a risk_level (low/medium/high) plus up to 5 ranked warnings with confidence and a known fix.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},event_type:{type:"string",enum:["file_open","pr_open","deploy","manual"],description:"What triggered this briefing \u2014 determines how the context is interpreted"},context:{type:"string",description:"The event context: file path for file_open, title+body for pr_open, short description for deploy/manual"},threshold:{type:"number",description:"Minimum confidence (0\u20131) for a warning to be surfaced. Default 0.6 \u2014 raise it to reduce noise."}},required:["event_type","context"]}},{name:"brain_contribute_signal",description:"Contribute a privacy-safe signal to the global Brain commons. Only the topic category, outcome, and confidence bucket (high/medium/low) are shared \u2014 no lesson text, no org identity. When \u2265 k independent orgs contribute the same pattern, a meta-lesson is derived in the commons. Use this instead of fedbrain_contribute when privacy is required (enterprise, GDPR).",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},topic_category:{type:"string",description:'Normalised topic, e.g. "auth:jwt" or "deploy:k8s"'},outcome:{type:"string",enum:["success","failure","partial"],description:"Outcome of the pattern"},confidence:{type:"number",description:"Confidence 0\u20131 (bucketed before sending; default 0.5)"}},required:["topic_category","outcome"]}},{name:"brain_import_meta",description:'Import k-anonymous meta-lessons from the global Brain commons into your local Brain. Meta-lessons are derived from \u2265 k independent org signals \u2014 no individual org data is revealed. Imported lessons get state="meta" and never overwrite your own lessons. Filter by category to target relevant patterns.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},category:{type:"string",description:'Optional filter, e.g. "auth" or "deploy"'},limit:{type:"number",description:"Max meta-lessons to import (default 20, max 200)"}},required:[]}},{name:"madc_deliberate",description:"Multi-Agent Deliberation Chamber (MADC \u2014 Layer 3): When conflicting lessons exist for a topic, run deliberation between 6 specialist expert agents (InfraAgent, AuthAgent, DeployAgent, DatabaseAgent, DebugAgent, APIAgent). Each agent votes based on its domain CKG coverage. Unanimous vote \u2192 loser superseded. Split vote \u2192 contested flag, causal_trace required before acting. Resolution stored as permanent CKG node. Called automatically when learn_from_attempts detects a contradiction.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},topic:{type:"string",description:'Topic to deliberate, e.g. "fix:jwks-rotation"'},context:{type:"string",description:"Optional context for the deliberation"}},required:["topic"]}},{name:"cls_ingest",description:"Continuous Learning Stream (CLS \u2014 Layer 5): Ingest learning signals WITHOUT explicit session_end calls. Sources: git_commit (commit message + files \u2192 CKG edges), ci_outcome (green/red build \u2192 confirms fix), ide_diagnostic (compiler error + fix pair \u2192 instant lesson). Install automatic ingestion with cls_install_hooks \u2014 brain learns from every commit and CI run.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},source:{type:"string",enum:["git_commit","ci_outcome","ide_diagnostic"],description:"Event source type"},payload:{type:"object",description:"Event data. git_commit: {message, sha?, files?, diff?}. ci_outcome: {status, prev_status, job, context?}. ide_diagnostic: {error, fix, file?}"}},required:["source","payload"]}},{name:"cls_install_hooks",description:"READ-ONLY \u2014 outputs text only, writes no files, makes no network calls, has no side effects. Generates ready-to-paste shell scripts: a git post-commit hook and/or a GitHub Actions step. You must manually copy and install the output. Once the generated scripts are installed, each git commit or CI run will make outbound HTTPS calls to api.cachly.dev to feed learning signals to your brain. No auth required to call this tool \u2014 only an instance_id. Run once per repository.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},repo_path:{type:"string",description:"Path to repo root (default: current dir)"},hooks:{type:"array",items:{type:"string",enum:["git","ci"]},description:'Which hooks to output (default: ["git", "ci"])'}},required:[]}},{name:"fedbrain_contribute",description:"FedBrain (Layer 6): Contribute a lesson to the global Knowledge Commons with a cryptographic knowledge certificate. Certificate includes: domain fingerprint, confidence, outcome chain hash. Lessons with 10+ independent confirmations become Gold Standard. Context-weighted: other brains with similar tech stacks see your lesson ranked higher in fedbrain_search.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},lesson_key:{type:"string",description:'Topic key to contribute, e.g. "fix:clickhouse-ipv6"'},visibility:{type:"string",enum:["public","org_private"],description:"Visibility (default: public)"}},required:["lesson_key"]}},{name:"fedbrain_search",description:"FedBrain context-weighted search: Search the global commons, weighting results by tech-stack similarity. Brains with matching domain context (Go/Kubernetes/Postgres) rank higher than unrelated stacks. Shows certificate provenance, confirm_count, and Gold Standard badges.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},query:{type:"string",description:"What to search for"},context_hints:{type:"array",items:{type:"string"},description:'Your tech stack, e.g. ["go", "kubernetes", "postgres"]'},limit:{type:"number",description:"Max results (default: 10)"}},required:["query"]}},{name:"fedbrain_confirm",description:"Confirm that a syndicated lesson from the global commons worked for you. Propagates confirmation back \u2014 increments confirm_count on the knowledge certificate. Also updates your local CKG confidence. At 10 independent confirmations \u2192 Gold Standard.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},id:{type:"string",description:"Syndicated lesson id to confirm (shown next to each fedbrain_search result)"},topic:{type:"string",description:"Optional topic of the lesson \u2014 also updates your local CKG confidence for it"},outcome:{type:"string",enum:["worked","partially_worked","did_not_work"],description:"Did the lesson work for you?"}},required:["id","outcome"]}},{name:"fedbrain_status",description:"Show your FedBrain federation status: lessons contributed to global commons, recent confirmations, Gold Standard lessons, pending propagations. Use to track your brain's global knowledge contribution.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"}},required:[]}},{name:"brain_federate",description:`FedBrain Layer 6 \u2014 Private org knowledge transfer: copy CKG edges + lessons from a source brain into your brain for a specific domain (e.g. "billing", "auth", "deploy"). The new hire use case: one command gives you the senior engineer's 5 years of typed, confidence-weighted knowledge in your domain. Unlike syndicate_search (global, anonymous), brain_federate is org-private \u2014 both brains must be in the same Cachly org, or the source instance_id must be explicitly shared. Example: brain_federate(source="prod-brain-id", domain="billing", min_confidence=0.6)`,inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Your brain instance ID (destination)"},source:{type:"string",description:"Source brain instance ID to federate from"},domain:{type:"string",description:'Domain to transfer, e.g. "billing", "auth", "deploy", "infra". Use "*" for all domains.'},min_confidence:{type:"number",description:"Minimum edge confidence to transfer (default: 0.6)"},dry_run:{type:"boolean",description:"Preview what would be transferred without writing (default: false)"}},required:["source","domain"]}},{name:"crystal_view",description:"Inspect the current Memory Crystal \u2014 the compressed wisdom distilled from all past sessions. Shows top patterns per category, lesson count, and when the crystal was last refreshed. Call after session_start when you want to quickly see accumulated wisdom across all past work.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},show_raw:{type:"boolean",description:"Include raw JSON crystal data (default: false)"}},required:[]}},{name:"compact_recover",description:"Call FIRST after any context limit hit / compaction. Reconstructs full context from Memory Crystal + recent sessions + WIP registry + open failures. Returns a condensed briefing so the new context window starts exactly where the previous one left off \u2014 no lost progress.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},focus:{type:"string",description:"What you were working on (helps filter relevant context)"}},required:[]}},{name:"brain_from_git",description:"Bootstrap brain lessons from git history. Parses commit messages and infers fix/feature/refactor lessons automatically. Great for onboarding an existing codebase \u2014 run once and the brain instantly knows your team's accumulated patterns. Incremental by default: only processes new commits since the last run, so repeated calls are fast. Emits progress updates to stderr during long scans.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},repo_path:{type:"string",description:"Path to git repository (default: current directory)"},limit:{type:"number",description:"Max commits to process (default: 100, max: 500)"},branch:{type:"string",description:"Git branch to parse (default: current branch / HEAD)"},since:{type:"string",description:'Only commits after this date, e.g. "2024-01-01" (optional)'},incremental:{type:"boolean",description:"Only process commits since last run (default: true). Set false to reprocess all."}},required:[]}},{name:"brain_from_ci",description:"Bulk-ingest CI run outcomes into the Brain \u2014 the brain_from_git equivalent for CI history. Feed it an array of {job, status, prev_status} objects from your CI system and it will learn which jobs have been fixed, broken, or are stable. Use it to bootstrap the Brain from historical CI logs.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},outcomes:{type:"array",description:"List of CI run outcomes to ingest",items:{type:"object",properties:{job:{type:"string",description:'Job name (e.g. "test", "build", "lint")'},status:{type:"string",description:"Current status: success|failure|error"},prev_status:{type:"string",description:"Previous run status (optional, needed to detect transitions)"},context:{type:"string",description:"Optional: error message, branch, commit hash, etc."}},required:["job","status"]}}},required:["outcomes"]}},{name:"brain_watch",description:"Install an ambient git post-commit hook that automatically learns from every commit \u2014 no manual brain_from_git needed. After installation every `git commit` silently POSTs the commit message, SHA, and changed files to the cachly Brain API in the background. Idempotent: running brain_watch twice installs the hook only once. Uses curl (not Node/npx) so it works in any environment. The hook always exits 0 and runs asynchronously \u2014 it never blocks a commit. Returns the hook path and installation status (written/upgraded/appended/unchanged/skipped-no-git).",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID to learn into"},project_dir:{type:"string",description:'Path to the git repository (default: current directory ".")'},api_key:{type:"string",description:"Optional cachly API key (cky_\u2026) to embed in the hook for authentication"}},required:[]}},{name:"brain_predict_failures",description:'Pre-deploy failure prediction with probability percentages. Given a change context (e.g. "upgrading Keycloak 21\u219224" or "deploying Redis 7 to prod"), returns the top likely failure modes ranked by probability, with pre-loaded fixes. Uses CKG causal edges + lesson history. Call before any significant deploy, migration, or infrastructure change.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},context:{type:"string",description:'What you are about to do, e.g. "upgrading Keycloak 21 to 24"'},top_k:{type:"number",description:"Number of failure predictions to return (default: 5)"},format:{type:"string",enum:["brief","detailed"],description:"Output format (default: detailed)"}},required:["context"]}},{name:"brain_share",description:'Export a Brain snapshot and create a publicly shareable link that anyone can import. Optionally filter by topic prefix (e.g. only "auth:" or "deploy:" lessons). Visibility can be "public" (discoverable) or "unlisted" (link-only). Returns a share URL and the import command to give to teammates or the community. Example: brain_share(instance_id="...", title="My Auth Patterns", topic_filter=["auth"])',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance to export from."},title:{type:"string",description:'Human-readable title for the shared Brain snapshot. Default: "My Brain Snapshot".'},description:{type:"string",description:"Short description of what knowledge this Brain contains."},topic_filter:{type:"array",items:{type:"string"},description:"Only export lessons whose topic contains one of these strings. Omit to export all lessons."},visibility:{type:"string",enum:["public","unlisted"],description:'"public" = discoverable in the Brain marketplace. "unlisted" = only accessible by direct link. Default: unlisted.'},max_lessons:{type:"number",description:"Maximum number of lessons to include (default 100, max 500)."},dry_run:{type:"boolean",description:"If true, preview what would be shared without creating the public link."}},required:[]}},{name:"brain_import",description:'Import lessons from a publicly shared Brain snapshot into your own Brain instance. Accepts a share ID (UUID) or the full share URL from brain_share. Optionally prefix all imported topics to avoid naming collisions (e.g. topic_prefix="team"). Existing lessons are NOT overwritten by default \u2014 pass overwrite=true to replace them. Example: brain_import(instance_id="...", share_id="abc123", topic_prefix="imported")',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance to import lessons into."},share_id:{type:"string",description:"Share ID (UUID) or full share URL from brain_share."},topic_prefix:{type:"string",description:'Optional prefix to prepend to all imported topic names (e.g. "team" \u2192 "team:auth:jwt-expiry"). Prevents collisions with your own lessons.'},min_confidence:{type:"number",description:"Skip lessons below this confidence threshold (0.0\u20131.0). Default: 0 (import all)."},overwrite:{type:"boolean",description:"Replace existing lessons with the same topic. Default false."},dry_run:{type:"boolean",description:"Preview what would be imported without writing to the Brain."}},required:["share_id"]}},{name:"brain_share_list",description:'List all Brain snapshots you have previously shared with brain_share. Shows share ID, title, lesson count, visibility, and creation date for each share. Checks the local provenance log and the cachly API. Example: brain_share_list(instance_id="...")',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance that created the shares."}},required:[]}},{name:"brain_unshare",description:'Revoke and permanently delete a public Brain share by its share ID. After calling this, the share URL becomes invalid and no one can import it. Note: users who already imported the Brain keep their local copy. Example: brain_unshare(instance_id="...", share_id="abc123")',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance that owns the share."},share_id:{type:"string",description:"Share ID to revoke (from brain_share or brain_share_list)."}},required:["share_id"]}},{name:"brain_discover",description:'Search and browse publicly shared Brain snapshots in the cachly marketplace. Find ready-made knowledge bases on specific topics (TypeScript, Docker, auth, CI/CD, etc.) created and shared by the community. Returns a ranked list with lesson counts, topics, and import commands. Example: brain_discover(query="kubernetes deployment") \xB7 brain_discover(topic="auth")',inputSchema:{type:"object",properties:{query:{type:"string",description:"Full-text search query across Brain titles and descriptions."},topic:{type:"string",description:'Filter by topic prefix (e.g. "auth", "docker", "nextjs").'},limit:{type:"number",description:"Max number of results to return (default 10, max 50)."}},required:[]}},{name:"brain_seed_starter",description:`Seed a fresh Brain with a curated set of universal, high-value engineering lessons (Docker layer cache, JWT clock skew, Postgres migration locks, K8s OOM limits, N+1 queries, cache stampede, CORS preflight, and more). Makes the very first smart_recall return a useful hit instead of nothing \u2014 ideal right after setup or in a fresh repo with no git history to learn from. Starter lessons are tagged source:"starter", never override your own lessons, and are idempotent (won't double-seed). Example: brain_seed_starter(instance_id="...") \xB7 brain_seed_starter(instance_id="...", topic_filter=["docker","redis"])`,inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance to seed."},topic_filter:{type:"array",items:{type:"string"},description:'Only seed lessons whose topic or tags match one of these strings (e.g. ["docker", "auth"]). Omit to seed all.'},force:{type:"boolean",description:"Re-seed even if already seeded; also overwrites same-topic lessons. Default false."},dry_run:{type:"boolean",description:"Preview which starter lessons would be seeded without writing."}},required:[]}},{name:"brain_graph",description:'Export the Causal Knowledge Graph as a 3D-render-ready node/link payload (schema cachly.brain_graph/v1) \u2014 the data layer behind the brain viz: the visual, explorable 3D map of every concept, person, file and service the brain knows, and how they causally relate. Node kinds (concept/person/file/service) carry stable color groups and a size (val) scaled by reference count; links carry edgeType (fixes/causes/co-occurs/authored/collaborates) and confidence (value). Consumed verbatim by react-force-graph-3d / three.js frontends. Example: brain_graph(instance_id="...") \xB7 brain_graph(instance_id="...", domain="auth", min_confidence=0.5, format="summary")',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance to export."},max_nodes:{type:"number",description:"Cap on nodes returned (default 400, max 2000). Edges to dropped nodes are pruned."},domain:{type:"string",description:'Only include nodes whose domain or id contains this string (e.g. "auth", "docker"). Omit for the whole graph.'},min_confidence:{type:"number",description:"Drop edges below this confidence 0..1 (default 0 = keep all)."},format:{type:"string",enum:["json","summary"],description:'"json" (default) emits the full renderable payload; "summary" emits a human-readable overview.'}},required:[]}},{name:"brain_set_pref",description:'Persist a user preference for this Brain instance. Preferences are stored in Redis and survive restarts. Known keys: `auto_changelog` (set to "false" to disable the automatic changelog shown at session_start).',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance (Brain ID)."},key:{type:"string",description:'Preference key (e.g. "auto_changelog").'},value:{type:"string",description:'Value to set (e.g. "false" to disable, "true" to re-enable).'}},required:["key","value"]}},{name:"brain_get_pref",description:"Read back one or all preferences stored for this Brain instance. Call with a `key` to get a single value, or omit `key` to list every preference that has been set. Returns a default note when a key has never been set. Complement to `brain_set_pref`.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance."},key:{type:"string",description:"Preference key to read. Omit to list all preferences."}},required:[]}}];export{e as TOOLS};
|
|
10
|
+
Optionally writes copilot-instructions.md directly to the project directory.`,inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cachly instance to use as the AI brain"},project_dir:{type:"string",description:"Absolute path to the project root. If provided, puts the cachly block into .github/copilot-instructions.md (and CLAUDE.md, .cursor/rules/cachly.mdc, .windsurfrules when that editor is in use). Text outside the cachly markers is kept."},embed_provider:{type:"string",enum:["openai","mistral","cohere","ollama","gemini"],description:"Embedding provider to use for smart_recall / semantic search. Default: openai. Use ollama for fully local/free setup."},project_description:{type:"string",description:"Short description of the project (used in the generated instructions)"}},required:[]}},{name:"cache_stream_set",description:"Cache a list of string chunks (e.g. LLM token stream) via Redis RPUSH. Each chunk is stored as a separate list element under cachly:stream:{key}. Replay with cache_stream_get.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},key:{type:"string",description:"Cache key"},chunks:{type:"array",items:{type:"string"},description:"Ordered list of string chunks"},ttl:{type:"number",description:"TTL in seconds for the stored list (optional)"}},required:["key","chunks"]}},{name:"cache_stream_get",description:"Retrieve a previously cached stream as an ordered list of string chunks. Returns null on cache miss (key absent or empty list). Stored under cachly:stream:{key}.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},key:{type:"string",description:"Cache key"}},required:["key"]}},{name:"cache_org_stats",description:"Show shared cache statistics for an org namespace. Scans all keys under org:{org_id}:sem:* and reports how many entries are shared. Use this to verify org-sharing is working and to monitor cross-instance cache utilization. Also aggregates org-wide ROI via the Cachly API: total cache hits, hits in the last 24h, estimated total and projected monthly USD savings across all org instances, plus a per-instance breakdown. Zero-config: no API changes required \u2014 any cache_set call with org_id writes to this namespace.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},org_id:{type:"string",description:'Org ID to inspect (e.g. "acme", "my-company")'}},required:["org_id"]}},{name:"set_cost_per_call",description:"Set the assumed cost per avoided LLM API call (USD) for this instance. This is used to compute accurate ROI savings estimates in cache_stats. The default ($0.002) is calibrated for a small model (gpt-5.5-mini class). Set your actual model cost for accurate numbers: claude-opus-4.8 \u2192 $0.02, gpt-5.5 \u2192 $0.015, claude-sonnet-4.6 \u2192 $0.009, claude-haiku-4.5 \u2192 $0.001. After updating, cache_stats will show savings computed from your real cost. Use list_instances to find your instance_id.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},cost_per_call_usd:{type:"number",description:"Cost per LLM API call in USD. Common values: 0.02 (claude-opus-4.8), 0.015 (gpt-5.5), 0.009 (claude-sonnet-4.6), 0.002 (gpt-5.5-mini), 0.001 (claude-haiku-4.5)."}},required:["cost_per_call_usd"]}},{name:"memory_consolidate",description:"Cognitive memory consolidation \u2014 the weekly garbage collector for your AI Brain. Scans all lessons, detects contradictions (same topic with conflicting outcomes), names possible duplicates by meaning (same content under a different topic, cosine \u2265 0.80), flags stale entries (not recalled in 90+ days), and computes a health score. Never merges or deletes a lesson; link two with `ersetzt` on learn_from_attempts. Run weekly or when brain_doctor reports > 20 lessons. Like git gc for knowledge.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},dry_run:{type:"boolean",description:"If true, report what would change without writing (default: false)"},stale_days:{type:"number",description:"Lessons not recalled in this many days are flagged stale (default: 90)"}},required:[]}},{name:"brain_diff",description:'git log for your AI Brain \u2014 see exactly what changed since a point in time. Returns a structured changelog: new lessons added, lessons updated (outcome changed), lessons recalled (hit count increased), and lessons that decayed. Perfect for weekly reviews: "What did my AI learn this week?" Example: brain_diff(instance_id="...", since="7d") \u2192 "12 new \xB7 4 updated \xB7 2 stale"',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},since:{type:"string",description:'Time window: "1d", "7d", "30d", or ISO-8601 date (default: "7d")'},format:{type:"string",enum:["summary","detailed"],description:"Output format (default: summary)"}},required:[]}},{name:"causal_trace",description:'Root Cause Analysis through memory: given a problem description, traces the causal chain from root cause through intermediate failures to the current symptom, then surfaces the exact solution that worked before. Read-only \u2014 does not modify any stored data. Requires prior learning: brain must have lessons stored via learn_from_attempts or brain_from_git. Returns an ordered chain of concepts with confidence scores plus the matching solution; returns an empty chain with a message if no causal path is found. Example: causal_trace(problem="auth breaks after restart") \u2192 "Root: k8s:namespace-terminating \u2192 keycloak:jwks-race \u2192 Solution: PollUntilContextTimeout 3min". Use recall_best_solution for direct topic lookup, syndicate_search for community patterns, and causal_trace when you have a symptom and need the full root-cause chain.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},problem:{type:"string",description:"Describe the problem or error you are seeing right now"},max_depth:{type:"number",description:"Max causal chain depth to trace (default: 5)"},tags:{type:"array",items:{type:"string"},description:"Optional: narrow search to these tags"}},required:["problem"]}},{name:"knowledge_decay",description:'Confidence scoring for every lesson in your Brain \u2014 because old knowledge rots. Computes a decay score (0\u2013100%) per lesson based on age, recall frequency, and outcome. Lessons recalled recently score high. Lessons from 90 days ago never recalled score low. Returns a ranked list with visual confidence bars: "\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591 40%". Use this before a big refactor to know which lessons to trust and which to re-validate.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},min_age_days:{type:"number",description:"Only include lessons older than N days (default: 0 = all)"},show_top:{type:"number",description:"Number of entries to return, sorted by lowest confidence first (default: 20)"}},required:[]}},{name:"autopilot",description:'Generate a CLAUDE.md / copilot-instructions.md that makes any AI self-managing forever. Writes a configuration file to disk \u2014 will overwrite an existing file at the target path. No auth required beyond a valid instance_id. The generated file instructs Claude, Cursor, Copilot, Windsurf, or Gemini to automatically call session_start at window open, learn_from_attempts after every fix, and session_end before closing \u2014 without being asked. Returns the generated file content as a string and the path where it was written. Use style="minimal" for just the three hooks; style="full" for the complete ruleset with examples. One command. Every AI. Always on. Use setup_ai_memory instead if you want an interactive one-shot setup that also creates an instance.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},editor:{type:"string",enum:["claude","cursor","copilot","windsurf","gemini","continue","all"],description:"Target editor (default: claude)"},project_name:{type:"string",description:"Your project name (used in generated instructions)"},style:{type:"string",enum:["minimal","full"],description:"minimal = just the hooks, full = full ruleset with examples (default: full)"}},required:[]}},{name:"syndicate",description:'Contribute a verified lesson to the GLOBAL Cachly Knowledge Commons \u2014 a privacy-preserving shared brain where every AI instance can learn from the discoveries of every other. Your contributor identity is a one-way HMAC hash: completely anonymous. The lesson is immediately searchable by any other AI using syndicate_search. This is how individual knowledge becomes collective intelligence. Call this AFTER every learn_from_attempts that is worth sharing universally (critical bugs, deployment gotchas, architecture discoveries). If a lesson with the same topic already exists in the commons, it is updated in place (idempotent). Returns { key, confirm_count, scope } confirming the stored lesson. Use scope="org" to keep the lesson private to your organisation. Do NOT use for secrets or PII \u2014 content is stored in a shared knowledge base.',inputSchema:{type:"object",properties:{topic:{type:"string",description:'Topic key in category:keyword format (e.g. "fix:clickhouse-ipv6", "deploy:docker-compose")'},outcome:{type:"string",enum:["success","failure","partial"],description:"Result of the attempt (default: success)"},what_worked:{type:"string",description:"Exact approach, command, or fix that worked. File paths are stripped automatically."},what_failed:{type:"string",description:"What failed or was wrong \u2014 helps others avoid the same trap."},severity:{type:"string",enum:["critical","major","minor"],description:"How severe the issue was (default: minor)"},tags:{type:"array",items:{type:"string"},description:"Up to 10 keywords for better discoverability"},scope:{type:"string",enum:["public","org"],description:'Visibility: "public" = global commons (default), "org" = private to your org only'}},required:["topic","what_worked"]}},{name:"syndicate_search",description:'Search the GLOBAL Cachly Knowledge Commons for solutions contributed by the entire community. Returns lessons ranked by confirm_count (trust score) then recency. Use this BEFORE debugging any unknown issue \u2014 someone in the global brain likely solved it already. Example: syndicate_search(q="clickhouse localhost connection refused") \u2192 "fix: use 127.0.0.1 not localhost when IPv6 is disabled \xB7 confirmed by 47 instances"',inputSchema:{type:"object",properties:{q:{type:"string",description:"Free-text search query (leave empty for most recent lessons)"},category:{type:"string",description:'Filter by category prefix: "fix", "deploy", "debug", "infra", "api", "web"'},scope:{type:"string",enum:["public","org"],description:'"public" = global commons (default), "org" = public + your org-private lessons'},limit:{type:"number",description:"Max results to return (default: 20, max: 50)"}},required:[]}},{name:"syndicate_stats",description:"Show the health of the global Knowledge Commons: total lessons, total confirms, top categories, most-trusted lessons, growth in the last 7 days, and top contributors (anonymous scores). Use for weekly reviews or to explore what the community knows.",inputSchema:{type:"object",properties:{},required:[]}},{name:"syndicate_trending",description:"Show the TRENDING lessons in the global Knowledge Commons \u2014 those with the fastest confirmation velocity in the last 7 days (confirm_count / age_in_days). Use this at the start of a session or weekly review to see what the community is actively validating. Lessons need at least 2 independent confirms to appear here.",inputSchema:{type:"object",properties:{limit:{type:"number",description:"Max results (default: 10, max: 50)"}},required:[]}},{name:"brain_marketplace",description:'Browse the Domain Brain marketplace \u2014 curated, installable packs of high-trust community lessons, grouped by domain (Kubernetes, Auth, Database, React, Payments, \u2026). Each brain is built from verified, community-confirmed lessons in the global Knowledge Commons. Use at onboarding or when starting work in an unfamiliar domain to bootstrap your Brain instantly. Install one with brain_install(slug="..."). Example: brain_marketplace() \u2192 "\u2638\uFE0F Kubernetes Incident Brain \xB7 42 lessons \xB7 install: brain_install(slug=\\"k8s\\")".',inputSchema:{type:"object",properties:{min_confirms:{type:"number",description:"Only count lessons with at least this many community confirmations (default: 1)"}},required:[]}},{name:"brain_install",description:'Install a Domain Brain into your local Brain \u2014 pulls its curated, high-trust lessons so they surface in smart_recall immediately, even offline. Idempotent and non-destructive: it NEVER overrides your own lessons (only prior installs of the same brain). Re-run anytime to pull updates. Browse available brains first with brain_marketplace(). Example: brain_install(slug="k8s") \u2192 "\u{1F4E6} Installed: Kubernetes Incident Brain \xB7 42 lessons merged".',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance."},slug:{type:"string",description:'Domain brain slug from brain_marketplace (e.g. "k8s", "auth", "db")'},min_confirms:{type:"number",description:"Only install lessons with at least this many community confirmations (default: 1)"},limit:{type:"number",description:"Max lessons to install (default: 200, max: 500)"},dry_run:{type:"boolean",description:"Preview what would be installed without writing anything (default: false)"}},required:["slug"]}},{name:"brain_search",description:"BM25+ full-text search over ALL brain data: lessons, context entries, session history, CKG nodes, roadmap items. Unlike smart_recall (which focuses on lessons + context), brain_search casts a wider net. Use when smart_recall returns nothing or when you want to find anything the brain knows about a topic.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},query:{type:"string",description:"What to search for"},limit:{type:"number",description:"Max results (default: 15)"}},required:["query"]}},{name:"ckg_inspect",description:"Inspect the Causal Knowledge Graph (CKG) for a concept. Shows all typed edges (fixes, requires, co-occurs, causes) with Bayesian confidence scores. Use to understand what the brain knows about a topic and which fixes have the highest confidence. Also shows related concepts via graph traversal.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},concept:{type:"string",description:'Concept to inspect, e.g. "fix:clickhouse-ipv6" or "docker"'},max_hops:{type:"number",description:"Traversal depth (default: 2)"}},required:["concept"]}},{name:"brain_predict",description:'READ-ONLY \u2014 no side effects, no writes, no external network calls. Predictive Pre-fetch Engine (PPE): given your current context, reads the CKG in your Redis instance to predict likely failures and return the highest-confidence fixes. "Pre-load" means results are returned inline \u2014 nothing is cached or persisted. Requires a valid instance_id (your Redis brain). No rate limits. Call at session start when working on a specific feature or debugging area. Set scope="org" to widen prediction across your whole organisation \u2014 surfaces cross-team risks ("failed 3\xD7 across 2 other teams") from the Org Knowledge Graph, so an incident in one team becomes a vaccine for yours.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},context:{type:"string",description:`What you're working on, e.g. "upgrading Keycloak from 21 to 24"`},top_k:{type:"number",description:"Max predictions to return (default: 5)"},scope:{type:"string",enum:["instance","org","org+commons"],description:'Scope: "instance" (default) = this brain, "org" = warnings from failures in other teams of your organisation, "org+commons" = plus public lessons. Falls back to "instance" without an org.'}},required:["context"]}},{name:"brain_plan",description:'READ-ONLY \u2014 no side effects, no writes, no external network calls. Generative planning layer on top of the CKG: given a task you are ABOUT to do (e.g. "upgrade Postgres 14\u219216", "add Stripe webhooks"), returns an ordered action plan grounded in your own proven lessons \u2014 the failure modes most likely to bite (ranked by confidence), the concrete steps that fixed them before (with commands), and a pre-flight checklist. Where brain_predict answers "what might fail?", brain_plan answers "what should I do, in what order?". Requires a valid instance_id (your Redis brain). Call before starting non-trivial work.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},task:{type:"string",description:'The change you are about to make, e.g. "migrate auth from sessions to JWT"'},top_k:{type:"number",description:"Max items per section (default: 5)"}},required:["task"]}},{name:"brain_conflicts",description:"READ-ONLY \u2014 list every unresolved belief_conflict (a previously confirmed fix now contradicted by a failure) plus the agents currently writing to this Brain (last 1h). This is the arbitration inbox for multi-agent teams: when several AI sessions share one Brain, contradictory writes surface here instead of silently overwriting each other. Resolve any listed conflict with brain_resolve_conflict.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"}},required:[]}},{name:"brain_resolve_conflict",description:'Arbitrate a contested topic by picking the winning side. winner="success" reaffirms the fix (the contradicting failure stops blocking recall); winner="failure" retires the fix (its CKG fixes-edges decay to ~0 and the losing lesson is archived). Human-in-the-loop resolution is the strongest possible confidence signal. List open conflicts first with brain_conflicts.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},topic:{type:"string",description:'The contested topic, e.g. "fix:jwks-rotation"'},winner:{type:"string",enum:["success","failure"],description:"Which side wins the arbitration"},resolved_by:{type:"string",description:'Who resolved it (agent name or "human"); default "human"'}},required:["topic","winner"]}},{name:"brain_confirm_ci",description:"Close the CI feedback loop: tell the Brain whether a CI job passed or failed and which topics it covered. The Brain adjusts lesson confidence automatically \u2014 confirmed failures get +15%, false positives (brain predicted failure but CI passed) get \u221210%. Called automatically by cachly-action at the end of every pipeline. Also use manually after a deploy to confirm or refute the brain's last prediction.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},job_status:{type:"string",enum:["success","failure","cancelled"],description:"Outcome of the CI job"},topics:{type:"array",items:{type:"string"},description:'Topics touched by this CI run (e.g. ["auth:jwt", "deploy:k8s"])'},scan_topics:{type:"array",items:{type:"string"},description:"Topics the brain predicted would fail (from the scan response). Used to detect false positives."},source:{type:"string",description:'Optional: "github_actions", "gitlab_ci", etc.'}},required:["job_status","topics"]}},{name:"brain_briefing",description:"Push-based Brain warning: instead of waiting for you to ask, the Brain proactively checks whether the file you just opened, the PR you are about to raise, or the deploy you are about to run matches any known failure pattern \u2014 and surfaces warnings BEFORE something breaks. Call this on file_open (with the file path as context), pr_open (with the PR title/body), or deploy (with a short description of what is being deployed). Returns a risk_level (low/medium/high) plus up to 5 ranked warnings with confidence and a known fix.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},event_type:{type:"string",enum:["file_open","pr_open","deploy","manual"],description:"What triggered this briefing \u2014 determines how the context is interpreted"},context:{type:"string",description:"The event context: file path for file_open, title+body for pr_open, short description for deploy/manual"},threshold:{type:"number",description:"Minimum confidence (0\u20131) for a warning to be surfaced. Default 0.6 \u2014 raise it to reduce noise."}},required:["event_type","context"]}},{name:"brain_contribute_signal",description:"Contribute a privacy-safe signal to the global Brain commons. Only the topic category, outcome, and confidence bucket (high/medium/low) are shared \u2014 no lesson text, no org identity. When \u2265 k independent orgs contribute the same pattern, a meta-lesson is derived in the commons. Use this instead of fedbrain_contribute when privacy is required (enterprise, GDPR).",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},topic_category:{type:"string",description:'Normalised topic, e.g. "auth:jwt" or "deploy:k8s"'},outcome:{type:"string",enum:["success","failure","partial"],description:"Outcome of the pattern"},confidence:{type:"number",description:"Confidence 0\u20131 (bucketed before sending; default 0.5)"}},required:["topic_category","outcome"]}},{name:"brain_import_meta",description:'Import k-anonymous meta-lessons from the global Brain commons into your local Brain. Meta-lessons are derived from \u2265 k independent org signals \u2014 no individual org data is revealed. Imported lessons get state="meta" and never overwrite your own lessons. Filter by category to target relevant patterns.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},category:{type:"string",description:'Optional filter, e.g. "auth" or "deploy"'},limit:{type:"number",description:"Max meta-lessons to import (default 20, max 200)"}},required:[]}},{name:"madc_deliberate",description:"Multi-Agent Deliberation Chamber (MADC \u2014 Layer 3): When conflicting lessons exist for a topic, run deliberation between 6 specialist expert agents (InfraAgent, AuthAgent, DeployAgent, DatabaseAgent, DebugAgent, APIAgent). Each agent votes based on its domain CKG coverage. Unanimous vote \u2192 loser superseded. Split vote \u2192 contested flag, causal_trace required before acting. Resolution stored as permanent CKG node. Called automatically when learn_from_attempts detects a contradiction.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},topic:{type:"string",description:'Topic to deliberate, e.g. "fix:jwks-rotation"'},context:{type:"string",description:"Optional context for the deliberation"}},required:["topic"]}},{name:"cls_ingest",description:"Continuous Learning Stream (CLS \u2014 Layer 5): Ingest learning signals WITHOUT explicit session_end calls. Sources: git_commit (commit message + files \u2192 CKG edges), ci_outcome (green/red build \u2192 confirms fix), ide_diagnostic (compiler error + fix pair \u2192 instant lesson). Install automatic ingestion with cls_install_hooks \u2014 brain learns from every commit and CI run.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},source:{type:"string",enum:["git_commit","ci_outcome","ide_diagnostic"],description:"Event source type"},payload:{type:"object",description:"Event data. git_commit: {message, sha?, files?, diff?}. ci_outcome: {status, prev_status, job, context?}. ide_diagnostic: {error, fix, file?}"}},required:["source","payload"]}},{name:"cls_install_hooks",description:"READ-ONLY \u2014 outputs text only, writes no files, makes no network calls, has no side effects. Generates ready-to-paste shell scripts: a git post-commit hook and/or a GitHub Actions step. You must manually copy and install the output. Once the generated scripts are installed, each git commit or CI run will make outbound HTTPS calls to api.cachly.dev to feed learning signals to your brain. No auth required to call this tool \u2014 only an instance_id. Run once per repository.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},repo_path:{type:"string",description:"Path to repo root (default: current dir)"},hooks:{type:"array",items:{type:"string",enum:["git","ci"]},description:'Which hooks to output (default: ["git", "ci"])'}},required:[]}},{name:"fedbrain_contribute",description:"FedBrain (Layer 6): Contribute a lesson to the global Knowledge Commons with a cryptographic knowledge certificate. Certificate includes: domain fingerprint, confidence, outcome chain hash. Lessons with 10+ independent confirmations become Gold Standard. Context-weighted: other brains with similar tech stacks see your lesson ranked higher in fedbrain_search.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},lesson_key:{type:"string",description:'Topic key to contribute, e.g. "fix:clickhouse-ipv6"'},visibility:{type:"string",enum:["public","org_private"],description:"Visibility (default: public)"}},required:["lesson_key"]}},{name:"fedbrain_search",description:"FedBrain context-weighted search: Search the global commons, weighting results by tech-stack similarity. Brains with matching domain context (Go/Kubernetes/Postgres) rank higher than unrelated stacks. Shows certificate provenance, confirm_count, and Gold Standard badges.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},query:{type:"string",description:"What to search for"},context_hints:{type:"array",items:{type:"string"},description:'Your tech stack, e.g. ["go", "kubernetes", "postgres"]'},limit:{type:"number",description:"Max results (default: 10)"}},required:["query"]}},{name:"fedbrain_confirm",description:"Confirm that a syndicated lesson from the global commons worked for you. Propagates confirmation back \u2014 increments confirm_count on the knowledge certificate. Also updates your local CKG confidence. At 10 independent confirmations \u2192 Gold Standard.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},id:{type:"string",description:"Syndicated lesson id to confirm (shown next to each fedbrain_search result)"},topic:{type:"string",description:"Optional topic of the lesson \u2014 also updates your local CKG confidence for it"},outcome:{type:"string",enum:["worked","partially_worked","did_not_work"],description:"Did the lesson work for you?"}},required:["id","outcome"]}},{name:"fedbrain_status",description:"Show your FedBrain federation status: lessons contributed to global commons, recent confirmations, Gold Standard lessons, pending propagations. Use to track your brain's global knowledge contribution.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"}},required:[]}},{name:"brain_federate",description:`FedBrain Layer 6 \u2014 Private org knowledge transfer: copy CKG edges + lessons from a source brain into your brain for a specific domain (e.g. "billing", "auth", "deploy"). The new hire use case: one command gives you the senior engineer's 5 years of typed, confidence-weighted knowledge in your domain. Unlike syndicate_search (global, anonymous), brain_federate is org-private \u2014 both brains must be in the same Cachly org, or the source instance_id must be explicitly shared. Example: brain_federate(source="prod-brain-id", domain="billing", min_confidence=0.6)`,inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Your brain instance ID (destination)"},source:{type:"string",description:"Source brain instance ID to federate from"},domain:{type:"string",description:'Domain to transfer, e.g. "billing", "auth", "deploy", "infra". Use "*" for all domains.'},min_confidence:{type:"number",description:"Minimum edge confidence to transfer (default: 0.6)"},dry_run:{type:"boolean",description:"Preview what would be transferred without writing (default: false)"}},required:["source","domain"]}},{name:"crystal_view",description:"Inspect the current Memory Crystal \u2014 the compressed wisdom distilled from all past sessions. Shows top patterns per category, lesson count, and when the crystal was last refreshed. Call after session_start when you want to quickly see accumulated wisdom across all past work.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},show_raw:{type:"boolean",description:"Include raw JSON crystal data (default: false)"}},required:[]}},{name:"compact_recover",description:"Call FIRST after any context limit hit / compaction. Reconstructs full context from Memory Crystal + recent sessions + WIP registry + open failures. Returns a condensed briefing so the new context window starts exactly where the previous one left off \u2014 no lost progress.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},focus:{type:"string",description:"What you were working on (helps filter relevant context)"}},required:[]}},{name:"brain_from_git",description:"Bootstrap brain lessons from git history. Parses commit messages and infers fix/feature/refactor lessons automatically. Great for onboarding an existing codebase \u2014 run once and the brain instantly knows your team's accumulated patterns. Incremental by default: only processes new commits since the last run, so repeated calls are fast. Emits progress updates to stderr during long scans.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},repo_path:{type:"string",description:"Path to git repository (default: current directory)"},limit:{type:"number",description:"Max commits to process (default: 100, max: 500)"},branch:{type:"string",description:"Git branch to parse (default: current branch / HEAD)"},since:{type:"string",description:'Only commits after this date, e.g. "2024-01-01" (optional)'},incremental:{type:"boolean",description:"Only process commits since last run (default: true). Set false to reprocess all."}},required:[]}},{name:"brain_from_ci",description:"Bulk-ingest CI run outcomes into the Brain \u2014 the brain_from_git equivalent for CI history. Feed it an array of {job, status, prev_status} objects from your CI system and it will learn which jobs have been fixed, broken, or are stable. Use it to bootstrap the Brain from historical CI logs.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},outcomes:{type:"array",description:"List of CI run outcomes to ingest",items:{type:"object",properties:{job:{type:"string",description:'Job name (e.g. "test", "build", "lint")'},status:{type:"string",description:"Current status: success|failure|error"},prev_status:{type:"string",description:"Previous run status (optional, needed to detect transitions)"},context:{type:"string",description:"Optional: error message, branch, commit hash, etc."}},required:["job","status"]}}},required:["outcomes"]}},{name:"brain_watch",description:"Install an ambient git post-commit hook that automatically learns from every commit \u2014 no manual brain_from_git needed. After installation every `git commit` sends the commit message, SHA, and changed files to the cachly Brain in the background. It is the same hook `init` installs; no key is written into the project (the hook reads $CACHLY_JWT or ~/.cachly/credentials.json when it runs). Removes an older brain_watch block. Idempotent: running brain_watch twice installs the hook only once. The hook always exits 0 and runs asynchronously \u2014 it never blocks a commit. Returns the hook path and installation status (written/upgraded/appended/unchanged/skipped-no-git).",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID to learn into"},project_dir:{type:"string",description:'Path to the git repository (default: current directory ".")'}},required:[]}},{name:"brain_predict_failures",description:'Pre-deploy failure prediction with probability percentages. Given a change context (e.g. "upgrading Keycloak 21\u219224" or "deploying Redis 7 to prod"), returns the top likely failure modes ranked by probability, with pre-loaded fixes. Uses CKG causal edges + lesson history. Call before any significant deploy, migration, or infrastructure change.',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"Brain instance ID"},context:{type:"string",description:'What you are about to do, e.g. "upgrading Keycloak 21 to 24"'},top_k:{type:"number",description:"Number of failure predictions to return (default: 5)"},format:{type:"string",enum:["brief","detailed"],description:"Output format (default: detailed)"}},required:["context"]}},{name:"brain_share",description:'Export a Brain snapshot and create a publicly shareable link that anyone can import. Optionally filter by topic prefix (e.g. only "auth:" or "deploy:" lessons). Visibility can be "public" (discoverable) or "unlisted" (link-only). Returns a share URL and the import command to give to teammates or the community. Example: brain_share(instance_id="...", title="My Auth Patterns", topic_filter=["auth"])',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance to export from."},title:{type:"string",description:'Human-readable title for the shared Brain snapshot. Default: "My Brain Snapshot".'},description:{type:"string",description:"Short description of what knowledge this Brain contains."},topic_filter:{type:"array",items:{type:"string"},description:"Only export lessons whose topic contains one of these strings. Omit to export all lessons."},visibility:{type:"string",enum:["public","unlisted"],description:'"public" = discoverable in the Brain marketplace. "unlisted" = only accessible by direct link. Default: unlisted.'},max_lessons:{type:"number",description:"Maximum number of lessons to include (default 100, max 500)."},dry_run:{type:"boolean",description:"If true, preview what would be shared without creating the public link."}},required:[]}},{name:"brain_import",description:'Import lessons from a publicly shared Brain snapshot into your own Brain instance. Accepts a share ID (UUID) or the full share URL from brain_share. Optionally prefix all imported topics to avoid naming collisions (e.g. topic_prefix="team"). Existing lessons are NOT overwritten by default \u2014 pass overwrite=true to replace them. Example: brain_import(instance_id="...", share_id="abc123", topic_prefix="imported")',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance to import lessons into."},share_id:{type:"string",description:"Share ID (UUID) or full share URL from brain_share."},topic_prefix:{type:"string",description:'Optional prefix to prepend to all imported topic names (e.g. "team" \u2192 "team:auth:jwt-expiry"). Prevents collisions with your own lessons.'},min_confidence:{type:"number",description:"Skip lessons below this confidence threshold (0.0\u20131.0). Default: 0 (import all)."},overwrite:{type:"boolean",description:"Replace existing lessons with the same topic. Default false."},dry_run:{type:"boolean",description:"Preview what would be imported without writing to the Brain."}},required:["share_id"]}},{name:"brain_share_list",description:'List all Brain snapshots you have previously shared with brain_share. Shows share ID, title, lesson count, visibility, and creation date for each share. Checks the local provenance log and the cachly API. Example: brain_share_list(instance_id="...")',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance that created the shares."}},required:[]}},{name:"brain_unshare",description:'Revoke and permanently delete a public Brain share by its share ID. After calling this, the share URL becomes invalid and no one can import it. Note: users who already imported the Brain keep their local copy. Example: brain_unshare(instance_id="...", share_id="abc123")',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance that owns the share."},share_id:{type:"string",description:"Share ID to revoke (from brain_share or brain_share_list)."}},required:["share_id"]}},{name:"brain_discover",description:'Search and browse publicly shared Brain snapshots in the cachly marketplace. Find ready-made knowledge bases on specific topics (TypeScript, Docker, auth, CI/CD, etc.) created and shared by the community. Returns a ranked list with lesson counts, topics, and import commands. Example: brain_discover(query="kubernetes deployment") \xB7 brain_discover(topic="auth")',inputSchema:{type:"object",properties:{query:{type:"string",description:"Full-text search query across Brain titles and descriptions."},topic:{type:"string",description:'Filter by topic prefix (e.g. "auth", "docker", "nextjs").'},limit:{type:"number",description:"Max number of results to return (default 10, max 50)."}},required:[]}},{name:"brain_seed_starter",description:`Seed a fresh Brain with a curated set of universal, high-value engineering lessons (Docker layer cache, JWT clock skew, Postgres migration locks, K8s OOM limits, N+1 queries, cache stampede, CORS preflight, and more). Makes the very first smart_recall return a useful hit instead of nothing \u2014 ideal right after setup or in a fresh repo with no git history to learn from. Starter lessons are tagged source:"starter", never override your own lessons, and are idempotent (won't double-seed). Example: brain_seed_starter(instance_id="...") \xB7 brain_seed_starter(instance_id="...", topic_filter=["docker","redis"])`,inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance to seed."},topic_filter:{type:"array",items:{type:"string"},description:'Only seed lessons whose topic or tags match one of these strings (e.g. ["docker", "auth"]). Omit to seed all.'},force:{type:"boolean",description:"Re-seed even if already seeded; also overwrites same-topic lessons. Default false."},dry_run:{type:"boolean",description:"Preview which starter lessons would be seeded without writing."}},required:[]}},{name:"brain_graph",description:'Export the Causal Knowledge Graph as a 3D-render-ready node/link payload (schema cachly.brain_graph/v1) \u2014 the data layer behind the brain viz: the visual, explorable 3D map of every concept, person, file and service the brain knows, and how they causally relate. Node kinds (concept/person/file/service) carry stable color groups and a size (val) scaled by reference count; links carry edgeType (fixes/causes/co-occurs/authored/collaborates) and confidence (value). Consumed verbatim by react-force-graph-3d / three.js frontends. Example: brain_graph(instance_id="...") \xB7 brain_graph(instance_id="...", domain="auth", min_confidence=0.5, format="summary")',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance to export."},max_nodes:{type:"number",description:"Cap on nodes returned (default 400, max 2000). Edges to dropped nodes are pruned."},domain:{type:"string",description:'Only include nodes whose domain or id contains this string (e.g. "auth", "docker"). Omit for the whole graph.'},min_confidence:{type:"number",description:"Drop edges below this confidence 0..1 (default 0 = keep all)."},format:{type:"string",enum:["json","summary"],description:'"json" (default) emits the full renderable payload; "summary" emits a human-readable overview.'}},required:[]}},{name:"brain_set_pref",description:'Persist a user preference for this Brain instance. Preferences are stored in Redis and survive restarts. Known keys: `auto_changelog` (set to "false" to disable the automatic changelog shown at session_start).',inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the cache instance (Brain ID)."},key:{type:"string",description:'Preference key (e.g. "auto_changelog").'},value:{type:"string",description:'Value to set (e.g. "false" to disable, "true" to re-enable).'}},required:["key","value"]}},{name:"brain_get_pref",description:"Read back one or all preferences stored for this Brain instance. Call with a `key` to get a single value, or omit `key` to list every preference that has been set. Returns a default note when a key has never been set. Complement to `brain_set_pref`.",inputSchema:{type:"object",properties:{instance_id:{type:"string",description:"UUID of the Brain instance."},key:{type:"string",description:"Preference key to read. Omit to list all preferences."}},required:[]}}];export{e as TOOLS};
|
package/glama.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cachly-dev/mcp-server",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.206",
|
|
4
4
|
"mcpName": "io.github.cachly-dev/mcp-server",
|
|
5
5
|
"description": "Solve it once. From then on, your AI knows. Experience for coding agents, EU-hosted: an MCP server for Claude Code, Cursor, Copilot & Windsurf. Learns from every bug fix, commit and CI run.",
|
|
6
6
|
"type": "module",
|
package/server.json
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
"url": "https://github.com/cachly-dev/cachly-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.10.
|
|
9
|
+
"version": "0.10.206",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"name": "@cachly-dev/mcp-server",
|
|
14
14
|
"identifier": "@cachly-dev/mcp-server",
|
|
15
|
-
"version": "0.10.
|
|
15
|
+
"version": "0.10.206",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
}
|