@cachly-dev/mcp-server 0.10.185 → 0.10.186

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import{setzeClientKennung as Tt}from"./herkunft.js";import{jwtExpiryMs as It,checkJwt as Et,handleApiError as Rt,diagnoseAuth as xe,planAuthHeal as Ne,readClientCredentialsFromEnv as Nt,buildClientCredentialsBody as Lt,clientCredentialsTokenUrl as Bt}from"./auth.js";import{cachlyUrl as N}from"./cachly-url.js";import{nutzungsSchluessel as jt}from"./werkzeug-nutzung.js";import{istLieferung as Ht,lieferSchluessel as Pt,tokenDerAntwort as Ot,hatTreffer as Mt,trefferSchluessel as Le}from"./geliefert.js";import{notify as Be}from"./notifier.js";import{fileURLToPath as je}from"node:url";import{createRequire as Dt}from"node:module";import{execFile as _e}from"node:child_process";const Jt=process.argv[1]!=null&&(process.argv[1]===je(import.meta.url)||process.argv[1].endsWith("/dist/index.js")||process.argv[1].endsWith("/src/index.ts"));import{Server as He}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Yt}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as Ut}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{CallToolRequestSchema as Pe,ErrorCode as ne,ListPromptsRequestSchema as Oe,ListResourceTemplatesRequestSchema as Me,ListResourcesRequestSchema as De,ListToolsRequestSchema as Je,McpError as Q}from"@modelcontextprotocol/sdk/types.js";import{Redis as Ye}from"ioredis";let x=process.env.CACHLY_API_URL??"https://api.cachly.dev",w=tt()??"";ae(w);const us=process.env.CACHLY_EMBED_MODEL??"",D=(()=>{try{const e=Dt(import.meta.url);for(const t of["../../package.json","../package.json"])try{const n=e(t);if(n.name==="@cachly-dev/mcp-server"&&n.version)return n.version}catch{}}catch{}return"0.10.100"})(),Wt=Number(process.env.CACHLY_PROVISION_TIMEOUT_MS??9e4);let H=Ae(process.env.CACHLY_BRAIN_INSTANCE_ID),X=0,ie=null,Ue=!1;async function Ft(){let e=[];try{G.getClientCapabilities()?.roots&&(e=(await G.listRoots(void 0,{timeout:3e3})).roots)}catch{}return cn({wurzeln:e,env:process.env,cwd:process.cwd(),dateiPfad:je})}function me(){return Ue?!/^(0|false|off|no|nein)$/i.test((process.env.CACHLY_STARTWISSEN??"").trim()):!1}function We(e){!e||!me()||nn({instanzId:e,verbindung:O,ausGit:t=>Se("brain_from_git",t,O,P),projektOrdner:Ft,einbetten:t=>Ke(t,{geduld:"lang"}),hatEinbettung:Xt,einbettenZweit:t=>Ke(t,{geduld:"lang",modell:eo}),melde:t=>S("brain_from_git",{...w?{api_key:w}:{},instance_id:e,total:t,auto:"startwissen"}),startvorrat:t=>ke("brain_seed_starter",t,O,P),meldeStartvorrat:t=>S("brain_seed_starter",{...w?{api_key:w}:{},instance_id:e,auto:!0},{seeded_count:t,auto:!0})})}function Fe(){return me()&&ln()}async function zt(){if(!w)return"";try{const e=await fetch(`${x}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${w}`,"Content-Type":"application/json"},signal:AbortSignal.timeout(12e3)});if(e.ok){const t=await e.json(),n=t.instance?.id??t.instance_id;if(n)return n}else fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`},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 ze(){if(H)return H;if(!w)return"";if(ie)return ie;const e=Date.now();if(X>0&&e-X<3e4)return"";X=e,ie=(async()=>{try{const t=await fetch(`${x}/api/v1/instances`,{headers:{Authorization:`Bearer ${w}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(t.ok){const s=(await t.json())?.data??[],o=s.find(i=>i.status==="running")??s.find(i=>i.status==="provisioning");if(o)return H=o.id,X=0,H;const c=await zt();if(c)return H=c,X=0,st(c,me(),Fe()),fe(c),We(c),H}}catch{}return""})();try{return await ie}finally{ie=null}}let $e=0;const qt=6e4;let se="";async function ge(e){try{const{writeFile:t,mkdir:n,readFile:s}=await import("node:fs/promises"),{existsSync:o}=await import("node:fs"),{resolve:c,dirname:i}=await import("node:path"),a=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!a)return;const d=c(a,".claude","mcp.json");let g={};if(o(d))try{g=JSON.parse(await s(d,"utf-8"))}catch{}g.mcpServers??={};const l=g.mcpServers.cachly;if(l)l.env??={},l.env.CACHLY_JWT=e;else{const y={};y.CACHLY_JWT=e,g.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:y}}await n(i(d),{recursive:!0}),await t(d,JSON.stringify(g,null,2),"utf-8");const u=[c(a,".cursor","mcp.json"),c(a,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(u.map(async y=>{if(o(y))try{const v=await s(y,"utf-8"),b=JSON.parse(v),p=b?.mcpServers?.cachly;p?.env&&(p.env.CACHLY_JWT=e,await t(y,JSON.stringify(b,null,2),"utf-8"))}catch{}}))}catch{}}async function fe(e){if(e){ot(e,{apiKey:w});try{const{writeFile:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),c=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!c)return;const i=[o(c,".claude","mcp.json"),o(c,".cursor","mcp.json"),o(c,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(i.map(async a=>{if(s(a))try{const d=JSON.parse(await n(a,"utf-8")),g=d?.mcpServers?.cachly;g?.env&&(g.env.CACHLY_BRAIN_INSTANCE_ID=e,await t(a,JSON.stringify(d,null,2),"utf-8"))}catch{}}))}catch{}}}async function Kt(){try{const e=await fetch(`${x}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`},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?(w=t.key,ae(t.key),ge(t.key),S("auth_self_healed",{reason:"near_expiry_refresh"}),!0):!1}catch{return!1}}async function Ce(){const e=xe(w),t=Ne(e);if(t==="none")return se="",!0;if(t==="refresh"){const n=Date.now();return n-$e>=qt&&($e=n,await Kt())?(se="",!0):(se=e.message,e.usable)}return se=e.message,!1}function re(e,t){const n=(i,a)=>{try{t?.(i,a)}catch{}},s=i=>{i?n(!1,i.code??i.message):n(!0)},o=ko(e);if(!o){n(!1,"keine-http-adresse");return}const c=To(o);try{process.platform==="win32"?_e("cmd",["/c","start","",c],{windowsHide:!0},s):process.platform==="darwin"?_e("open",[o],s):_e("xdg-open",[o],s)}catch(i){n(!1,i instanceof Error?i.message:"unknown")}}let K=null;async function Gt(){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(),n=t.verification_uri||N("/device","ambient-signin"),s=`${n}${n.includes("?")?"&":"?"}code=${encodeURIComponent(t.user_code)}`;return{deviceCode:t.device_code,userCode:t.user_code,verifyUrl:s,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 n=await t.json();return{deviceCode:n.device_code,userCode:n.user_code,verifyUrl:n.verification_uri_complete,pollInterval:(n.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}catch{return null}}async function Vt(e){if(Date.now()>e.deadline)return"expired";const t=async()=>{const s=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 s.ok?s.json():null},n=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 s=await t().catch(()=>null);if(s||(s=await n().catch(()=>null)),!s)return"pending";if(s.access_token){let o=s.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 i=await c.json();i.key&&(o=i.key)}}catch{}return w=o,ae(o),K=null,S("device_flow_completed"),ge(o),te(o),X=0,await ze(),H&&fe(H),"done"}return s.error==="slow_down"&&(e.pollInterval=Math.min(e.pollInterval+2e3,15e3)),"pending"}catch{return"pending"}}async function qe(e){if(e.polling)return"pending";e.polling=!0;try{return await Vt(e)}finally{e.polling=!1}}function Zt(e,t=qe,n=o=>K===o,s=Qt){const o=async()=>{if(!n(e))return;let c="pending";try{c=await t(e)}catch{}if(c!=="done"){if(c==="expired"){n(e)&&(K=null);return}n(e)&&s(o,e.pollInterval)}};s(o,e.pollInterval)}function Qt(e,t){const n=setTimeout(e,t);typeof n.unref=="function"&&n.unref()}import{setEmbedJwt as ae,computeEmbedding as Ke,hasEmbedProvider as Xt}from"./embeddings.js";import{ZWEIT_MODELL as eo}from"./rangfolge-stellschrauben.js";import{tokenize as to,splitMultiQuery as oo,levenshtein as no,recencyBoost as so,extractTimestamp as ro,STOPWORDS as io,katakanaToRomaji as ao,arabicLightStem as co,expandCrossLingual as lo,CROSS_LINGUAL_MAP as po,ZERO_RESULTS_LOG as uo,zeroResultsTotal as mo}from"./search.js";const ee=new Map;function go(e){return e<=1?200:null}async function O(e){if(!e)throw new Q(ne.InvalidRequest,`\u23F3 Your Brain instance is still being set up.
2
+ import{setzeClientKennung as It}from"./herkunft.js";import{jwtExpiryMs as Et,checkJwt as Rt,handleApiError as Nt,diagnoseAuth as xe,planAuthHeal as Ne,readClientCredentialsFromEnv as Lt,buildClientCredentialsBody as Bt,clientCredentialsTokenUrl as jt}from"./auth.js";import{cachlyUrl as N}from"./cachly-url.js";import{nutzungsSchluessel as Ht}from"./werkzeug-nutzung.js";import{istLieferung as Pt,lieferSchluessel as Ot,tokenDerAntwort as Mt,hatTreffer as Dt,trefferSchluessel as Le}from"./geliefert.js";import{notify as Be}from"./notifier.js";import{fileURLToPath as je}from"node:url";import{createRequire as Jt}from"node:module";import{execFile as _e}from"node:child_process";const Yt=process.argv[1]!=null&&(process.argv[1]===je(import.meta.url)||process.argv[1].endsWith("/dist/index.js")||process.argv[1].endsWith("/src/index.ts"));import{Server as He}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Ut}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as Wt}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{CallToolRequestSchema as Pe,ErrorCode as ne,ListPromptsRequestSchema as Oe,ListResourceTemplatesRequestSchema as Me,ListResourcesRequestSchema as De,ListToolsRequestSchema as Je,McpError as Q}from"@modelcontextprotocol/sdk/types.js";import{Redis as Ye}from"ioredis";let x=process.env.CACHLY_API_URL??"https://api.cachly.dev",w=ot()??"";ae(w);const ms=process.env.CACHLY_EMBED_MODEL??"",D=(()=>{try{const e=Jt(import.meta.url);for(const t of["../../package.json","../package.json"])try{const n=e(t);if(n.name==="@cachly-dev/mcp-server"&&n.version)return n.version}catch{}}catch{}return"0.10.100"})(),Ft=Number(process.env.CACHLY_PROVISION_TIMEOUT_MS??9e4);let H=Se(process.env.CACHLY_BRAIN_INSTANCE_ID),X=0,ie=null,Ue=!1;async function zt(){let e=[];try{G.getClientCapabilities()?.roots&&(e=(await G.listRoots(void 0,{timeout:3e3})).roots)}catch{}return ln({wurzeln:e,env:process.env,cwd:process.cwd(),dateiPfad:je})}function me(){return Ue?!/^(0|false|off|no|nein)$/i.test((process.env.CACHLY_STARTWISSEN??"").trim()):!1}function We(e){!e||!me()||sn({instanzId:e,verbindung:O,ausGit:t=>Ae("brain_from_git",t,O,P),projektOrdner:zt,einbetten:t=>Ke(t,{geduld:"lang"}),hatEinbettung:eo,einbettenZweit:t=>Ke(t,{geduld:"lang",modell:to}),melde:t=>A("brain_from_git",{...w?{api_key:w}:{},instance_id:e,total:t,auto:"startwissen"}),startvorrat:t=>ke("brain_seed_starter",t,O,P),meldeStartvorrat:t=>A("brain_seed_starter",{...w?{api_key:w}:{},instance_id:e,auto:!0},{seeded_count:t,auto:!0})})}function Fe(){return me()&&dn()}async function qt(){if(!w)return"";try{const e=await fetch(`${x}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${w}`,"Content-Type":"application/json"},signal:AbortSignal.timeout(12e3)});if(e.ok){const t=await e.json(),n=t.instance?.id??t.instance_id;if(n)return n}else fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`},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 ze(){if(H)return H;if(!w)return"";if(ie)return ie;const e=Date.now();if(X>0&&e-X<3e4)return"";X=e,ie=(async()=>{try{const t=await fetch(`${x}/api/v1/instances`,{headers:{Authorization:`Bearer ${w}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(t.ok){const s=(await t.json())?.data??[],o=s.find(i=>i.status==="running")??s.find(i=>i.status==="provisioning");if(o)return H=o.id,X=0,H;const c=await qt();if(c)return H=c,X=0,rt(c,me(),Fe()),fe(c),We(c),H}}catch{}return""})();try{return await ie}finally{ie=null}}let $e=0;const Kt=6e4;let se="";async function ge(e){try{const{writeFile:t,mkdir:n,readFile:s}=await import("node:fs/promises"),{existsSync:o}=await import("node:fs"),{resolve:c,dirname:i}=await import("node:path"),a=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!a)return;const d=c(a,".claude","mcp.json");let g={};if(o(d))try{g=JSON.parse(await s(d,"utf-8"))}catch{}g.mcpServers??={};const l=g.mcpServers.cachly;if(l)l.env??={},l.env.CACHLY_JWT=e;else{const y={};y.CACHLY_JWT=e,g.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:y}}await n(i(d),{recursive:!0}),await t(d,JSON.stringify(g,null,2),"utf-8");const m=[c(a,".cursor","mcp.json"),c(a,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(m.map(async y=>{if(o(y))try{const v=await s(y,"utf-8"),b=JSON.parse(v),u=b?.mcpServers?.cachly;u?.env&&(u.env.CACHLY_JWT=e,await t(y,JSON.stringify(b,null,2),"utf-8"))}catch{}}))}catch{}}async function fe(e){if(e){nt(e,{apiKey:w});try{const{writeFile:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),c=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!c)return;const i=[o(c,".claude","mcp.json"),o(c,".cursor","mcp.json"),o(c,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(i.map(async a=>{if(s(a))try{const d=JSON.parse(await n(a,"utf-8")),g=d?.mcpServers?.cachly;g?.env&&(g.env.CACHLY_BRAIN_INSTANCE_ID=e,await t(a,JSON.stringify(d,null,2),"utf-8"))}catch{}}))}catch{}}}async function Gt(){try{const e=await fetch(`${x}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`},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?(w=t.key,ae(t.key),ge(t.key),A("auth_self_healed",{reason:"near_expiry_refresh"}),!0):!1}catch{return!1}}async function Ce(){const e=xe(w),t=Ne(e);if(t==="none")return se="",!0;if(t==="refresh"){const n=Date.now();return n-$e>=Kt&&($e=n,await Gt())?(se="",!0):(se=e.message,e.usable)}return se=e.message,!1}function re(e,t){const n=(i,a)=>{try{t?.(i,a)}catch{}},s=i=>{i?n(!1,i.code??i.message):n(!0)},o=To(e);if(!o){n(!1,"keine-http-adresse");return}const c=Io(o);try{process.platform==="win32"?_e("cmd",["/c","start","",c],{windowsHide:!0},s):process.platform==="darwin"?_e("open",[o],s):_e("xdg-open",[o],s)}catch(i){n(!1,i instanceof Error?i.message:"unknown")}}let K=null;async function Vt(){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(),n=t.verification_uri||N("/device","ambient-signin"),s=`${n}${n.includes("?")?"&":"?"}code=${encodeURIComponent(t.user_code)}`;return{deviceCode:t.device_code,userCode:t.user_code,verifyUrl:s,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 n=await t.json();return{deviceCode:n.device_code,userCode:n.user_code,verifyUrl:n.verification_uri_complete,pollInterval:(n.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}catch{return null}}async function Zt(e){if(Date.now()>e.deadline)return"expired";const t=async()=>{const s=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 s.ok?s.json():null},n=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 s=await t().catch(()=>null);if(s||(s=await n().catch(()=>null)),!s)return"pending";if(s.access_token){let o=s.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 i=await c.json();i.key&&(o=i.key)}}catch{}return w=o,ae(o),K=null,A("device_flow_completed"),ge(o),te(o),X=0,await ze(),H&&fe(H),"done"}return s.error==="slow_down"&&(e.pollInterval=Math.min(e.pollInterval+2e3,15e3)),"pending"}catch{return"pending"}}async function qe(e){if(e.polling)return"pending";e.polling=!0;try{return await Zt(e)}finally{e.polling=!1}}function Qt(e,t=qe,n=o=>K===o,s=Xt){const o=async()=>{if(!n(e))return;let c="pending";try{c=await t(e)}catch{}if(c!=="done"){if(c==="expired"){n(e)&&(K=null);return}n(e)&&s(o,e.pollInterval)}};s(o,e.pollInterval)}function Xt(e,t){const n=setTimeout(e,t);typeof n.unref=="function"&&n.unref()}import{setEmbedJwt as ae,computeEmbedding as Ke,hasEmbedProvider as eo,EMBED_PROVIDER as Ge}from"./embeddings.js";import{ZWEIT_MODELL as to}from"./rangfolge-stellschrauben.js";import{tokenize as oo,splitMultiQuery as no,levenshtein as so,recencyBoost as ro,extractTimestamp as io,STOPWORDS as ao,katakanaToRomaji as co,arabicLightStem as lo,expandCrossLingual as po,CROSS_LINGUAL_MAP as uo,ZERO_RESULTS_LOG as mo,zeroResultsTotal as go}from"./search.js";const ee=new Map;function fo(e){return e<=1?200:null}async function O(e){if(!e)throw new Q(ne.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=ee.get(e);return t||tn(fo,e,()=>ho(e))}const fo=new Map;async function ho(e){W("verbindung: Instanz abfragen");let t=await P(`/api/v1/instances/${e}`);if(W(`verbindung: Instanz ${t.status}`),t=await en(t,()=>P(`/api/v1/instances/${e}`),{fristMs:Wt,melde:i=>W(`verbindung: Instanz ${i.status}`)}),t.status!=="running"){fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...w?{Authorization:`Bearer ${w}`}:{}},body:JSON.stringify({event:"instance_not_reachable",instance_id:e,status:t.status,version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{});let i;throw t.status==="provisioning"?i=`\u23F3 Brain instance "${t.name}" is still starting up.
9
+ \u2022 Reach us at support@cachly.dev.`);const t=ee.get(e);return t||on(ho,e,()=>yo(e))}const ho=new Map;async function yo(e){W("verbindung: Instanz abfragen");let t=await P(`/api/v1/instances/${e}`);if(W(`verbindung: Instanz ${t.status}`),t=await tn(t,()=>P(`/api/v1/instances/${e}`),{fristMs:Ft,melde:i=>W(`verbindung: Instanz ${i.status}`)}),t.status!=="running"){fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...w?{Authorization:`Bearer ${w}`}:{}},body:JSON.stringify({event:"instance_not_reachable",instance_id:e,status:t.status,version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{});let i;throw t.status==="provisioning"?i=`\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"?i=`\u274C Brain instance "${t.name}" failed to start.
12
12
 
@@ -18,52 +18,52 @@ Update your payment method at: ${N("/billing","upgrade")}`:t.status==="pending_p
18
18
  Complete your checkout at: ${N("/instances","upgrade")}`:i=`Brain instance "${t.name}" is not reachable (status: ${t.status}).
19
19
 
20
20
  \u2022 View your instance at: ${N("/instances","instance-error")}
21
- \u2022 Run \`get_api_status\` for a full diagnostic.`,new Q(ne.InvalidRequest,i)}if(!t.host||!t.port)throw new Q(ne.InternalError,`Instance "${t.name}" is running but has no host/port \u2014 contact support@cachly.dev.`);let n,s=t.tls_enabled!==!1;try{const i=await P(`/api/v1/instances/${e}/connection`);n=i.password??void 0,s=i.tls_enabled!==!1,W("verbindung: Zugangsdaten da")}catch(i){const a=i instanceof Error?i.message:String(i);if(a.includes("401")||a.includes("403")||a.includes("Unauthorized"))throw new Q(ne.InvalidRequest,"API key rejected \u2014 run `cachly setup` to refresh your credentials.")}const o=new Ye({host:t.host,port:t.port,password:n||void 0,commandTimeout:8e3,...s?{tls:{}}:{},lazyConnect:!0,enableReadyCheck:!0,connectTimeout:8e3,retryStrategy:go,maxRetriesPerRequest:1,keepAlive:15e3}),c=()=>{ee.delete(e),o.disconnect()};o.on("error",c),o.on("end",c);try{await o.connect()}catch(i){o.disconnect();const a=i instanceof Error?i.message:String(i);throw fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...w?{Authorization:`Bearer ${w}`}:{}},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 Q(ne.InternalError,`Could not reach Brain instance "${t.name}" (${t.host}:${t.port}).
21
+ \u2022 Run \`get_api_status\` for a full diagnostic.`,new Q(ne.InvalidRequest,i)}if(!t.host||!t.port)throw new Q(ne.InternalError,`Instance "${t.name}" is running but has no host/port \u2014 contact support@cachly.dev.`);let n,s=t.tls_enabled!==!1;try{const i=await P(`/api/v1/instances/${e}/connection`);n=i.password??void 0,s=i.tls_enabled!==!1,W("verbindung: Zugangsdaten da")}catch(i){const a=i instanceof Error?i.message:String(i);if(a.includes("401")||a.includes("403")||a.includes("Unauthorized"))throw new Q(ne.InvalidRequest,"API key rejected \u2014 run `cachly setup` to refresh your credentials.")}const o=new Ye({host:t.host,port:t.port,password:n||void 0,commandTimeout:8e3,...s?{tls:{}}:{},lazyConnect:!0,enableReadyCheck:!0,connectTimeout:8e3,retryStrategy:fo,maxRetriesPerRequest:1,keepAlive:15e3}),c=()=>{ee.delete(e),o.disconnect()};o.on("error",c),o.on("end",c);try{await o.connect()}catch(i){o.disconnect();const a=i instanceof Error?i.message:String(i);throw fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...w?{Authorization:`Bearer ${w}`}:{}},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 Q(ne.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 ee.set(e,o),W("verbindung: Valkey verbunden"),o}async function P(e,t={},n=!1){n||Ne(xe(w))!=="none"&&await Ce(),Et(w);const s=Number(process.env.CACHLY_API_TIMEOUT_MS??15e3),o=await fetch(`${x}${e}`,{...t,signal:AbortSignal.timeout(s),headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`,...t.headers}});if(!o.ok){if(o.status===401&&!n&&($e=0,await Ce()))return P(e,t,!0);const i=(await o.json().catch(()=>({error:o.statusText}))).error??o.statusText;Rt(o.status,i)}if(o.status!==204)return o.json()}import{handleBrainTool as yo}from"./handlers/brain.js";import{handleContextTool as bo}from"./handlers/context.js";import{handleInstanceTool as vo}from"./handlers/instances.js";import{handleCacheTool as wo}from"./handlers/cache.js";import{handleTeamTool as xo}from"./handlers/team.js";import{handleRoadmapTool as _o}from"./handlers/roadmap.js";import{handleAdvancedTool as $o}from"./handlers/advanced.js";import{handleSyndicateTool as Co}from"./handlers/syndicate.js";import{handleFedbrainTool as Se,_lastBrainFromGitCounts as he}from"./handlers/fedbrain.js";import{extractFirstRecallProof as So,renderFirstRecallProof as Ao}from"./first-recall-proof.js";import{installClsPostCommitHook as Ge,CLS_HOOK_VERSION as Ve}from"./cls-hook.js";import{gitLesen as Ze}from"./git-ohne-shell.js";import{browserAdresse as ko,fuerCmd as To}from"./browser-adresse.js";import{installAmbientHooks as Qe,installCursorHooks as Io,installCopilotHooks as Eo,installCodexHooks as Ro,installGeminiHooks as No,AMBIENT_HOOK_VERSION as Xe,COPILOT_HOOKS_DATEI as Lo,CODEX_HOOKS_DATEI as Bo,GEMINI_SETTINGS_DATEI as jo}from"./ambient-hooks.js";import{hookHauptlauf as Ho,auffrischenHauptlauf as Po}from"./ambient-hook.js";import{rahmeAntwort as Oo}from"./antwort-rahmen.js";import{appendLedgerEntry as Mo,readLedger as et,defaultLedgerPath as Do,reportLedgerEntry as Jo}from"./ambient-ledger.js";import{resolveApiKey as tt,saveApiKey as te,saveInstanceId as ot,readSavedApiKey as Yo}from"./credentials.js";import{KEYCLOAK_BASIS as nt,istTestSchluessel as Uo,waehleTestSchluessel as Wo,starteKeycloakAnmeldung as Fo,warteAufKeycloakAnmeldung as zo,uebernimm as qo,brainImKonto as Ko,erfolgsText as Go,fehlerText as Vo,ersetzeSchluessel as Zo}from"./uebernahme.js";import{holeSofortTest as Qo}from"./sofort-test.js";import{sichereZugang as Xo,echterWert as Ae}from"./zugang.js";import{zeitpunkt as W}from"./zeitmessung.js";import{warteAufLaufendeInstanz as en,gemeinsamerAufbau as tn}from"./instanz-warten.js";import{merkeNeuesBrain as st,startetLautLetztemBlick as on}from"./leeres-brain.js";import{starteStartwissen as nn,startwissenGestartet as sn,beanspruchStartwissen as rn,holeStartwissenHinweis as an,waehleProjektOrdner as cn,startvorratErlaubt as ln}from"./startwissen.js";import{eigeneFassung as dn,pruefeNeueFassung as pn,holeNeueFassungHinweis as un}from"./neue-fassung.js";import{beiStdinEnde as mn}from"./stdin-ende.js";import{merkeWerkzeugAufruf as gn,starteBrandWachhund as fn}from"./brand-wachhund.js";import{sichtbareWerkzeuge as hn,VERTEILER as rt}from"./werkzeug-auswahl.js";import{buildLessonsMarkdown as yn,buildLessonsJsonl as bn,vonRohLektion as vn}from"./brain-export.js";import{detectEditor as wn}from"./editor.js";import{milestoneSent as it,markMilestoneSent as at}from"./funnel-milestones.js";import{kostprobeUebrig as xn,kostprobeVerbrauchen as _n,kostprobeHinweis as $n,schrankeNachKostproben as Cn}from"./kostprobe.js";import{netBalance as Sn}from"./ambient-recall.js";import{handleShareTool as ke}from"./handlers/share.js";import{handleVizTool as An}from"./handlers/viz.js";import{commitArt as kn,istRueckbau as Tn,zaehleLektionen as In}from"./commit-art.js";import{TOOLS as ce}from"./tools.js";let ct=!1,ye=!1;function lt(){return wn()}function En(e){if(!e)return null;const t=e.match(/\*\*💡\s+([^*]+)\*\*/),n=e.match(/^>\s+(.+)$/m);if(!t||!n)return null;const s=t[1].trim(),o=n[1].trim();return!s||!o?null:{topic:s,what:o}}function Rn(e){try{const t=e.split(".");if(t.length!==3)return;const n=JSON.parse(Buffer.from(t[1],"base64url").toString("utf-8"));if(!n.sub)return;let s=2166136261;for(let o=0;o<n.sub.length;o++)s^=n.sub.charCodeAt(o),s=s*16777619>>>0;return s.toString(16).padStart(8,"0")+n.sub.length.toString(16).padStart(4,"0")}catch{return}}function S(e,t,n){if(process.env.CACHLY_NO_TELEMETRY==="1")return;const s=w?Rn(w):void 0;fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:e,version:D,editor:lt(),...w?{jwt:w}:{},...s?{user_fingerprint:s}:{},...n?{metrics:n}:{},...t}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}function Nn(e,t){return Jo({apiUrl:x,jwt:w,instanceId:e},t)}async function Ln(e){if(!ct&&process.env.CACHLY_NO_TELEMETRY!=="1"){ct=!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:lt(),tool:e}),signal:AbortSignal.timeout(3e3)})}catch{}}}const Bn=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"]),jn={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."},dt=N("/billing","upgrade"),pt=new Map;async function Hn(e){const t=pt.get(e);if(t&&t.expiresAt>Date.now())return t.info;try{const s=((await P(`/api/v1/instances/${e}`))?.tier??"free").toLowerCase(),o={tier:s,isFree:s==="free"||s===""};return pt.set(e,{info:o,expiresAt:Date.now()+6e4}),o}catch{return{tier:"unknown",isFree:!1}}}async function Pn(e,t){if(!Bn.has(e)||!t)return null;const{isFree:n}=await Hn(t);if(!n)return null;const s=jn[e]??"A Premium intelligence feature.";if(xn(e)){const o=_n(e);return{kostprobe:$n(e,o,dt)}}return{sperre:Cn(e,s,dt)}}async function On(e,t){try{await(await O(e)).hincrby(jt(e),t,1)}catch{}}async function Mn(e,t,n){if(Ht(t))try{const s=await O(e),o=Mt(n);await s.incrby(Pt(e),o?Ot(n):0),await s.hincrby(Le(e),"abrufe",1),o&&await s.hincrby(Le(e),"treffer",1)}catch{}}async function Dn(e){const t=await Gt();return t?(K=t,S("device_flow_started",{tool:e}),re(t.verifyUrl,(n,s)=>{if(n){S("device_browser_opened",{stelle:"tool"});return}S("device_browser_failed",{reason:s??"unknown",stelle:"tool"}),process.stderr.write(`
25
+ \u2022 Technical detail: ${a}`)}return ee.set(e,o),W("verbindung: Valkey verbunden"),o}async function P(e,t={},n=!1){n||Ne(xe(w))!=="none"&&await Ce(),Rt(w);const s=Number(process.env.CACHLY_API_TIMEOUT_MS??15e3),o=await fetch(`${x}${e}`,{...t,signal:AbortSignal.timeout(s),headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`,...t.headers}});if(!o.ok){if(o.status===401&&!n&&($e=0,await Ce()))return P(e,t,!0);const i=(await o.json().catch(()=>({error:o.statusText}))).error??o.statusText;Nt(o.status,i)}if(o.status!==204)return o.json()}import{handleBrainTool as bo}from"./handlers/brain.js";import{handleContextTool as vo}from"./handlers/context.js";import{handleInstanceTool as wo}from"./handlers/instances.js";import{handleCacheTool as xo}from"./handlers/cache.js";import{handleTeamTool as _o}from"./handlers/team.js";import{handleRoadmapTool as $o}from"./handlers/roadmap.js";import{handleAdvancedTool as Co}from"./handlers/advanced.js";import{handleSyndicateTool as Ao}from"./handlers/syndicate.js";import{handleFedbrainTool as Ae,_lastBrainFromGitCounts as he}from"./handlers/fedbrain.js";import{extractFirstRecallProof as So,renderFirstRecallProof as ko}from"./first-recall-proof.js";import{installClsPostCommitHook as Ve,CLS_HOOK_VERSION as Ze}from"./cls-hook.js";import{gitLesen as Qe}from"./git-ohne-shell.js";import{browserAdresse as To,fuerCmd as Io}from"./browser-adresse.js";import{installAmbientHooks as Xe,installCursorHooks as Eo,installCopilotHooks as Ro,installCodexHooks as No,installGeminiHooks as Lo,AMBIENT_HOOK_VERSION as et,COPILOT_HOOKS_DATEI as Bo,CODEX_HOOKS_DATEI as jo,GEMINI_SETTINGS_DATEI as Ho}from"./ambient-hooks.js";import{hookHauptlauf as Po,auffrischenHauptlauf as Oo}from"./ambient-hook.js";import{rahmeAntwort as Mo}from"./antwort-rahmen.js";import{appendLedgerEntry as Do,readLedger as tt,defaultLedgerPath as Jo,reportLedgerEntry as Yo}from"./ambient-ledger.js";import{resolveApiKey as ot,saveApiKey as te,saveInstanceId as nt,readSavedApiKey as Uo}from"./credentials.js";import{KEYCLOAK_BASIS as st,istTestSchluessel as Wo,waehleTestSchluessel as Fo,starteKeycloakAnmeldung as zo,warteAufKeycloakAnmeldung as qo,uebernimm as Ko,brainImKonto as Go,erfolgsText as Vo,fehlerText as Zo,ersetzeSchluessel as Qo}from"./uebernahme.js";import{holeSofortTest as Xo}from"./sofort-test.js";import{sichereZugang as en,echterWert as Se}from"./zugang.js";import{zeitpunkt as W}from"./zeitmessung.js";import{warteAufLaufendeInstanz as tn,gemeinsamerAufbau as on}from"./instanz-warten.js";import{merkeNeuesBrain as rt,startetLautLetztemBlick as nn}from"./leeres-brain.js";import{starteStartwissen as sn,startwissenGestartet as rn,beanspruchStartwissen as an,holeStartwissenHinweis as cn,waehleProjektOrdner as ln,startvorratErlaubt as dn}from"./startwissen.js";import{eigeneFassung as pn,pruefeNeueFassung as un,holeNeueFassungHinweis as mn}from"./neue-fassung.js";import{beiStdinEnde as gn}from"./stdin-ende.js";import{merkeWerkzeugAufruf as fn,starteBrandWachhund as hn}from"./brand-wachhund.js";import{sichtbareWerkzeuge as yn,VERTEILER as it}from"./werkzeug-auswahl.js";import{buildLessonsMarkdown as bn,buildLessonsJsonl as vn,vonRohLektion as wn}from"./brain-export.js";import{detectEditor as xn}from"./editor.js";import{milestoneSent as at,markMilestoneSent as ct}from"./funnel-milestones.js";import{kostprobeUebrig as _n,kostprobeVerbrauchen as $n,kostprobeHinweis as Cn,schrankeNachKostproben as An}from"./kostprobe.js";import{netBalance as Sn}from"./ambient-recall.js";import{handleShareTool as ke}from"./handlers/share.js";import{handleVizTool as kn}from"./handlers/viz.js";import{commitArt as Tn,istRueckbau as In,zaehleLektionen as En}from"./commit-art.js";import{TOOLS as ce}from"./tools.js";let lt=!1,ye=!1;function dt(){return xn()}function Rn(e){if(!e)return null;const t=e.match(/\*\*💡\s+([^*]+)\*\*/),n=e.match(/^>\s+(.+)$/m);if(!t||!n)return null;const s=t[1].trim(),o=n[1].trim();return!s||!o?null:{topic:s,what:o}}function Nn(e){try{const t=e.split(".");if(t.length!==3)return;const n=JSON.parse(Buffer.from(t[1],"base64url").toString("utf-8"));if(!n.sub)return;let s=2166136261;for(let o=0;o<n.sub.length;o++)s^=n.sub.charCodeAt(o),s=s*16777619>>>0;return s.toString(16).padStart(8,"0")+n.sub.length.toString(16).padStart(4,"0")}catch{return}}function A(e,t,n){if(process.env.CACHLY_NO_TELEMETRY==="1")return;const s=w?Nn(w):void 0;fetch(`${x}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:e,version:D,editor:dt(),...w?{jwt:w}:{},...s?{user_fingerprint:s}:{},...n?{metrics:n}:{},...t}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}function Ln(e,t){return Yo({apiUrl:x,jwt:w,instanceId:e},t)}async function Bn(e){if(!lt&&process.env.CACHLY_NO_TELEMETRY!=="1"){lt=!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:dt(),tool:e}),signal:AbortSignal.timeout(3e3)})}catch{}}}const jn=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"]),Hn={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."},pt=N("/billing","upgrade"),ut=new Map;async function Pn(e){const t=ut.get(e);if(t&&t.expiresAt>Date.now())return t.info;try{const s=((await P(`/api/v1/instances/${e}`))?.tier??"free").toLowerCase(),o={tier:s,isFree:s==="free"||s===""};return ut.set(e,{info:o,expiresAt:Date.now()+6e4}),o}catch{return{tier:"unknown",isFree:!1}}}async function On(e,t){if(!jn.has(e)||!t)return null;const{isFree:n}=await Pn(t);if(!n)return null;const s=Hn[e]??"A Premium intelligence feature.";if(_n(e)){const o=$n(e);return{kostprobe:Cn(e,o,pt)}}return{sperre:An(e,s,pt)}}async function Mn(e,t){try{await(await O(e)).hincrby(Ht(e),t,1)}catch{}}async function Dn(e,t,n){if(Pt(t))try{const s=await O(e),o=Dt(n);await s.incrby(Ot(e),o?Mt(n):0),await s.hincrby(Le(e),"abrufe",1),o&&await s.hincrby(Le(e),"treffer",1)}catch{}}async function Jn(e){const t=await Vt();return t?(K=t,A("device_flow_started",{tool:e}),re(t.verifyUrl,(n,s)=>{if(n){A("device_browser_opened",{stelle:"tool"});return}A("device_browser_failed",{reason:s??"unknown",stelle:"tool"}),process.stderr.write(`
26
26
  cachly: could not open a browser (${s??"unknown"}).
27
27
  cachly: open this yourself to finish signing in:
28
28
  cachly: ${t.verifyUrl}
29
29
  cachly: code ${t.userCode}
30
30
 
31
- `)}),Zt(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 ${ce.length} MCP tools \xB7 GDPR \xB7 EU servers \xB7 free tier, no credit card`].join(`
31
+ `)}),Qt(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 ${ce.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: ${N("/setup-ai","ambient-signin")}`,"","\u2728 Free tier includes: 1 Brain instance, persistent memory, semantic search."].join(`
33
- `)}async function Jn(e){if(!e)return!0;if(sn(e))return!1;try{return await rn(await O(e),"sitzungsstart")}catch{return!0}}async function U(e,t){if(!w){if(Ln(e),K){const r=await qe(K);return r==="done"?U(e,t):r==="expired"?(S("device_flow_failed",{reason:"timeout"}),K=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: **${K.verifyUrl}**`,`Code: **${K.userCode}**`,"","This completes automatically once you sign in \u2014 no need to come back here."].join(`
34
- `)}return Xo({schluessel:w,konfigurierteInstanz:H,aufrufInstanz:t.instance_id,werkzeugName:e,holeSofortTest:async()=>{W("sofort-test: Anfang");const r=await Qo({apiUrl:x,version:D,speichern:()=>{}});return W(`sofort-test: ${r?"Brain angelegt":"kein Test"}`),r&&st(r.instanzId,me(),Fe()),r},ablagen:{setzeSchluessel:r=>{w=r},setEmbedJwt:ae,saveApiKey:r=>te(r),persistApiKeyToConfig:ge,merkeInstanz:r=>{H=r,X=0},persistInstanceIdToConfig:fe},meldeEreignis:S,werkzeug:()=>U(e,t),anmelden:()=>Dn(e),neuesBrain:We})}if(!t.instance_id){const r=await ze();r&&(t={...t,instance_id:r})}const n=await Pn(e,t.instance_id);let s="";if(n!==null){if("sperre"in n)return S("premium_gate_hit",{tool:e,instance_id:t.instance_id??""}),n.sperre;s=n.kostprobe,S("premium_taste_used",{tool:e,instance_id:t.instance_id??""})}typeof t.instance_id=="string"&&t.instance_id&&On(t.instance_id,e),W(`werkzeug ${e}: Zugang und Tarif geklaert`);const o=await yo(e,t,O,P);if(W(`werkzeug ${e}: Brain-Werkzeug fertig`),o!==null){typeof t.instance_id=="string"&&t.instance_id&&Mn(t.instance_id,e,String(o??"")),!ye&&w&&(ye=!0,it("first_call_success")||(at("first_call_success"),S("first_call_success",{tool:e,instance_id:t.instance_id??H??""})));const r=t.instance_id??H??"",m=w?{api_key:w,instance_id:r}:{instance_id:r};if(e==="recall_best_solution")S("recall_best_solution",m);else if(e==="learn_from_attempts")S("learn_from_attempts",m);else if(e==="session_start"){S("session_start",m,{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??""),k=h.includes("Welcome! Your AI Brain is live.");if(!on(r)){if(!k&&h.length>100)S("recall_best_solution",m);else if(k&&t.workspace_path&&await Jn(r))try{const I=await Se("brain_from_git",{instance_id:r,repo_path:t.workspace_path,limit:50},O,P);if(I!==null){S("brain_from_git",{...m,...he??{}}),S("recall_best_solution",m);let T="";if((he?.total??0)===0)try{const j=await ke("brain_seed_starter",{instance_id:r},O,P);j&&(S("brain_seed_starter",{...m,auto:!0},{seeded_count:16,auto:!0}),T=`
33
+ `)}async function Yn(e){if(!e)return!0;if(rn(e))return!1;try{return await an(await O(e),"sitzungsstart")}catch{return!0}}async function U(e,t){if(!w){if(Bn(e),K){const r=await qe(K);return r==="done"?U(e,t):r==="expired"?(A("device_flow_failed",{reason:"timeout"}),K=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: **${K.verifyUrl}**`,`Code: **${K.userCode}**`,"","This completes automatically once you sign in \u2014 no need to come back here."].join(`
34
+ `)}return en({schluessel:w,konfigurierteInstanz:H,aufrufInstanz:t.instance_id,werkzeugName:e,holeSofortTest:async()=>{W("sofort-test: Anfang");const r=await Xo({apiUrl:x,version:D,speichern:()=>{}});return W(`sofort-test: ${r?"Brain angelegt":"kein Test"}`),r&&rt(r.instanzId,me(),Fe()),r},ablagen:{setzeSchluessel:r=>{w=r},setEmbedJwt:ae,saveApiKey:r=>te(r),persistApiKeyToConfig:ge,merkeInstanz:r=>{H=r,X=0},persistInstanceIdToConfig:fe},meldeEreignis:A,werkzeug:()=>U(e,t),anmelden:()=>Jn(e),neuesBrain:We})}if(!t.instance_id){const r=await ze();r&&(t={...t,instance_id:r})}const n=await On(e,t.instance_id);let s="";if(n!==null){if("sperre"in n)return A("premium_gate_hit",{tool:e,instance_id:t.instance_id??""}),n.sperre;s=n.kostprobe,A("premium_taste_used",{tool:e,instance_id:t.instance_id??""})}typeof t.instance_id=="string"&&t.instance_id&&Mn(t.instance_id,e),W(`werkzeug ${e}: Zugang und Tarif geklaert`);const o=await bo(e,t,O,P);if(W(`werkzeug ${e}: Brain-Werkzeug fertig`),o!==null){typeof t.instance_id=="string"&&t.instance_id&&Dn(t.instance_id,e,String(o??"")),!ye&&w&&(ye=!0,at("first_call_success")||(ct("first_call_success"),A("first_call_success",{tool:e,instance_id:t.instance_id??H??""})));const r=t.instance_id??H??"",p=w?{api_key:w,instance_id:r}:{instance_id:r};if(e==="recall_best_solution")A("recall_best_solution",p);else if(e==="learn_from_attempts")A("learn_from_attempts",p);else if(e==="session_start"){A("session_start",p,{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(!nn(r)){if(!T&&h.length>100)A("recall_best_solution",p);else if(T&&t.workspace_path&&await Yn(r))try{const I=await Ae("brain_from_git",{instance_id:r,repo_path:t.workspace_path,limit:50},O,P);if(I!==null){A("brain_from_git",{...p,...he??{}}),A("recall_best_solution",p);let k="";if((he?.total??0)===0)try{const j=await ke("brain_seed_starter",{instance_id:r},O,P);j&&(A("brain_seed_starter",{...p,auto:!0},{seeded_count:16,auto:!0}),k=`
35
35
  ---
36
36
  `+String(j))}catch{}const E=String(I),$=he?.total??0,C=$>0?`
37
- \u2705 **Brain bootstrapped from git \u2014 ${$} lesson${$===1?"":"s"} loaded.** Your AI already knows your history.`:"";if(E||T||C)return String(o)+C+`
37
+ \u2705 **Brain bootstrapped from git \u2014 ${$} lesson${$===1?"":"s"} loaded.** Your AI already knows your history.`:"";if(E||k||C)return String(o)+C+`
38
38
  ---
39
- `+E+T}}catch(I){return S("brain_from_git_failed",{...m,reason:I instanceof Error?I.message.slice(0,120):"unknown"}),String(o)+`
39
+ `+E+k}}catch(I){return A("brain_from_git_failed",{...p,reason:I instanceof Error?I.message.slice(0,120):"unknown"}),String(o)+`
40
40
 
41
41
  > \u26A0\uFE0F **Auto-bootstrap from git history failed** \u2014 your Brain is live but starts empty.
42
- > Run \`brain_from_git(instance_id="`+r+'", 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",m);else if(e==="smart_recall"){const h=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),k=h.length>50&&!h.includes("No lessons found")&&!h.includes("no lessons")&&!h.includes("No matches found");if(S("smart_recall",m,{hit:k,topic:String(t.query??"").slice(0,80)}),k&&S("recall_best_solution",m),se&&typeof o=="string")return`> \u26A0\uFE0F **Brain auth degraded** \u2014 ${se.split(`
42
+ > Run \`brain_from_git(instance_id="`+r+'", 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")A("session_end",p);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(A("smart_recall",p,{hit:T,topic:String(t.query??"").slice(0,80)}),T&&A("recall_best_solution",p),se&&typeof o=="string")return`> \u26A0\uFE0F **Brain auth degraded** \u2014 ${se.split(`
43
43
  `)[0]}
44
44
 
45
- ${o}`}return o}const c=await bo(e,t,O,P);if(c!==null)return!ye&&w&&(ye=!0,it("first_call_success")||(at("first_call_success"),S("first_call_success",{tool:e,instance_id:t.instance_id??H??""}))),c;const i=await vo(e,t,O,P);if(i!==null)return i;const a=await wo(e,t,O,P);if(a!==null)return a;const d=r=>s?r+s:r,g=await xo(e,t,O,P);if(g!==null)return d(g);const l=await _o(e,t,O,P);if(l!==null)return l;const u=await $o(e,t,O,P);if(u!==null)return d(u);const y=await Co(e,t,O,P);if(y!==null){if(e==="brain_predict"){const r=t.instance_id??H??"";S("brain_predict",w?{api_key:w,instance_id:r}:{instance_id:r})}return d(y)}const v=await ke(e,t,O,P);if(v!==null)return v;const b=await An(e,t,O,P);if(b!==null)return b;const p=await Se(e,t,O,P);if(p!==null){const r=t.instance_id??H??"",m=w?{api_key:w,instance_id:r}:{instance_id:r};if(e==="brain_from_git"){const h=he;S("brain_from_git",{...m,...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",m);return p}switch(e){case"get_api_status":{let r="unknown";try{const I=await fetch(`${x}/health`,{signal:AbortSignal.timeout(8e3)});if(I.ok){const A=await I.json();r=`${A.status??"ok"} (db: ${A.db??"?"})`}else r=`HTTP ${I.status}`}catch(I){r=`unreachable: ${I.message}`}if(!w)return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${x}`,` \u{1F493} Health: ${r}`," \u{1F511} Auth: \u274C CACHLY_JWT not set","",`\u{1F4A1} Get your API token at ${N("/instances","api-status")} \u2192 Settings \u2192 API Token`].join(`
46
- `);let m="\u274C invalid JWT format";try{const I=w.split(".");if(I.length===3){const A=JSON.parse(Buffer.from(I[1],"base64url").toString("utf-8")),T=A.sub??"(unknown)",E=A.iss??"(unknown)",$=E.includes("keycloak")?"Keycloak":"OIDC",C=A.exp?new Date(A.exp*1e3):null,j=C?C<new Date:!1;m=["\u2705 JWT decoded",` Sub (user ID): ${T}`,` Provider: ${$}`,` Issuer: ${E}`,` Expires: ${C?C.toISOString():"never"} ${j?"\u26A0\uFE0F EXPIRED \u2013 get a new token!":"\u2705"}`].join(`
47
- `)}}catch{m="\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=`
45
+ ${o}`}return o}const c=await vo(e,t,O,P);if(c!==null)return!ye&&w&&(ye=!0,at("first_call_success")||(ct("first_call_success"),A("first_call_success",{tool:e,instance_id:t.instance_id??H??""}))),c;const i=await wo(e,t,O,P);if(i!==null)return i;const a=await xo(e,t,O,P);if(a!==null)return a;const d=r=>s?r+s:r,g=await _o(e,t,O,P);if(g!==null)return d(g);const l=await $o(e,t,O,P);if(l!==null)return l;const m=await Co(e,t,O,P);if(m!==null)return d(m);const y=await Ao(e,t,O,P);if(y!==null){if(e==="brain_predict"){const r=t.instance_id??H??"";A("brain_predict",w?{api_key:w,instance_id:r}:{instance_id:r})}return d(y)}const v=await ke(e,t,O,P);if(v!==null)return v;const b=await kn(e,t,O,P);if(b!==null)return b;const u=await Ae(e,t,O,P);if(u!==null){const r=t.instance_id??H??"",p=w?{api_key:w,instance_id:r}:{instance_id:r};if(e==="brain_from_git"){const h=he;A("brain_from_git",{...p,...h??{}},h?{fixes:h.fixes,features:h.features,refactors:h.refactors,total:h.total}:void 0)}else e==="brain_predict_failures"&&A("brain_predict_failures",p);return u}switch(e){case"get_api_status":{let r="unknown";try{const I=await fetch(`${x}/health`,{signal:AbortSignal.timeout(8e3)});if(I.ok){const S=await I.json();r=`${S.status??"ok"} (db: ${S.db??"?"})`}else r=`HTTP ${I.status}`}catch(I){r=`unreachable: ${I.message}`}if(!w)return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${x}`,` \u{1F493} Health: ${r}`," \u{1F511} Auth: \u274C CACHLY_JWT not set","",`\u{1F4A1} Get your API token at ${N("/instances","api-status")} \u2192 Settings \u2192 API Token`].join(`
46
+ `);let p="\u274C invalid JWT format";try{const I=w.split(".");if(I.length===3){const S=JSON.parse(Buffer.from(I[1],"base64url").toString("utf-8")),k=S.sub??"(unknown)",E=S.iss??"(unknown)",$=E.includes("keycloak")?"Keycloak":"OIDC",C=S.exp?new Date(S.exp*1e3):null,j=C?C<new Date:!1;p=["\u2705 JWT decoded",` Sub (user ID): ${k}`,` Provider: ${$}`,` Issuer: ${E}`,` Expires: ${C?C.toISOString():"never"} ${j?"\u26A0\uFE0F EXPIRED \u2013 get a new token!":"\u2705"}`].join(`
47
+ `)}}catch{p="\u274C JWT decode failed \u2013 check CACHLY_JWT format"}let h="";try{const S=(await P("/api/v1/instances")).data??[];if(S.length===0)h=`
48
48
 
49
- \u{1F9E0} **Brain Instances:** none \u2014 create one at ${N("/instances","api-status")}`;else{const T=[`
49
+ \u{1F9E0} **Brain Instances:** none \u2014 create one at ${N("/instances","api-status")}`;else{const k=[`
50
50
 
51
- \u{1F9E0} **Brain Instances:**`];for(const E of A){const $=E.status==="running"?"\u{1F7E2}":E.status==="provisioning"?"\u{1F7E1}":"\u{1F534}",C=E.id===H?" \u2190 active":"";if(T.push(` ${$} **${E.name}** (\`${E.id}\`) \xB7 ${E.status}${C}`),E.status==="running"&&E.host){const j=ee.get(E.id);if(j)try{await j.ping(),T.push(" \u{1F493} Redis: connected")}catch{T.push(" \u26A0\uFE0F Redis: pooled but ping failed \u2014 will reconnect on next use")}else T.push(" \u{1F4A4} Redis: not connected yet (connects on first tool use)")}else E.status==="provisioning"?T.push(" \u23F3 Still provisioning \u2014 check back in ~30 s"):E.status!=="running"&&T.push(` \u274C Not reachable (status: ${E.status})`)}h=T.join(`
51
+ \u{1F9E0} **Brain Instances:**`];for(const E of S){const $=E.status==="running"?"\u{1F7E2}":E.status==="provisioning"?"\u{1F7E1}":"\u{1F534}",C=E.id===H?" \u2190 active":"";if(k.push(` ${$} **${E.name}** (\`${E.id}\`) \xB7 ${E.status}${C}`),E.status==="running"&&E.host){const j=ee.get(E.id);if(j)try{await j.ping(),k.push(" \u{1F493} Redis: connected")}catch{k.push(" \u26A0\uFE0F Redis: pooled but ping failed \u2014 will reconnect on next use")}else k.push(" \u{1F4A4} Redis: not connected yet (connects on first tool use)")}else E.status==="provisioning"?k.push(" \u23F3 Still provisioning \u2014 check back in ~30 s"):E.status!=="running"&&k.push(` \u274C Not reachable (status: ${E.status})`)}h=k.join(`
52
52
  `)}}catch(I){h=`
53
53
 
54
- \u{1F9E0} **Brain Instances:** could not fetch \u2014 ${I.message}`}await Ce();const k=xe(w),B=k.state==="long_lived"?"\u{1F6E1}\uFE0F Self-healing: \u2705 long-lived API key (won't expire silently)":k.state==="healthy"?`\u{1F6E1}\uFE0F Self-healing: \u2705 token valid${k.expiresInMs?` (${Math.round(k.expiresInMs/36e5)}h left)`:""}`:k.state==="near_expiry"?"\u{1F6E1}\uFE0F Self-healing: \u267B\uFE0F token near expiry \u2014 auto-refresh attempted":`\u{1F6E1}\uFE0F Self-healing: \u26A0\uFE0F ${k.message.split(`
55
- `)[0]}`;return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${x}`,` \u{1F493} Health: ${r}`,` ${B}`,"","\u{1F511} **Auth:**",m,h].join(`
56
- `)}default:throw new ut(`Unknown tool: ${e}`)}}class ut extends Error{}const mt=`This project has a Cachly AI Brain \u2014 persistent, cross-session memory of past fixes, decisions, and gotchas for THIS codebase. Use it proactively; it makes you faster and stops you repeating known mistakes.
54
+ \u{1F9E0} **Brain Instances:** could not fetch \u2014 ${I.message}`}await Ce();const T=xe(w),B=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(`
55
+ `)[0]}`;return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${x}`,` \u{1F493} Health: ${r}`,` ${B}`,"","\u{1F511} **Auth:**",p,h].join(`
56
+ `)}default:throw new mt(`Unknown tool: ${e}`)}}class mt extends Error{}const gt=`This project has a Cachly AI Brain \u2014 persistent, cross-session memory of past fixes, decisions, and gotchas for THIS codebase. Use it proactively; it makes you faster and stops you repeating known mistakes.
57
57
 
58
58
  - BEFORE a non-trivial task: call smart_recall with a short description of what you're about to do. If it returns lessons, apply them before researching from scratch.
59
59
  - WHEN debugging an error: call causal_trace with the exact error first \u2014 a known fix may already exist.
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.`,gt={tools:{},resources:{},prompts:{}},ft=async()=>{const{katalog:e,unbekannteKernnamen:t}=hn(ce);return t.length>0&&console.error(`cachly: ${t.length} Kernwerkzeug(e) gibt es gar nicht: ${t.join(", ")}`),{tools:e}};async function ht(){return{resources:[]}}async function yt(){return{resourceTemplates:[]}}async function bt(){return{prompts:[]}}function Yn(e){e.setRequestHandler(Je,ft),e.setRequestHandler(Pe,xt),e.setRequestHandler(De,ht),e.setRequestHandler(Me,yt),e.setRequestHandler(Oe,bt)}function Un(){const e=new He({name:"cachly-mcp",version:D},{capabilities:gt,instructions:mt});return Yn(e),vt(e),e}function vt(e){const t=e.oninitialized;e.oninitialized=()=>{try{const n=e.getClientVersion();Tt(n?.name,n?.version)}catch{}t?.()}}const G=new He({name:"cachly-mcp",version:D},{capabilities:gt,instructions:mt});vt(G),G.setRequestHandler(Je,ft),G.setRequestHandler(De,ht),G.setRequestHandler(Me,yt),G.setRequestHandler(Oe,bt);let Te=null,le=!1,V=null,wt=0;async function Wn(e){if(!le){if(V){await V;return}V=(async()=>{le=!0,Te=e;try{await U("session_start",{instance_id:e,focus:"auto (MCP session)",workspace_path:process.cwd()})}catch{}finally{V=null}})(),await V,process.env.CACHLY_AUTO_INDEX!=="false"&&(async()=>{const t=await O(e),n=await t.get(`cachly:index:last_indexed:${e}`),s=1440*60*1e3;(!n||Date.now()-parseInt(n,10)>s)&&(await t.set(`cachly:index:last_indexed:${e}`,String(Date.now()),"EX",9e4),await U("index_project",{instance_id:e,dir:process.cwd(),max_files:150,ttl:86400*7,namespace:"cachly:sem:code",hintergrund:!0}))})().catch(()=>{})}}async function Ie(){if(!(!le||!Te)){le=!1;try{await U("session_end",{instance_id:Te,summary:`Auto-ended after ${wt} tool call(s). Session was started automatically.`,files_changed:[],lessons_learned:0})}catch{}}}const xt=async e=>{let{name:t,arguments:n}=e.params;if(t===rt){const o=n??{},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 i=ce.find(a=>a.name===c);if(!i)return{content:[{type:"text",text:`Kein Werkzeug namens "${c}". Die Liste steht in der Beschreibung von ${rt}.`}],isError:!0};if(o.describe===!0)return{content:[{type:"text",text:JSON.stringify({name:i.name,description:i.description,inputSchema:i.inputSchema},null,2)}]};t=c,n=o.arguments??{}}const s=new Set(["session_start","session_start_summary","session_end","auto_learn_session"]);if(!s.has(t)&&!le&&!V){const o=Ae(n?.instance_id)||H||Ae(process.env.CACHLY_BRAIN_INSTANCE_ID);o&&await Wn(o).catch(()=>{})}else V&&await V.catch(()=>{});s.has(t)||wt++;try{gn(),W(`werkzeug ${t}: Anfang`);const o=await U(t,n??{});return W(`werkzeug ${t}: Antwort fertig`),{content:[{type:"text",text:Oo(t,o)+an()+un(t)}]}}catch(o){if(o instanceof ut)return{content:[{type:"text",text:o.message}],isError:!0};if(o instanceof Q)throw o;const c=o.message??String(o);throw Be("cachly","tool_error",{tool:t,error:c}).catch(()=>{}),new Q(ne.InternalError,c)}};G.setRequestHandler(Pe,xt),process.on("SIGTERM",async()=>{await Ie().catch(()=>{});for(const[,e]of ee)await e.quit().catch(()=>{});process.exit(0)}),process.on("SIGINT",async()=>{await Ie().catch(()=>{});for(const[,e]of ee)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}
63
+ The Brain instance id comes from the CACHLY_BRAIN_INSTANCE_ID environment variable.`,ft={tools:{},resources:{},prompts:{}},ht=async()=>{const{katalog:e,unbekannteKernnamen:t}=yn(ce);return t.length>0&&console.error(`cachly: ${t.length} Kernwerkzeug(e) gibt es gar nicht: ${t.join(", ")}`),{tools:e}};async function yt(){return{resources:[]}}async function bt(){return{resourceTemplates:[]}}async function vt(){return{prompts:[]}}function Un(e){e.setRequestHandler(Je,ht),e.setRequestHandler(Pe,_t),e.setRequestHandler(De,yt),e.setRequestHandler(Me,bt),e.setRequestHandler(Oe,vt)}function Wn(){const e=new He({name:"cachly-mcp",version:D},{capabilities:ft,instructions:gt});return Un(e),wt(e),e}function wt(e){const t=e.oninitialized;e.oninitialized=()=>{try{const n=e.getClientVersion();It(n?.name,n?.version)}catch{}t?.()}}const G=new He({name:"cachly-mcp",version:D},{capabilities:ft,instructions:gt});wt(G),G.setRequestHandler(Je,ht),G.setRequestHandler(De,yt),G.setRequestHandler(Me,bt),G.setRequestHandler(Oe,vt);let Te=null,le=!1,V=null,xt=0;async function Fn(e){if(!le){if(V){await V;return}V=(async()=>{le=!0,Te=e;try{await U("session_start",{instance_id:e,focus:"auto (MCP session)",workspace_path:process.cwd()})}catch{}finally{V=null}})(),await V,process.env.CACHLY_AUTO_INDEX!=="false"&&(async()=>{const t=await O(e),n=await t.get(`cachly:index:last_indexed:${e}`),s=1440*60*1e3;(!n||Date.now()-parseInt(n,10)>s)&&(await t.set(`cachly:index:last_indexed:${e}`,String(Date.now()),"EX",9e4),await U("index_project",{instance_id:e,dir:process.cwd(),max_files:150,ttl:86400*7,namespace:"cachly:sem:code",hintergrund:!0}))})().catch(()=>{})}}async function Ie(){if(!(!le||!Te)){le=!1;try{await U("session_end",{instance_id:Te,summary:`Auto-ended after ${xt} tool call(s). Session was started automatically.`,files_changed:[],lessons_learned:0})}catch{}}}const _t=async e=>{let{name:t,arguments:n}=e.params;if(t===it){const o=n??{},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 i=ce.find(a=>a.name===c);if(!i)return{content:[{type:"text",text:`Kein Werkzeug namens "${c}". Die Liste steht in der Beschreibung von ${it}.`}],isError:!0};if(o.describe===!0)return{content:[{type:"text",text:JSON.stringify({name:i.name,description:i.description,inputSchema:i.inputSchema},null,2)}]};t=c,n=o.arguments??{}}const s=new Set(["session_start","session_start_summary","session_end","auto_learn_session"]);if(!s.has(t)&&!le&&!V){const o=Se(n?.instance_id)||H||Se(process.env.CACHLY_BRAIN_INSTANCE_ID);o&&await Fn(o).catch(()=>{})}else V&&await V.catch(()=>{});s.has(t)||xt++;try{fn(),W(`werkzeug ${t}: Anfang`);const o=await U(t,n??{});return W(`werkzeug ${t}: Antwort fertig`),{content:[{type:"text",text:Mo(t,o)+cn()+mn(t)}]}}catch(o){if(o instanceof mt)return{content:[{type:"text",text:o.message}],isError:!0};if(o instanceof Q)throw o;const c=o.message??String(o);throw Be("cachly","tool_error",{tool:t,error:c}).catch(()=>{}),new Q(ne.InternalError,c)}};G.setRequestHandler(Pe,_t),process.on("SIGTERM",async()=>{await Ie().catch(()=>{});for(const[,e]of ee)await e.quit().catch(()=>{});process.exit(0)}),process.on("SIGINT",async()=>{await Ie().catch(()=>{});for(const[,e]of ee)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
- `)}),process.stdout.on("error",()=>{}),process.stdin.on("error",()=>{});const be={claude:".mcp.json",cursor:".cursor/mcp.json",windsurf:".windsurf/mcp.json",copilot:".vscode/mcp.json",continue:".continue/config.json",cline:".vscode/mcp.json",zed:".zed/settings.json"};function Fn(e,t){const n=Object.entries(t).map(([s,o])=>`${s}=${o}`);return e==="codex"?{befehl:`codex mcp add cachly ${n.map(s=>`--env ${s}`).join(" ")} -- npx -y @cachly-dev/mcp-server@latest`,wo:"~/.codex/config.toml"}:e==="gemini"?{befehl:`gemini mcp add -s project ${n.map(s=>`-e ${s}`).join(" ")} cachly npx -- -y @cachly-dev/mcp-server@latest`,wo:".gemini/settings.json"}:null}const Ee="<!-- cachly-brain-start -->",_t="<!-- cachly-brain-end -->",$t="https://api.cachly.dev";function oe(e,t,n={}){const s={CACHLY_BRAIN_INSTANCE_ID:t};return n.includeApiKey&&(s.CACHLY_JWT=e),x&&x!==$t&&(s.CACHLY_API_URL=x),s}function zn(e,t,n){return n==="continue"?JSON.stringify({experimental:{modelContextProtocolServers:[{transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:oe(e,t)}]}},null,2):n==="zed"?JSON.stringify({context_servers:{cachly:{command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(e,t)},settings:{}}}},null,2):Ct(n)?JSON.stringify({servers:{cachly:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(e,t)}}},null,2):JSON.stringify({mcpServers:{cachly:{command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(e,t)}}},null,2)}function Ct(e){return be[e]===".vscode/mcp.json"}function de(e,t){Uo(e)||te(e,t)}async function St(e,t,n,s,o,c={}){const i={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(t,n)};if(!o.existsSync(e))return zn(t,n,s);let a={};try{a=JSON.parse(await o.readFile(e,"utf-8"))}catch{try{const{rename:u}=await import("node:fs/promises");await u(e,e+".bak"),process.stderr.write(`\u26A0\uFE0F ${e} was not valid JSON \u2014 backed up to ${e}.bak
66
- `)}catch{}}if(s==="continue"){const u=a.experimental??{},y=u.modelContextProtocolServers??[];let v;for(const p of y){const r=p.env??{};if(r.CACHLY_JWT){v=r.CACHLY_JWT;break}}v&&de(v,c);const b=y.filter(p=>{const r=p.env??{};return!r.CACHLY_JWT&&!r.CACHLY_BRAIN_INSTANCE_ID});return b.push({transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:i.env}),a.experimental={...u,modelContextProtocolServers:b},JSON.stringify(a,null,2)}if(s==="zed"){const u=a.context_servers??{},v=u.cachly?.command?.env?.CACHLY_JWT;return v&&de(v,c),u.cachly={command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:i.env},settings:{}},a.context_servers=u,JSON.stringify(a,null,2)}if(Ct(s)){const u=a.mcpServers??void 0,v=u?.cachly?.env?.CACHLY_JWT;v&&de(v,c),u&&"cachly"in u&&(delete u.cachly,Object.keys(u).length===0&&delete a.mcpServers);const b=a.servers??{},p=b.cachly,r=p?.env?.CACHLY_JWT;return r&&de(r,c),b.cachly=p?.envFile?{type:"stdio",...i,envFile:p.envFile}:{type:"stdio",...i},a.servers=b,JSON.stringify(a,null,2)}const d=a.mcpServers??{},l=d.cachly?.env?.CACHLY_JWT;return l&&de(l,c),d.cachly=i,a.mcpServers=d,JSON.stringify(a,null,2)}function At(e){return`${Ee}
65
+ `)}),process.stdout.on("error",()=>{}),process.stdin.on("error",()=>{});const be={claude:".mcp.json",cursor:".cursor/mcp.json",windsurf:".windsurf/mcp.json",copilot:".vscode/mcp.json",continue:".continue/config.json",cline:".vscode/mcp.json",zed:".zed/settings.json"};function zn(e,t){const n=Object.entries(t).map(([s,o])=>`${s}=${o}`);return e==="codex"?{befehl:`codex mcp add cachly ${n.map(s=>`--env ${s}`).join(" ")} -- npx -y @cachly-dev/mcp-server@latest`,wo:"~/.codex/config.toml"}:e==="gemini"?{befehl:`gemini mcp add -s project ${n.map(s=>`-e ${s}`).join(" ")} cachly npx -- -y @cachly-dev/mcp-server@latest`,wo:".gemini/settings.json"}:null}const Ee="<!-- cachly-brain-start -->",$t="<!-- cachly-brain-end -->",Ct="https://api.cachly.dev";function oe(e,t,n={}){const s={CACHLY_BRAIN_INSTANCE_ID:t};return n.includeApiKey&&(s.CACHLY_JWT=e),x&&x!==Ct&&(s.CACHLY_API_URL=x),s}function qn(e,t,n){return n==="continue"?JSON.stringify({experimental:{modelContextProtocolServers:[{transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:oe(e,t)}]}},null,2):n==="zed"?JSON.stringify({context_servers:{cachly:{command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(e,t)},settings:{}}}},null,2):At(n)?JSON.stringify({servers:{cachly:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(e,t)}}},null,2):JSON.stringify({mcpServers:{cachly:{command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(e,t)}}},null,2)}function At(e){return be[e]===".vscode/mcp.json"}function de(e,t){Wo(e)||te(e,t)}async function St(e,t,n,s,o,c={}){const i={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(t,n)};if(!o.existsSync(e))return qn(t,n,s);let a={};try{a=JSON.parse(await o.readFile(e,"utf-8"))}catch{try{const{rename:m}=await import("node:fs/promises");await m(e,e+".bak"),process.stderr.write(`\u26A0\uFE0F ${e} was not valid JSON \u2014 backed up to ${e}.bak
66
+ `)}catch{}}if(s==="continue"){const m=a.experimental??{},y=m.modelContextProtocolServers??[];let v;for(const u of y){const r=u.env??{};if(r.CACHLY_JWT){v=r.CACHLY_JWT;break}}v&&de(v,c);const b=y.filter(u=>{const r=u.env??{};return!r.CACHLY_JWT&&!r.CACHLY_BRAIN_INSTANCE_ID});return b.push({transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:i.env}),a.experimental={...m,modelContextProtocolServers:b},JSON.stringify(a,null,2)}if(s==="zed"){const m=a.context_servers??{},v=m.cachly?.command?.env?.CACHLY_JWT;return v&&de(v,c),m.cachly={command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:i.env},settings:{}},a.context_servers=m,JSON.stringify(a,null,2)}if(At(s)){const m=a.mcpServers??void 0,v=m?.cachly?.env?.CACHLY_JWT;v&&de(v,c),m&&"cachly"in m&&(delete m.cachly,Object.keys(m).length===0&&delete a.mcpServers);const b=a.servers??{},u=b.cachly,r=u?.env?.CACHLY_JWT;return r&&de(r,c),b.cachly=u?.envFile?{type:"stdio",...i,envFile:u.envFile}:{type:"stdio",...i},a.servers=b,JSON.stringify(a,null,2)}const d=a.mcpServers??{},l=d.cachly?.env?.CACHLY_JWT;return l&&de(l,c),d.cachly=i,a.mcpServers=d,JSON.stringify(a,null,2)}function kt(e){return`${Ee}
67
67
  ## Cachly AI Brain \u2014 Always Active
68
68
 
69
69
  The Brain MCP server runs automatically. Instance: \`${e}\`
@@ -118,31 +118,31 @@ Report predicted failure risks to the user before proceeding.
118
118
 
119
119
  ### Half-finished code rule:
120
120
  Never commit code that does not compile. Run \`tsc --noEmit\` / \`go build ./...\` before every commit.
121
- ${_t}`}const qn=`---
121
+ ${$t}`}const Kn=`---
122
122
  description: Cachly AI Brain \u2014 persistent memory protocol (recall before tasks, learn after fixes)
123
123
  alwaysApply: true
124
124
  ---
125
125
 
126
- `;async function kt(e,t){const{writeFile:n,appendFile:s,readFile:o,mkdir:c}=await import("node:fs/promises"),{existsSync:i}=await import("node:fs"),{resolve:a,dirname:d}=await import("node:path"),g=[{path:a(e,"CLAUDE.md")},{path:a(e,"AGENTS.md")},{path:a(e,".github","copilot-instructions.md")},{path:a(e,".cursor","rules","cachly.mdc"),prefix:qn},{path:a(e,".windsurfrules")},{path:a(e,".clinerules")},...i(a(e,".idea"))?[{path:a(e,".aiassistant","rules","cachly.md")}]:[]],l=`
127
- `+At(t)+`
128
- `,u={};for(const{path:y,prefix:v}of g){if(await c(d(y),{recursive:!0}),i(y)){const b=await o(y,"utf-8");if(b.includes(Ee)){const p=b.replace(new RegExp(`${Ee}[\\s\\S]*?${_t}`),At(t));await n(y,p,"utf-8"),u[y]="updated";continue}await s(y,l,"utf-8"),u[y]="appended";continue}await n(y,(v??"")+l.trimStart(),"utf-8"),u[y]="written"}return u}if(process.argv[2]==="digest"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
126
+ `;async function Tt(e,t){const{writeFile:n,appendFile:s,readFile:o,mkdir:c}=await import("node:fs/promises"),{existsSync:i}=await import("node:fs"),{resolve:a,dirname:d}=await import("node:path"),g=[{path:a(e,"CLAUDE.md")},{path:a(e,"AGENTS.md")},{path:a(e,".github","copilot-instructions.md")},{path:a(e,".cursor","rules","cachly.mdc"),prefix:Kn},{path:a(e,".windsurfrules")},{path:a(e,".clinerules")},...i(a(e,".idea"))?[{path:a(e,".aiassistant","rules","cachly.md")}]:[]],l=`
127
+ `+kt(t)+`
128
+ `,m={};for(const{path:y,prefix:v}of g){if(await c(d(y),{recursive:!0}),i(y)){const b=await o(y,"utf-8");if(b.includes(Ee)){const u=b.replace(new RegExp(`${Ee}[\\s\\S]*?${$t}`),kt(t));await n(y,u,"utf-8"),m[y]="updated";continue}await s(y,l,"utf-8"),m[y]="appended";continue}await n(y,(v??"")+l.trimStart(),"utf-8"),m[y]="written"}return m}if(process.argv[2]==="digest"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
129
129
  \u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
130
130
  `),process.exit(1)),process.stdout.write(`
131
131
  \u{1F9E0} Fetching your weekly Brain digest...
132
132
 
133
- `);try{const n=await fetch(`${x}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)});if(!n.ok)throw new Error(`stats HTTP ${n.status}`);const s=await n.json(),o=s.lesson_count??0,c=s.total_recall_count??0,i=Math.round(s.iq_boost_pct??0),a=(s.top_lessons??[]).slice(0,5),d=s.team_authors??[],g=c*1200,l=(g*3e-6).toFixed(2),u=o<10?"Junior Dev \u{1F527}":o<30?"Mid Dev \u26A1":o<60?"Senior Dev \u{1F9E0}":o<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}",y=new Date,v=new Date(y);v.setDate(y.getDate()-7);const b=h=>h.toLocaleDateString("en-US",{month:"short",day:"numeric"});if(console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log(`\u2502 \x1B[1m\u{1F9E0} Brain Weekly Digest\x1B[0m \x1B[90m${b(v)} \u2013 ${b(y)}\x1B[0m \u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Total lessons : \x1B[33m${String(o).padEnd(8)}\x1B[0m Brain level : \x1B[32m${u.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Total recalls : \x1B[36m${String(c).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(i).padEnd(3)}%\x1B[0m \u2502`),console.log(`\u2502 Tokens saved : \x1B[32m${(Math.round(g/1e3)+"K").padEnd(8)}\x1B[0m Cost saved : \x1B[32m$${l.padEnd(20)}\x1B[0m\u2502`),d.length>0&&(console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 \x1B[36m\u{1F465} Team contributors:\x1B[0m ${d.slice(0,5).join(", ").slice(0,42).padEnd(42)} \u2502`)),a.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[33m\u{1F525} Most recalled lessons this week:\x1B[0m \u2502");for(const h of a){const k=`${h.topic}: ${h.what_worked}`.slice(0,57);console.log(`\u2502 \x1B[90m\u2022 ${k.padEnd(58)}\x1B[0m\u2502`)}}console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("");const p=a[0],r=[`\u{1F9E0} My AI Brain weekly digest (${b(v)} \u2013 ${b(y)}):`,"",` \u{1F4DA} ${o} lessons learned`,` \u{1F501} ${c} recalls \xB7 ~${Math.round(g/1e3)}K tokens saved`,` \u{1F3AF} Brain Level: ${u}`,p?` \u{1F525} Top lesson: "${p.topic}: ${p.what_worked.slice(0,60)}${p.what_worked.length>60?"\u2026":""}"`:"","","Built with @cachly_dev \u2014 AI that actually remembers \u{1F680}","cachly.dev"].filter(Boolean).join(`
134
- `),m="https://twitter.com/intent/tweet?text="+encodeURIComponent(r);console.log("\x1B[1m\u{1F4E3} Share your digest:\x1B[0m"),console.log(""),console.log("\x1B[90m"+"\u2500".repeat(63)+"\x1B[0m");for(const h of r.split(`
135
- `))console.log(` ${h}`);console.log("\x1B[90m"+"\u2500".repeat(63)+"\x1B[0m"),console.log(""),console.log(" \x1B[36m\u{1F426} Tweet this:\x1B[0m"),console.log(` \x1B[4m${m.slice(0,90)}...\x1B[0m`),console.log(""),console.log(" \x1B[2m\u{1F4A1} Invite your team: npx @cachly-dev/mcp-server@latest invite\x1B[0m"),console.log(" \x1B[2m Cron: 0 9 * * 1 npx @cachly-dev/mcp-server@latest digest\x1B[0m"),console.log("")}catch(n){console.log(`
133
+ `);try{const n=await fetch(`${x}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)});if(!n.ok)throw new Error(`stats HTTP ${n.status}`);const s=await n.json(),o=s.lesson_count??0,c=s.total_recall_count??0,i=Math.round(s.iq_boost_pct??0),a=(s.top_lessons??[]).slice(0,5),d=s.team_authors??[],g=c*1200,l=(g*3e-6).toFixed(2),m=o<10?"Junior Dev \u{1F527}":o<30?"Mid Dev \u26A1":o<60?"Senior Dev \u{1F9E0}":o<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}",y=new Date,v=new Date(y);v.setDate(y.getDate()-7);const b=h=>h.toLocaleDateString("en-US",{month:"short",day:"numeric"});if(console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log(`\u2502 \x1B[1m\u{1F9E0} Brain Weekly Digest\x1B[0m \x1B[90m${b(v)} \u2013 ${b(y)}\x1B[0m \u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Total lessons : \x1B[33m${String(o).padEnd(8)}\x1B[0m Brain level : \x1B[32m${m.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Total recalls : \x1B[36m${String(c).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(i).padEnd(3)}%\x1B[0m \u2502`),console.log(`\u2502 Tokens saved : \x1B[32m${(Math.round(g/1e3)+"K").padEnd(8)}\x1B[0m Cost saved : \x1B[32m$${l.padEnd(20)}\x1B[0m\u2502`),d.length>0&&(console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 \x1B[36m\u{1F465} Team contributors:\x1B[0m ${d.slice(0,5).join(", ").slice(0,42).padEnd(42)} \u2502`)),a.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[33m\u{1F525} Most recalled lessons this week:\x1B[0m \u2502");for(const h of a){const T=`${h.topic}: ${h.what_worked}`.slice(0,57);console.log(`\u2502 \x1B[90m\u2022 ${T.padEnd(58)}\x1B[0m\u2502`)}}console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("");const u=a[0],r=[`\u{1F9E0} My AI Brain weekly digest (${b(v)} \u2013 ${b(y)}):`,"",` \u{1F4DA} ${o} lessons learned`,` \u{1F501} ${c} recalls \xB7 ~${Math.round(g/1e3)}K tokens saved`,` \u{1F3AF} Brain Level: ${m}`,u?` \u{1F525} Top lesson: "${u.topic}: ${u.what_worked.slice(0,60)}${u.what_worked.length>60?"\u2026":""}"`:"","","Built with @cachly_dev \u2014 AI that actually remembers \u{1F680}","cachly.dev"].filter(Boolean).join(`
134
+ `),p="https://twitter.com/intent/tweet?text="+encodeURIComponent(r);console.log("\x1B[1m\u{1F4E3} Share your digest:\x1B[0m"),console.log(""),console.log("\x1B[90m"+"\u2500".repeat(63)+"\x1B[0m");for(const h of r.split(`
135
+ `))console.log(` ${h}`);console.log("\x1B[90m"+"\u2500".repeat(63)+"\x1B[0m"),console.log(""),console.log(" \x1B[36m\u{1F426} Tweet this:\x1B[0m"),console.log(` \x1B[4m${p.slice(0,90)}...\x1B[0m`),console.log(""),console.log(" \x1B[2m\u{1F4A1} Invite your team: npx @cachly-dev/mcp-server@latest invite\x1B[0m"),console.log(" \x1B[2m Cron: 0 9 * * 1 npx @cachly-dev/mcp-server@latest digest\x1B[0m"),console.log("")}catch(n){console.log(`
136
136
  \u274C Could not fetch digest: ${n.message}
137
137
  `),process.exit(1)}process.exit(0)}if(process.argv[2]==="export"){const{writeFile:e,mkdir:t}=await import("node:fs/promises"),{resolve:n}=await import("node:path"),s=process.argv.slice(3),o=g=>{const l=s.indexOf(`--${g}`);return l!==-1?s[l+1]:void 0},c=o("format")??"both";c!=="md"&&c!=="jsonl"&&c!=="both"&&(console.log(`
138
138
  \u274C Unknown --format "${c}" \u2014 use md, jsonl, or both.
139
- `),process.exit(1));const i=n(o("out")??"."),a=w||tt()||"",d=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!a||!d)&&(console.log(`
139
+ `),process.exit(1));const i=n(o("out")??"."),a=w||ot()||"",d=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!a||!d)&&(console.log(`
140
140
  \u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
141
141
  `),process.exit(1)),process.stdout.write(`
142
142
  \u{1F4E4} Exporting your Brain...
143
143
 
144
- `);try{let g=[],l="";const u=await fetch(`${x}/api/v1/instances/${d}/export`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(12e4)});if(u.ok){const v=await u.json();g=(v.lessons??[]).map(vn).filter(b=>b!==null),v.complete===!1&&(l=v.note??"the server reported an incomplete read")}else if(u.status===404){const v=await fetch(`${x}/api/v1/instances/${d}/memory`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(8e3)});if(!v.ok)throw new Error(`memory HTTP ${v.status}`);g=((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 ${u.status}`);g.length===0&&(console.log(` No lessons in this Brain yet \u2014 nothing to export.
145
- `),process.exit(0)),await t(i,{recursive:!0});const y=[];if(c==="md"||c==="both"){const v=n(i,"lessons.md");await e(v,yn(g),"utf-8"),y.push(`${g.length} lesson${g.length===1?"":"s"} \u2192 ${v}`)}if(c==="jsonl"||c==="both"){const v=n(i,"lessons.jsonl");await e(v,bn(g),"utf-8"),y.push(`${g.length} lesson${g.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 y)console.log(` ${v}`);console.log("")}catch(g){console.log(`
144
+ `);try{let g=[],l="";const m=await fetch(`${x}/api/v1/instances/${d}/export`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(12e4)});if(m.ok){const v=await m.json();g=(v.lessons??[]).map(wn).filter(b=>b!==null),v.complete===!1&&(l=v.note??"the server reported an incomplete read")}else if(m.status===404){const v=await fetch(`${x}/api/v1/instances/${d}/memory`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(8e3)});if(!v.ok)throw new Error(`memory HTTP ${v.status}`);g=((await v.json()).top_lessons??[]).map(u=>({topic:u.topic,outcome:u.outcome,severity:u.severity,tags:u.tags,whatWorked:u.what_worked,ts:u.ts,author:u.author,recallCount:u.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 ${m.status}`);g.length===0&&(console.log(` No lessons in this Brain yet \u2014 nothing to export.
145
+ `),process.exit(0)),await t(i,{recursive:!0});const y=[];if(c==="md"||c==="both"){const v=n(i,"lessons.md");await e(v,bn(g),"utf-8"),y.push(`${g.length} lesson${g.length===1?"":"s"} \u2192 ${v}`)}if(c==="jsonl"||c==="both"){const v=n(i,"lessons.jsonl");await e(v,vn(g),"utf-8"),y.push(`${g.length} lesson${g.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 y)console.log(` ${v}`);console.log("")}catch(g){console.log(`
146
146
  \u274C Could not export your Brain: ${g.message}
147
147
  `),process.exit(1)}process.exit(0)}if(process.argv[2]==="invite"){const e=process.env.CACHLY_JWT??"";e||(console.log(`
148
148
  \u26A0\uFE0F CACHLY_JWT must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
@@ -159,25 +159,25 @@ Try it free: ${s}
159
159
  \u274C Usage: npx @cachly-dev/mcp-server@latest join <token>
160
160
  `),console.log(` Get a token from a teammate: npx @cachly-dev/mcp-server@latest invite
161
161
  `),process.exit(1)),console.log(`
162
- \u23F3 Looking up invite...`);let g;try{const A=await fetch(`${x}/api/invite/${d}`,{signal:AbortSignal.timeout(8e3)});A.status===404&&(console.log(`
162
+ \u23F3 Looking up invite...`);let g;try{const S=await fetch(`${x}/api/invite/${d}`,{signal:AbortSignal.timeout(8e3)});S.status===404&&(console.log(`
163
163
  \u274C Invite not found \u2014 the link may be invalid.
164
- `),process.exit(1)),A.status===410&&(console.log(`
164
+ `),process.exit(1)),S.status===410&&(console.log(`
165
165
  \u274C This invite link has expired (7-day limit).
166
- `),process.exit(1)),A.ok||(console.log(`
167
- \u274C Could not fetch invite: HTTP ${A.status}
168
- `),process.exit(1)),g=await A.json()}catch(A){console.log(`
169
- \u274C Network error: ${A.message}
170
- `),process.exit(1)}const{instance_id:l,instance_name:u,tier:y,label:v}=g,b=new Date(g.expires_at).toLocaleDateString();console.log(""),console.log(" \x1B[35m\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\x1B[0m"),console.log(" \x1B[35m\u2551\x1B[0m \x1B[1m\u{1F9E0} Brain Invite\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log(" \x1B[35m\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\x1B[0m"),console.log(""),console.log(` Brain : \x1B[1m${u}\x1B[0m`),console.log(` Tier : ${y}`),v&&console.log(` Note : ${v}`),console.log(` Expires : ${b}`),console.log("");const p=a({input:process.stdin,output:process.stdout}),r=await new Promise(A=>{p.question(" Join this Brain? [Y/n] ",T=>{p.close(),A(T.trim().toLowerCase()||"y")})});r!=="y"&&r!=="yes"&&(console.log(`
166
+ `),process.exit(1)),S.ok||(console.log(`
167
+ \u274C Could not fetch invite: HTTP ${S.status}
168
+ `),process.exit(1)),g=await S.json()}catch(S){console.log(`
169
+ \u274C Network error: ${S.message}
170
+ `),process.exit(1)}const{instance_id:l,instance_name:m,tier:y,label:v}=g,b=new Date(g.expires_at).toLocaleDateString();console.log(""),console.log(" \x1B[35m\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\x1B[0m"),console.log(" \x1B[35m\u2551\x1B[0m \x1B[1m\u{1F9E0} Brain Invite\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log(" \x1B[35m\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\x1B[0m"),console.log(""),console.log(` Brain : \x1B[1m${m}\x1B[0m`),console.log(` Tier : ${y}`),v&&console.log(` Note : ${v}`),console.log(` Expires : ${b}`),console.log("");const u=a({input:process.stdin,output:process.stdout}),r=await new Promise(S=>{u.question(" Join this Brain? [Y/n] ",k=>{u.close(),S(k.trim().toLowerCase()||"y")})});r!=="y"&&r!=="yes"&&(console.log(`
171
171
  Cancelled.
172
- `),process.exit(0));let m=w;if(!m){console.log(`
172
+ `),process.exit(0));let p=w;if(!p){console.log(`
173
173
  No API key found \u2014 starting sign-in (10 seconds)...
174
- `);try{const A=await fetch(`${x}/api/v1/auth/device/code`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_id:"cachly-mcp-cli"}),signal:AbortSignal.timeout(1e4)});if(A.ok){const T=await A.json();console.log(` \u{1F449} Open: \x1B[36m${T.verification_uri}\x1B[0m`),console.log(` Code: \x1B[1m${T.user_code}\x1B[0m
175
- `);const E=(T.interval??5)*1e3;for(let $=0;$<24;$++){await new Promise(C=>setTimeout(C,E));try{const C=await fetch(`${x}/api/v1/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:T.device_code,client_id:"cachly-mcp-cli"}),signal:AbortSignal.timeout(8e3)});if(C.ok){const j=await C.json();if(j.access_token){m=j.access_token;break}}}catch{}}m||(console.log(`
174
+ `);try{const S=await fetch(`${x}/api/v1/auth/device/code`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_id:"cachly-mcp-cli"}),signal:AbortSignal.timeout(1e4)});if(S.ok){const k=await S.json();console.log(` \u{1F449} Open: \x1B[36m${k.verification_uri}\x1B[0m`),console.log(` Code: \x1B[1m${k.user_code}\x1B[0m
175
+ `);const E=(k.interval??5)*1e3;for(let $=0;$<24;$++){await new Promise(C=>setTimeout(C,E));try{const C=await fetch(`${x}/api/v1/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:k.device_code,client_id:"cachly-mcp-cli"}),signal:AbortSignal.timeout(8e3)});if(C.ok){const j=await C.json();if(j.access_token){p=j.access_token;break}}}catch{}}p||(console.log(`
176
176
  \u274C Sign-in timed out. Run the command again.
177
177
  `),process.exit(1)),console.log(` \u2705 Signed in!
178
- `)}}catch(A){console.log(`
179
- \u26A0\uFE0F Could not start sign-in: ${A.message}`),console.log(` Set CACHLY_JWT manually from ${N("/setup-ai","join")}
180
- `),process.exit(1)}}const h=process.cwd(),k=i(),B=[{label:".mcp.json (Claude Code project)",path:o(h,".mcp.json")},{label:".cursor/mcp.json",path:o(h,".cursor","mcp.json")},{label:".windsurf/mcp.json",path:o(h,".windsurf","mcp.json")},{label:".vscode/mcp.json (Copilot/Cline)",path:o(h,".vscode","mcp.json")},{label:"~/.claude/mcp.json (global)",path:o(k,".claude","mcp.json"),global:!0}];let I=0;for(const{label:A,path:T,global:E}of B){const $=c(T);if(!(!E&&!s($)&&!s(T)))try{await n($,{recursive:!0});let C={};if(s(T))try{C=JSON.parse(await t(T,"utf-8"))}catch{try{await(await import("node:fs/promises")).rename(T,T+".bak")}catch{}}const j=C.mcpServers??{},F=j.cachly??{},z=F.env??{};z.CACHLY_BRAIN_INSTANCE_ID=l,m&&!z.CACHLY_JWT&&(z.CACHLY_JWT=m),x!==$t&&(z.CACHLY_API_URL=x),j.cachly={...F,command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:z},C.mcpServers=j,await e(T,JSON.stringify(C,null,2),"utf-8"),console.log(` \u2705 ${A}`),I++}catch(C){C.code!=="ENOENT"&&console.log(` \u26A0\uFE0F ${A}: ${C.message}`)}}console.log(""),I===0?console.log(" \u26A0\uFE0F No editor configs found \u2014 run `cachly setup` first.\n"):(console.log(` \u{1F9E0} You're now sharing Brain: \x1B[1m${u}\x1B[0m`),console.log(` Restart your editor \u2014 your AI arrives pre-briefed from the team Brain.
178
+ `)}}catch(S){console.log(`
179
+ \u26A0\uFE0F Could not start sign-in: ${S.message}`),console.log(` Set CACHLY_JWT manually from ${N("/setup-ai","join")}
180
+ `),process.exit(1)}}const h=process.cwd(),T=i(),B=[{label:".mcp.json (Claude Code project)",path:o(h,".mcp.json")},{label:".cursor/mcp.json",path:o(h,".cursor","mcp.json")},{label:".windsurf/mcp.json",path:o(h,".windsurf","mcp.json")},{label:".vscode/mcp.json (Copilot/Cline)",path:o(h,".vscode","mcp.json")},{label:"~/.claude/mcp.json (global)",path:o(T,".claude","mcp.json"),global:!0}];let I=0;for(const{label:S,path:k,global:E}of B){const $=c(k);if(!(!E&&!s($)&&!s(k)))try{await n($,{recursive:!0});let C={};if(s(k))try{C=JSON.parse(await t(k,"utf-8"))}catch{try{await(await import("node:fs/promises")).rename(k,k+".bak")}catch{}}const j=C.mcpServers??{},F=j.cachly??{},z=F.env??{};z.CACHLY_BRAIN_INSTANCE_ID=l,p&&!z.CACHLY_JWT&&(z.CACHLY_JWT=p),x!==Ct&&(z.CACHLY_API_URL=x),j.cachly={...F,command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:z},C.mcpServers=j,await e(k,JSON.stringify(C,null,2),"utf-8"),console.log(` \u2705 ${S}`),I++}catch(C){C.code!=="ENOENT"&&console.log(` \u26A0\uFE0F ${S}: ${C.message}`)}}console.log(""),I===0?console.log(" \u26A0\uFE0F No editor configs found \u2014 run `cachly setup` first.\n"):(console.log(` \u{1F9E0} You're now sharing Brain: \x1B[1m${m}\x1B[0m`),console.log(` Restart your editor \u2014 your AI arrives pre-briefed from the team Brain.
181
181
  `),console.log(" \u{1F4DB} Add the badge to your README:"),console.log(` npx @cachly-dev/mcp-server@latest badge
182
182
  `)),process.exit(0)}if(process.argv[2]==="upgrade"){process.stdout.write(`
183
183
  \u23F3 Checking for updates...
@@ -185,20 +185,20 @@ Try it free: ${s}
185
185
  \u2705 Already on the latest version: \x1B[32mv${D}\x1B[0m
186
186
  `):(console.log(""),console.log("\x1B[35m \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\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly update available\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \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\x1B[0m"),console.log(""),console.log(` Current : \x1B[31mv${D}\x1B[0m`),console.log(` Latest : \x1B[32mv${n}\x1B[0m`),console.log(""),console.log(" Update your editor configs to pick up the new version:"),console.log(""),console.log(" \x1B[32m npx @cachly-dev/mcp-server@latest autopilot\x1B[0m"),console.log(""),console.log(" \x1B[2m(npx always fetches the latest when @latest is specified)\x1B[0m"),console.log(""))}catch(e){console.log(`
187
187
  \u274C Could not check for updates: ${e.message}
188
- `),process.exit(1)}process.exit(0)}if(process.argv[2]==="bench"){const{fileURLToPath:e}=await import("node:url"),{dirname:t,resolve:n}=await import("node:path"),{loadExternalCorpus:s,runExternalBenchmark:o}=await import("./bench/external-corpus.js"),c=process.argv.includes("--json"),i=process.argv.slice(3).find(g=>!g.startsWith("--")),a=t(e(import.meta.url)),d=i?n(process.cwd(),i):n(a,"bench","external","sample-corpus.json");try{const g=await s(d),l=await o(g);c&&(console.log(JSON.stringify({corpus:g.name,lessons:l.corpusSize,queries:l.queryCount,cachly_p1:Math.round(l.cachly.precisionAt1*1e3)/10,flatfile_p1:Math.round(l.flatfile.precisionAt1*1e3)/10,cachly_mrr:Math.round(l.cachly.mrr*1e3)/10,flatfile_mrr:Math.round(l.flatfile.mrr*1e3)/10,p1_lift_vs_flatfile_pct:Math.round((l.cachly.precisionAt1-l.flatfile.precisionAt1)*1e3)/10,mrr_lift_vs_flatfile_pct:Math.round((l.cachly.mrr-l.flatfile.mrr)*1e3)/10},null,2)),process.exit(0));const u=((l.cachly.precisionAt1-l.flatfile.precisionAt1)*100).toFixed(1),y=((l.cachly.mrr-l.flatfile.mrr)*100).toFixed(1),v=((l.cachly.precisionAt1-l.baseline.precisionAt1)*100).toFixed(1),b=l.cachly.precisionAt1>=l.flatfile.precisionAt1?"\x1B[32m+":"\x1B[31m",p=l.cachly.mrr>=l.flatfile.mrr?"\x1B[32m+":"\x1B[31m";console.log(""),console.log("\x1B[35m \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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly recall quality benchmark\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m"),console.log(""),console.log(` Corpus : ${g.name??d}`),console.log(` Dataset: ${l.corpusSize} lessons \xB7 ${l.queryCount} queries \xB7 10 engineering domains`),console.log(" (k8s, DB, auth, CI, frontend, API, payments, observability, Node.js, infra)"),console.log(""),console.log(" \x1B[1mPrecision@1\x1B[0m (finds the right lesson at rank #1):"),console.log(` flat-file memory : \x1B[33m${(l.flatfile.precisionAt1*100).toFixed(1)}%\x1B[0m (naive keyword overlap \u2014 no quality signal)`),console.log(` raw BM25 : \x1B[33m${(l.baseline.precisionAt1*100).toFixed(1)}%\x1B[0m (keyword ranking)`),console.log(` cachly : \x1B[1m\x1B[32m${(l.cachly.precisionAt1*100).toFixed(1)}%\x1B[0m (BM25 + quality reranking)`),console.log(""),console.log(" \x1B[1mMean Reciprocal Rank\x1B[0m (average rank of the right answer):"),console.log(` flat-file memory : \x1B[33m${(l.flatfile.mrr*100).toFixed(1)}%\x1B[0m`),console.log(` raw BM25 : \x1B[33m${(l.baseline.mrr*100).toFixed(1)}%\x1B[0m`),console.log(` cachly : \x1B[1m\x1B[32m${(l.cachly.mrr*100).toFixed(1)}%\x1B[0m`),console.log(""),console.log(" \x1B[1mLift vs flat-file memory\x1B[0m (what you get by switching from plain memory files):"),console.log(` Precision@1 : ${b}${u}%\x1B[0m`),console.log(` MRR : ${p}${y}%\x1B[0m`),console.log(` vs BM25 : \x1B[32m+${v}%\x1B[0m Precision@1 (quality reranking on top of keyword search)`),console.log(""),console.log(" \x1B[2mFlat-file = lexical overlap over raw text files (how Anthropic/Claude Memory works).\x1B[0m"),console.log(" \x1B[2mAdversarial distractors included \u2014 failure lessons that share the exact query vocabulary.\x1B[0m"),console.log(" \x1B[2mcachly ignores them because they have low confidence / failed outcome.\x1B[0m"),console.log(""),console.log(" Share your results:"),console.log(` \x1B[36m"My Brain: Precision@1 ${(l.cachly.precisionAt1*100).toFixed(1)}% (${b}${u}% vs flat-file memory, ${l.queryCount} queries)"\x1B[0m`),console.log(""),console.log(" Run on a custom corpus:"),console.log(" \x1B[2m npx @cachly-dev/mcp-server@latest bench my-incidents.json\x1B[0m"),console.log(" \x1B[2m npx @cachly-dev/mcp-server@latest bench --json # machine-readable\x1B[0m"),console.log(""),console.log(" \x1B[1m\u2192 Give your AI this recall quality on your own work (free, 1\u20135 min):\x1B[0m"),console.log(" \x1B[32m$ npx @cachly-dev/mcp-server@latest autopilot\x1B[0m"),console.log(" \x1B[90m Signs in, configures every editor, bootstraps from your git history.\x1B[0m"),console.log(` \x1B[90m Or create your Brain at: \x1B[36m${N("/setup-ai","bench")}\x1B[0m`),console.log("")}catch(g){console.error(`
188
+ `),process.exit(1)}process.exit(0)}if(process.argv[2]==="bench"){const{fileURLToPath:e}=await import("node:url"),{dirname:t,resolve:n}=await import("node:path"),{loadExternalCorpus:s,runExternalBenchmark:o}=await import("./bench/external-corpus.js"),c=process.argv.includes("--json"),i=process.argv.slice(3).find(g=>!g.startsWith("--")),a=t(e(import.meta.url)),d=i?n(process.cwd(),i):n(a,"bench","external","sample-corpus.json");try{const g=await s(d),l=await o(g);c&&(console.log(JSON.stringify({corpus:g.name,lessons:l.corpusSize,queries:l.queryCount,cachly_p1:Math.round(l.cachly.precisionAt1*1e3)/10,flatfile_p1:Math.round(l.flatfile.precisionAt1*1e3)/10,cachly_mrr:Math.round(l.cachly.mrr*1e3)/10,flatfile_mrr:Math.round(l.flatfile.mrr*1e3)/10,p1_lift_vs_flatfile_pct:Math.round((l.cachly.precisionAt1-l.flatfile.precisionAt1)*1e3)/10,mrr_lift_vs_flatfile_pct:Math.round((l.cachly.mrr-l.flatfile.mrr)*1e3)/10},null,2)),process.exit(0));const m=((l.cachly.precisionAt1-l.flatfile.precisionAt1)*100).toFixed(1),y=((l.cachly.mrr-l.flatfile.mrr)*100).toFixed(1),v=((l.cachly.precisionAt1-l.baseline.precisionAt1)*100).toFixed(1),b=l.cachly.precisionAt1>=l.flatfile.precisionAt1?"\x1B[32m+":"\x1B[31m",u=l.cachly.mrr>=l.flatfile.mrr?"\x1B[32m+":"\x1B[31m";console.log(""),console.log("\x1B[35m \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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly recall quality benchmark\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m"),console.log(""),console.log(` Corpus : ${g.name??d}`),console.log(` Dataset: ${l.corpusSize} lessons \xB7 ${l.queryCount} queries \xB7 10 engineering domains`),console.log(" (k8s, DB, auth, CI, frontend, API, payments, observability, Node.js, infra)"),console.log(""),console.log(" \x1B[1mPrecision@1\x1B[0m (finds the right lesson at rank #1):"),console.log(` flat-file memory : \x1B[33m${(l.flatfile.precisionAt1*100).toFixed(1)}%\x1B[0m (naive keyword overlap \u2014 no quality signal)`),console.log(` raw BM25 : \x1B[33m${(l.baseline.precisionAt1*100).toFixed(1)}%\x1B[0m (keyword ranking)`),console.log(` cachly : \x1B[1m\x1B[32m${(l.cachly.precisionAt1*100).toFixed(1)}%\x1B[0m (BM25 + quality reranking)`),console.log(""),console.log(" \x1B[1mMean Reciprocal Rank\x1B[0m (average rank of the right answer):"),console.log(` flat-file memory : \x1B[33m${(l.flatfile.mrr*100).toFixed(1)}%\x1B[0m`),console.log(` raw BM25 : \x1B[33m${(l.baseline.mrr*100).toFixed(1)}%\x1B[0m`),console.log(` cachly : \x1B[1m\x1B[32m${(l.cachly.mrr*100).toFixed(1)}%\x1B[0m`),console.log(""),console.log(" \x1B[1mLift vs flat-file memory\x1B[0m (what you get by switching from plain memory files):"),console.log(` Precision@1 : ${b}${m}%\x1B[0m`),console.log(` MRR : ${u}${y}%\x1B[0m`),console.log(` vs BM25 : \x1B[32m+${v}%\x1B[0m Precision@1 (quality reranking on top of keyword search)`),console.log(""),console.log(" \x1B[2mFlat-file = lexical overlap over raw text files (how Anthropic/Claude Memory works).\x1B[0m"),console.log(" \x1B[2mAdversarial distractors included \u2014 failure lessons that share the exact query vocabulary.\x1B[0m"),console.log(" \x1B[2mcachly ignores them because they have low confidence / failed outcome.\x1B[0m"),console.log(""),console.log(" Share your results:"),console.log(` \x1B[36m"My Brain: Precision@1 ${(l.cachly.precisionAt1*100).toFixed(1)}% (${b}${m}% vs flat-file memory, ${l.queryCount} queries)"\x1B[0m`),console.log(""),console.log(" Run on a custom corpus:"),console.log(" \x1B[2m npx @cachly-dev/mcp-server@latest bench my-incidents.json\x1B[0m"),console.log(" \x1B[2m npx @cachly-dev/mcp-server@latest bench --json # machine-readable\x1B[0m"),console.log(""),console.log(" \x1B[1m\u2192 Give your AI this recall quality on your own work (free, 1\u20135 min):\x1B[0m"),console.log(" \x1B[32m$ npx @cachly-dev/mcp-server@latest autopilot\x1B[0m"),console.log(" \x1B[90m Signs in, configures every editor, bootstraps from your git history.\x1B[0m"),console.log(` \x1B[90m Or create your Brain at: \x1B[36m${N("/setup-ai","bench")}\x1B[0m`),console.log("")}catch(g){console.error(`
189
189
  \u274C bench failed: ${g.message}
190
190
  `),process.exit(1)}process.exit(0)}if(process.argv[2]==="demo"){const{existsSync:e,readFileSync:t}=await import("node:fs"),{resolve:n,basename:s}=await import("node:path"),o=process.cwd();console.log(`
191
191
  \x1B[35m\u{1F9E0} cachly Brain \u2014 Live Demo\x1B[0m`),console.log(`\x1B[90mNo account needed. Reading your git history...\x1B[0m
192
192
  `),e(n(o,".git"))||(console.log("\u26A0\uFE0F No git repository found here."),console.log(` Run this command inside a project directory with git history.
193
193
  `),console.log(` Example: cd ~/my-project && npx @cachly-dev/mcp-server@latest demo
194
- `),process.exit(0));let c="";try{c=Ze(o,["config","user.name"]).trim().split(" ")[0]??""}catch{}let i=s(o);try{const $=JSON.parse(t(n(o,"package.json"),"utf-8"));$.name&&(i=$.name.replace(/^@[^/]+\//,""))}catch{}let a="";try{a=Ze(o,["log","HEAD","--pretty=format:%H|||%s|||%ad|||%an","--date=short","--no-merges","-n","200"],{timeoutMs:3e4})}catch{console.log(`\u26A0\uFE0F Could not read git log. Make sure you have commits.
194
+ `),process.exit(0));let c="";try{c=Qe(o,["config","user.name"]).trim().split(" ")[0]??""}catch{}let i=s(o);try{const $=JSON.parse(t(n(o,"package.json"),"utf-8"));$.name&&(i=$.name.replace(/^@[^/]+\//,""))}catch{}let a="";try{a=Qe(o,["log","HEAD","--pretty=format:%H|||%s|||%ad|||%an","--date=short","--no-merges","-n","200"],{timeoutMs:3e4})}catch{console.log(`\u26A0\uFE0F Could not read git log. Make sure you have commits.
195
195
  `),process.exit(0)}const d=a.trim().split(`
196
196
  `).filter(Boolean).map($=>{const[C,j,F,z]=$.split("|||");return{sha:(C??"").trim().slice(0,8),subject:(j??"").trim(),date:(F??"").trim(),author:(z??"").trim()}});d.length===0&&(console.log(`\u26A0\uFE0F No commits found.
197
- `),process.exit(0));const g=new Map,l=[],u=[],y=[],v=new Set;let b=0;for(const $ of d){const C=kn($.subject);g.set(C,(g.get(C)??0)+1),Tn($.subject)&&b++,C==="fix"&&l.length<5&&l.push($.subject.slice(0,72)),C==="feat"&&u.length<5&&u.push($.subject.slice(0,72)),C==="security"&&y.length<3&&y.push($.subject.slice(0,72)),$.author&&v.add($.author)}const p=In(d.map($=>$.subject)),r=`${d[d.length-1]?.date??"?"} \u2192 ${d[0]?.date??"?"}`,m=p>=501?"Oracle":p>=201?"Architect":p>=51?"Expert":p>=11?"Explorer":"Apprentice",k=`${c?`Hey ${c} \u2014 `:""}here's what your AI would know about ${i}`;process.stdout.write("\x1B[2K\r"),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log(`\u2502 \x1B[1m\u{1F9E0} ${k.slice(0,58).padEnd(58)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Commits analysed : \x1B[33m${String(d.length).padEnd(6)}\x1B[0m Date range: \x1B[90m${r.slice(0,23).padEnd(23)}\x1B[0m \u2502`),console.log(`\u2502 Lessons extracted: \x1B[32m${String(p).padEnd(6)}\x1B[0m Contributors: \x1B[36m${String(v.size).padEnd(20)}\x1B[0m\u2502`),console.log(`\u2502 Brain Level : \x1B[35m${m.padEnd(10)}\x1B[0m Reverts: \x1B[33m${String(b).padEnd(21)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");const B=[...g.entries()].filter(([$])=>$!=="chore").sort(($,C)=>C[1]-$[1]),I=($,C)=>"\u2588".repeat(Math.round($/C*20)).padEnd(20),A=Math.max(...B.map(([,$])=>$),1);console.log("\u2502 \x1B[90mCategory breakdown:\x1B[0m \u2502");for(const[$,C]of B){const j={fix:"\u{1F527}",feat:"\u2728",perf:"\u26A1",security:"\u{1F512}",deploy:"\u{1F680}",refactor:"\u{1F504}"}[$]??"\u2022";console.log(`\u2502 ${j} \x1B[36m${$.padEnd(10)}\x1B[0m \x1B[35m${I(C,A)}\x1B[0m \x1B[33m${String(C).padStart(3)}\x1B[0m \u2502`)}if(y.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[31m\u{1F512} Security fixes your AI would know:\x1B[0m \u2502");for(const $ of y)console.log(`\u2502 \x1B[90m\u2022 ${$.slice(0,58).padEnd(58)}\x1B[0m \u2502`)}if(l.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[33m\u{1F527} Bug fixes your AI would never repeat:\x1B[0m \u2502");for(const $ of l.slice(0,4))console.log(`\u2502 \x1B[90m\u2022 ${$.slice(0,58).padEnd(58)}\x1B[0m \u2502`)}if(u.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[32m\u2728 Features & decisions it would recall:\x1B[0m \u2502");for(const $ of u.slice(0,3))console.log(`\u2502 \x1B[90m\u2022 ${$.slice(0,58).padEnd(58)}\x1B[0m \u2502`)}console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[32m\u{1F4A1} With cachly, your AI arrives pre-briefed every session.\x1B[0m \u2502"),console.log("\u2502 \x1B[32m No more re-explaining. No more repeated mistakes.\x1B[0m \u2502"),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("");const T=new URLSearchParams({repo:i,commits:String(d.length),lessons:String(p),level:m,authors:String(v.size),reverts:String(b)}),E=N(`/preview?${T.toString()}`,"demo");console.log(" \x1B[1mMake this permanent (free, 1\u20135 minutes):\x1B[0m"),console.log(" \x1B[32m$ npx @cachly-dev/mcp-server@latest autopilot\x1B[0m"),console.log(""),console.log(` \x1B[90m\u{1F517} Shareable preview:\x1B[0m \x1B[36m${E}\x1B[0m`),console.log(""),console.log(" Works with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 Copilot \xB7 Cline \xB7 Zed"),console.log(" GDPR \xB7 German servers \xB7 free tier, no credit card"),console.log(""),process.exit(0)}if(process.argv[2]==="share"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
197
+ `),process.exit(0));const g=new Map,l=[],m=[],y=[],v=new Set;let b=0;for(const $ of d){const C=Tn($.subject);g.set(C,(g.get(C)??0)+1),In($.subject)&&b++,C==="fix"&&l.length<5&&l.push($.subject.slice(0,72)),C==="feat"&&m.length<5&&m.push($.subject.slice(0,72)),C==="security"&&y.length<3&&y.push($.subject.slice(0,72)),$.author&&v.add($.author)}const u=En(d.map($=>$.subject)),r=`${d[d.length-1]?.date??"?"} \u2192 ${d[0]?.date??"?"}`,p=u>=501?"Oracle":u>=201?"Architect":u>=51?"Expert":u>=11?"Explorer":"Apprentice",T=`${c?`Hey ${c} \u2014 `:""}here's what your AI would know about ${i}`;process.stdout.write("\x1B[2K\r"),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log(`\u2502 \x1B[1m\u{1F9E0} ${T.slice(0,58).padEnd(58)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Commits analysed : \x1B[33m${String(d.length).padEnd(6)}\x1B[0m Date range: \x1B[90m${r.slice(0,23).padEnd(23)}\x1B[0m \u2502`),console.log(`\u2502 Lessons extracted: \x1B[32m${String(u).padEnd(6)}\x1B[0m Contributors: \x1B[36m${String(v.size).padEnd(20)}\x1B[0m\u2502`),console.log(`\u2502 Brain Level : \x1B[35m${p.padEnd(10)}\x1B[0m Reverts: \x1B[33m${String(b).padEnd(21)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");const B=[...g.entries()].filter(([$])=>$!=="chore").sort(($,C)=>C[1]-$[1]),I=($,C)=>"\u2588".repeat(Math.round($/C*20)).padEnd(20),S=Math.max(...B.map(([,$])=>$),1);console.log("\u2502 \x1B[90mCategory breakdown:\x1B[0m \u2502");for(const[$,C]of B){const j={fix:"\u{1F527}",feat:"\u2728",perf:"\u26A1",security:"\u{1F512}",deploy:"\u{1F680}",refactor:"\u{1F504}"}[$]??"\u2022";console.log(`\u2502 ${j} \x1B[36m${$.padEnd(10)}\x1B[0m \x1B[35m${I(C,S)}\x1B[0m \x1B[33m${String(C).padStart(3)}\x1B[0m \u2502`)}if(y.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[31m\u{1F512} Security fixes your AI would know:\x1B[0m \u2502");for(const $ of y)console.log(`\u2502 \x1B[90m\u2022 ${$.slice(0,58).padEnd(58)}\x1B[0m \u2502`)}if(l.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[33m\u{1F527} Bug fixes your AI would never repeat:\x1B[0m \u2502");for(const $ of l.slice(0,4))console.log(`\u2502 \x1B[90m\u2022 ${$.slice(0,58).padEnd(58)}\x1B[0m \u2502`)}if(m.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[32m\u2728 Features & decisions it would recall:\x1B[0m \u2502");for(const $ of m.slice(0,3))console.log(`\u2502 \x1B[90m\u2022 ${$.slice(0,58).padEnd(58)}\x1B[0m \u2502`)}console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[32m\u{1F4A1} With cachly, your AI arrives pre-briefed every session.\x1B[0m \u2502"),console.log("\u2502 \x1B[32m No more re-explaining. No more repeated mistakes.\x1B[0m \u2502"),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("");const k=new URLSearchParams({repo:i,commits:String(d.length),lessons:String(u),level:p,authors:String(v.size),reverts:String(b)}),E=N(`/preview?${k.toString()}`,"demo");console.log(" \x1B[1mMake this permanent (free, 1\u20135 minutes):\x1B[0m"),console.log(" \x1B[32m$ npx @cachly-dev/mcp-server@latest autopilot\x1B[0m"),console.log(""),console.log(` \x1B[90m\u{1F517} Shareable preview:\x1B[0m \x1B[36m${E}\x1B[0m`),console.log(""),console.log(" Works with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 Copilot \xB7 Cline \xB7 Zed"),console.log(" GDPR \xB7 German servers \xB7 free tier, no credit card"),console.log(""),process.exit(0)}if(process.argv[2]==="share"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
198
198
  \u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot (takes 1\u20135 minutes)
199
199
  `),process.exit(1)),process.stdout.write(`
200
200
  \u{1F9E0} Fetching your Brain stats...
201
- `);try{const n=await fetch(`${x}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)});if(!n.ok)throw new Error(`HTTP ${n.status}`);const s=await n.json(),o=s.lesson_count??0,c=s.total_recall_count??0,i=Math.round(s.iq_boost_pct??0),a=c*1200,d=(a*3e-6).toFixed(2),g=o===0?"Intern \u{1F331}":o<10?"Junior Dev \u{1F527}":o<30?"Mid Dev \u26A1":o<60?"Senior Dev \u{1F9E0}":o<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}";console.log(""),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 \u{1F9E0} My AI Brain \xB7 powered by \x1B[35mcachly.dev\x1B[0m \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Lessons stored : \x1B[33m${String(o).padEnd(8)}\x1B[0m Brain level: \x1B[32m${g.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Total recalls : \x1B[36m${String(c).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(i).padEnd(3)}%\x1B[0m \u2502`),console.log(`\u2502 Tokens saved : \x1B[32m${((a/1e3).toFixed(0)+"K").padEnd(8)}\x1B[0m Cost saved: \x1B[32m$${d.padEnd(20)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 Works with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 Copilot \u2502"),console.log("\u2502 Free \xB7 GDPR \xB7 German servers \u2502"),console.log("\u2502 \x1B[35mnpx @cachly-dev/mcp-server@latest autopilot\x1B[0m \u2502"),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("");const l=N("/","share"),u=`\u{1F9E0} My AI coding assistant now has persistent memory.
201
+ `);try{const n=await fetch(`${x}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)});if(!n.ok)throw new Error(`HTTP ${n.status}`);const s=await n.json(),o=s.lesson_count??0,c=s.total_recall_count??0,i=Math.round(s.iq_boost_pct??0),a=c*1200,d=(a*3e-6).toFixed(2),g=o===0?"Intern \u{1F331}":o<10?"Junior Dev \u{1F527}":o<30?"Mid Dev \u26A1":o<60?"Senior Dev \u{1F9E0}":o<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}";console.log(""),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 \u{1F9E0} My AI Brain \xB7 powered by \x1B[35mcachly.dev\x1B[0m \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Lessons stored : \x1B[33m${String(o).padEnd(8)}\x1B[0m Brain level: \x1B[32m${g.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Total recalls : \x1B[36m${String(c).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(i).padEnd(3)}%\x1B[0m \u2502`),console.log(`\u2502 Tokens saved : \x1B[32m${((a/1e3).toFixed(0)+"K").padEnd(8)}\x1B[0m Cost saved: \x1B[32m$${d.padEnd(20)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 Works with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 Copilot \u2502"),console.log("\u2502 Free \xB7 GDPR \xB7 German servers \u2502"),console.log("\u2502 \x1B[35mnpx @cachly-dev/mcp-server@latest autopilot\x1B[0m \u2502"),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("");const l=N("/","share"),m=`\u{1F9E0} My AI coding assistant now has persistent memory.
202
202
 
203
203
  ${o} lessons stored \xB7 ${c} recalls \xB7 ${g}
204
204
 
@@ -206,7 +206,7 @@ Fix a bug once \u2192 AI remembers forever. Across Claude Code, Cursor, Windsurf
206
206
 
207
207
  ${l}
208
208
 
209
- #AIMemory #ClaudeCode #Cursor #DeveloperTools`;console.log(" \x1B[1m\u{1F4CB} Share on Twitter/X (copy this):\x1B[0m"),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(u.split(`
209
+ #AIMemory #ClaudeCode #Cursor #DeveloperTools`;console.log(" \x1B[1m\u{1F4CB} Share on Twitter/X (copy this):\x1B[0m"),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(m.split(`
210
210
  `).map(y=>` ${y}`).join(`
211
211
  `)),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(""),console.log(" \x1B[2mPro tip: add a screenshot of your Brain panel for 3x more engagement\x1B[0m"),console.log(" \x1B[2mAlso add a live badge to your README:\x1B[0m"),console.log(" \x1B[90m npx @cachly-dev/mcp-server@latest badge\x1B[0m"),console.log("")}catch(n){console.log(`
212
212
  \u274C Could not fetch stats: ${n.message}
@@ -214,7 +214,7 @@ ${l}
214
214
  \u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
215
215
  `),process.exit(1));const n=process.argv.indexOf("--title"),s=n!==-1?process.argv[n+1]??"My Brain Snapshot":"My Brain Snapshot",o=process.argv.includes("--public");process.stdout.write(`
216
216
  \u{1F9E0} Publishing Brain snapshot...
217
- `);try{const c=await fetch(`${x}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)});let i=0,a=0;if(c.ok){const y=await c.json();i=y.lesson_count??0,a=y.total_recall_count??0}const d=await fetch(`${x}/api/v1/brains/share`,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({title:s,visibility:o?"public":"unlisted",instance_id:t}),signal:AbortSignal.timeout(15e3)});if(!d.ok)throw new Error(`HTTP ${d.status}`);const l=(await d.json()).share_id??"unavailable",u=N(`/brain/share/${l}`,"publish");console.log(""),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 \u{1F4E4} Brain Published \xB7 powered by \x1B[35mcachly.dev\x1B[0m \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Title : \x1B[33m${s.slice(0,44).padEnd(44)}\x1B[0m\u2502`),console.log(`\u2502 Lessons : \x1B[32m${String(i).padEnd(10)}\x1B[0m Recalls: \x1B[36m${String(a).padEnd(26)}\x1B[0m\u2502`),console.log(`\u2502 Visibility: \x1B[${o?"32":"33"}m${(o?"public (discoverable)":"unlisted (link only)").padEnd(44)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 \x1B[1mShare URL:\x1B[0m \x1B[36m${u.padEnd(51)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[2mAnyone can import with:\x1B[0m \u2502"),console.log(`\u2502 \x1B[90m brain_import(instance_id="...", share_id="${l.slice(0,17)}")\x1B[0m\u2502`),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log(""),console.log(" \x1B[1m\u{1F4CB} Share this with your team:\x1B[0m"),console.log(` ${u}`),console.log(""),console.log(` \x1B[2mTo list all your shares:\x1B[0m brain_share_list(instance_id="${t.slice(0,24)}...")`),console.log(` \x1B[2mTo revoke this share:\x1B[0m brain_unshare(share_id="${l.slice(0,24)}...")`),console.log("")}catch(c){console.log(`
217
+ `);try{const c=await fetch(`${x}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)});let i=0,a=0;if(c.ok){const y=await c.json();i=y.lesson_count??0,a=y.total_recall_count??0}const d=await fetch(`${x}/api/v1/brains/share`,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({title:s,visibility:o?"public":"unlisted",instance_id:t}),signal:AbortSignal.timeout(15e3)});if(!d.ok)throw new Error(`HTTP ${d.status}`);const l=(await d.json()).share_id??"unavailable",m=N(`/brain/share/${l}`,"publish");console.log(""),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 \u{1F4E4} Brain Published \xB7 powered by \x1B[35mcachly.dev\x1B[0m \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Title : \x1B[33m${s.slice(0,44).padEnd(44)}\x1B[0m\u2502`),console.log(`\u2502 Lessons : \x1B[32m${String(i).padEnd(10)}\x1B[0m Recalls: \x1B[36m${String(a).padEnd(26)}\x1B[0m\u2502`),console.log(`\u2502 Visibility: \x1B[${o?"32":"33"}m${(o?"public (discoverable)":"unlisted (link only)").padEnd(44)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 \x1B[1mShare URL:\x1B[0m \x1B[36m${m.padEnd(51)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[2mAnyone can import with:\x1B[0m \u2502"),console.log(`\u2502 \x1B[90m brain_import(instance_id="...", share_id="${l.slice(0,17)}")\x1B[0m\u2502`),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log(""),console.log(" \x1B[1m\u{1F4CB} Share this with your team:\x1B[0m"),console.log(` ${m}`),console.log(""),console.log(` \x1B[2mTo list all your shares:\x1B[0m brain_share_list(instance_id="${t.slice(0,24)}...")`),console.log(` \x1B[2mTo revoke this share:\x1B[0m brain_unshare(share_id="${l.slice(0,24)}...")`),console.log("")}catch(c){console.log(`
218
218
  \u274C Could not publish Brain: ${c.message}
219
219
  `),process.exit(1)}process.exit(0)}if(process.argv[2]==="tool-specs"||process.argv[2]==="openapi"){const{renderToolSpecs:e}=await import("./toolspecs.js");let t="openapi";if(process.argv[2]!=="openapi"){const s=process.argv.find(o=>o.startsWith("--format="));if(s)t=s.slice(9);else{const o=process.argv.indexOf("--format");o!==-1&&(t=process.argv[o+1]??"openapi")}}const n=["openapi","openai","anthropic","langchain"];n.includes(t)||(process.stderr.write(`
220
220
  \u274C Unknown format "${t}". Use one of: ${n.join(", ")}
@@ -222,86 +222,86 @@ ${l}
222
222
  `),process.exit(1)),process.stdout.write(e(ce,t,D)+`
223
223
  `,()=>process.exit(0))}if(process.argv[2]==="badge"){const e=process.env.CACHLY_BRAIN_INSTANCE_ID??"";e||(console.log(`
224
224
  \u26A0\uFE0F CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot (takes 1\u20135 minutes)
225
- `),process.exit(1));const t=`${x}/api/v1/badge/${e}`,n=N("/","badge"),s=`[![cachly Brain](${t})](${n})`,o=`<a href="${n}"><img src="${t}" alt="cachly Brain" /></a>`;console.log(""),console.log("\x1B[35m \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\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly Brain Badge\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \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\u2550\u255D\x1B[0m"),console.log(""),console.log(" Paste into your README.md:"),console.log(""),console.log(` \x1B[32m${s}\x1B[0m`),console.log(""),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(" Or paste into HTML:"),console.log(""),console.log(` \x1B[36m${o}\x1B[0m`),console.log(""),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(" Badge URL (live, updates every hour):"),console.log(` \x1B[90m${t}\x1B[0m`),console.log(""),console.log(" \x1B[2mThe badge shows your current lesson count \u2014 no auth required,"),console.log(" safe to embed in public repos. Updates hourly.\x1B[0m"),console.log(""),process.exit(0)}!process.argv[2]&&process.stdout.isTTY&&(console.log(""),console.log("\x1B[35m \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\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly \u2014 Persistent AI Memory for Developers\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \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\u2550\u255D\x1B[0m"),console.log(""),console.log(" Stop re-teaching your AI every morning."),console.log(" cachly gives it a permanent brain \u2014 pre-briefed every session."),console.log(""),console.log(" \x1B[1mCommands:\x1B[0m"),console.log(" \x1B[1m\x1B[32m npx @cachly-dev/mcp-server@latest autopilot\x1B[0m \u2190 \x1B[1mOne command, fully ready\x1B[0m"),console.log(" \x1B[32m npx @cachly-dev/mcp-server@latest demo\x1B[0m \u2190 Try it first (no account)"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest setup\x1B[0m \u2190 Interactive setup (pick editors)"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest claim\x1B[0m \u2190 Keep a test Brain in your own account"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest health\x1B[0m \u2190 Check everything works"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest doctor\x1B[0m \u2190 Diagnose a broken or missing install"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest digest\x1B[0m \u2190 Weekly Brain summary"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest share\x1B[0m \u2190 Share your Brain stats"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest badge\x1B[0m \u2190 README badge for your Brain"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest invite\x1B[0m \u2190 Invite a teammate"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest join <token>\x1B[0m \u2190 Accept a Brain invite"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest bench\x1B[0m \u2190 Recall quality vs flat-file memory"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest upgrade\x1B[0m \u2190 Check for updates"),console.log(""),console.log(" \x1B[90mWorks with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 GitHub Copilot \xB7 Cline \xB7 Zed\x1B[0m"),console.log(` \x1B[90mGDPR \xB7 German servers \xB7 ${ce.length} MCP tools\x1B[0m`),console.log(""),process.exit(0));const Kn={cursor:{datei:".cursor/hooks.json",name:"Cursor",wie:"session briefing, per-prompt recall after the first tool call"},copilot:{datei:Lo,name:"VS Code / Copilot",wie:"session briefing, per-prompt recall"},codex:{datei:Bo,name:"Codex",wie:"session briefing, per-prompt recall; trust it once in /hooks"},gemini:{datei:jo,name:"Gemini CLI",wie:"session briefing, per-prompt recall"}};function Gn(e,t,n){if(!t)return;const{datei:s,name:o,wie:c}=Kn[e];if(t.hooks==="skipped"){console.log(`\u26A0\uFE0F ${n}${s} ${t.grund??"is not valid JSON"} \u2014 left untouched, ${o} hooks not wired`);return}const i=t.hooks==="unchanged"?"\u2713 ":"\u2705 ",a=t.hooks==="written"?"Written":t.hooks==="merged"?"Merged":"Already wired";console.log(`${i}${n}${a}: ${s} (Ambient Recall for ${o} \u2014 ${c})`)}async function pe(e,t,n,s){const o={cursor:Io,copilot:Eo,codex:Ro,gemini:No}[e];Gn(e,await o(t,n).catch(()=>null),s)}if(process.argv[2]==="init"){const e=Date.now(),{writeFile:t,mkdir:n,readFile:s}=await import("node:fs/promises"),{resolve:o,dirname:c}=await import("node:path"),i=process.argv.slice(3),a=r=>{const m=i.indexOf(`--${r}`);return m!==-1?i[m+1]:void 0};let d=a("instance-id")??process.env.CACHLY_BRAIN_INSTANCE_ID,g=a("api-key")??process.env.CACHLY_JWT;const l=(a("editor")??"claude").toLowerCase(),u=o(a("project-dir")??"."),y=a("api-url");if(y&&(x=y.replace(/\/+$/,"")),!d||!g)try{const{existsSync:r}=await import("node:fs"),m=process.env.HOME??process.env.USERPROFILE??"",h=m?o(m,".claude","mcp.json"):"";if(h&&r(h)){const B=JSON.parse(await s(h,"utf-8")).mcpServers?.cachly?.env??{};g??=B.CACHLY_JWT,d??=B.CACHLY_BRAIN_INSTANCE_ID,g&&d&&console.log("\u2713 Reusing credentials from ~/.claude/mcp.json (saved by a prior setup)")}}catch{}(!d||!g)&&(console.error(`
225
+ `),process.exit(1));const t=`${x}/api/v1/badge/${e}`,n=N("/","badge"),s=`[![cachly Brain](${t})](${n})`,o=`<a href="${n}"><img src="${t}" alt="cachly Brain" /></a>`;console.log(""),console.log("\x1B[35m \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\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly Brain Badge\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \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\u2550\u255D\x1B[0m"),console.log(""),console.log(" Paste into your README.md:"),console.log(""),console.log(` \x1B[32m${s}\x1B[0m`),console.log(""),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(" Or paste into HTML:"),console.log(""),console.log(` \x1B[36m${o}\x1B[0m`),console.log(""),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(" Badge URL (live, updates every hour):"),console.log(` \x1B[90m${t}\x1B[0m`),console.log(""),console.log(" \x1B[2mThe badge shows your current lesson count \u2014 no auth required,"),console.log(" safe to embed in public repos. Updates hourly.\x1B[0m"),console.log(""),process.exit(0)}!process.argv[2]&&process.stdout.isTTY&&(console.log(""),console.log("\x1B[35m \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\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly \u2014 Persistent AI Memory for Developers\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \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\u2550\u255D\x1B[0m"),console.log(""),console.log(" Stop re-teaching your AI every morning."),console.log(" cachly gives it a permanent brain \u2014 pre-briefed every session."),console.log(""),console.log(" \x1B[1mCommands:\x1B[0m"),console.log(" \x1B[1m\x1B[32m npx @cachly-dev/mcp-server@latest autopilot\x1B[0m \u2190 \x1B[1mOne command, fully ready\x1B[0m"),console.log(" \x1B[32m npx @cachly-dev/mcp-server@latest demo\x1B[0m \u2190 Try it first (no account)"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest setup\x1B[0m \u2190 Interactive setup (pick editors)"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest claim\x1B[0m \u2190 Keep a test Brain in your own account"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest health\x1B[0m \u2190 Check everything works"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest doctor\x1B[0m \u2190 Diagnose a broken or missing install"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest digest\x1B[0m \u2190 Weekly Brain summary"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest share\x1B[0m \u2190 Share your Brain stats"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest badge\x1B[0m \u2190 README badge for your Brain"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest invite\x1B[0m \u2190 Invite a teammate"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest join <token>\x1B[0m \u2190 Accept a Brain invite"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest bench\x1B[0m \u2190 Recall quality vs flat-file memory"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest upgrade\x1B[0m \u2190 Check for updates"),console.log(""),console.log(" \x1B[90mWorks with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 GitHub Copilot \xB7 Cline \xB7 Zed\x1B[0m"),console.log(` \x1B[90mGDPR \xB7 German servers \xB7 ${ce.length} MCP tools\x1B[0m`),console.log(""),process.exit(0));const Gn={cursor:{datei:".cursor/hooks.json",name:"Cursor",wie:"session briefing, per-prompt recall after the first tool call"},copilot:{datei:Bo,name:"VS Code / Copilot",wie:"session briefing, per-prompt recall"},codex:{datei:jo,name:"Codex",wie:"session briefing, per-prompt recall; trust it once in /hooks"},gemini:{datei:Ho,name:"Gemini CLI",wie:"session briefing, per-prompt recall"}};function Vn(e,t,n){if(!t)return;const{datei:s,name:o,wie:c}=Gn[e];if(t.hooks==="skipped"){console.log(`\u26A0\uFE0F ${n}${s} ${t.grund??"is not valid JSON"} \u2014 left untouched, ${o} hooks not wired`);return}const i=t.hooks==="unchanged"?"\u2713 ":"\u2705 ",a=t.hooks==="written"?"Written":t.hooks==="merged"?"Merged":"Already wired";console.log(`${i}${n}${a}: ${s} (Ambient Recall for ${o} \u2014 ${c})`)}async function pe(e,t,n,s){const o={cursor:Eo,copilot:Ro,codex:No,gemini:Lo}[e];Vn(e,await o(t,n).catch(()=>null),s)}if(process.argv[2]==="init"){const e=Date.now(),{writeFile:t,mkdir:n,readFile:s}=await import("node:fs/promises"),{resolve:o,dirname:c}=await import("node:path"),i=process.argv.slice(3),a=r=>{const p=i.indexOf(`--${r}`);return p!==-1?i[p+1]:void 0};let d=a("instance-id")??process.env.CACHLY_BRAIN_INSTANCE_ID,g=a("api-key")??process.env.CACHLY_JWT;const l=(a("editor")??"claude").toLowerCase(),m=o(a("project-dir")??"."),y=a("api-url");if(y&&(x=y.replace(/\/+$/,"")),!d||!g)try{const{existsSync:r}=await import("node:fs"),p=process.env.HOME??process.env.USERPROFILE??"",h=p?o(p,".claude","mcp.json"):"";if(h&&r(h)){const B=JSON.parse(await s(h,"utf-8")).mcpServers?.cachly?.env??{};g??=B.CACHLY_JWT,d??=B.CACHLY_BRAIN_INSTANCE_ID,g&&d&&console.log("\u2713 Reusing credentials from ~/.claude/mcp.json (saved by a prior setup)")}}catch{}(!d||!g)&&(console.error(`
226
226
  Usage: npx @cachly-dev/mcp-server@latest init --instance-id <uuid> --api-key <cky_live_...> [--editor claude|cursor|windsurf|copilot|continue|codex|gemini] [--project-dir /path] [--api-url https://your-self-hosted-backend]
227
227
  `),console.error(`First time? Run the zero-config wizard (signs you in, auto-provisions): npx @cachly-dev/mcp-server@latest autopilot
228
228
  `),console.error(`Get your credentials from: ${N("/setup-ai","init")}
229
- `),process.exit(1));const v=Fn(l,oe(g,d));if(v)te(g),console.log(`
230
- \u{1F449} Register the MCP server once (writes ${v.wo}):`),console.log(` ${v.befehl}`);else{const r=be[l]??".mcp.json",m=o(u,r);await n(c(m),{recursive:!0});const{existsSync:h}=await import("node:fs"),k=h(m),B=k?await s(m,"utf-8").catch(()=>""):"";te(g);const I=await St(m,g,d,l,{readFile:s,existsSync:h});I!==B?(await t(m,I,"utf-8"),console.log(`
231
- \u2705 ${k?"Updated":"Written"}: ${r}`)):console.log(`
232
- \u2713 Already configured: ${r} (no change)`)}const b=await kt(u,d);for(const[r,m]of Object.entries(b)){const h=m==="updated"?"\u2705 Updated":m==="appended"?"\u2705 Appended to":"\u2705 Written",k=r.split(/[\\/]/).pop()??r;console.log(`${h}: ${k}`)}try{const r=await Ge(u,d,w||void 0);r==="written"?console.log("\u2705 Written: .git/hooks/post-commit (CLS hook)"):r==="upgraded"?console.log(`\u2705 Upgraded: .git/hooks/post-commit (CLS hook \u2192 ${Ve})`):r==="appended"?console.log("\u2705 Appended: .git/hooks/post-commit (CLS hook)"):r==="unchanged"&&console.log("\u2713 CLS hook already current in .git/hooks/post-commit")}catch{}if(l==="claude")try{const r=await Qe(u,d),m=r.scripts==="written"?"\u2705 Written":r.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${Xe})`:"\u2713 Unchanged";console.log(`${m}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),r.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):r.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 pe(l,u,d,"");const p=((Date.now()-e)/1e3).toFixed(1);console.log(`
233
- \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(`
229
+ `),process.exit(1));const v=zn(l,oe(g,d));if(v)te(g),console.log(`
230
+ \u{1F449} Register the MCP server once (writes ${v.wo}):`),console.log(` ${v.befehl}`);else{const r=be[l]??".mcp.json",p=o(m,r);await n(c(p),{recursive:!0});const{existsSync:h}=await import("node:fs"),T=h(p),B=T?await s(p,"utf-8").catch(()=>""):"";te(g);const I=await St(p,g,d,l,{readFile:s,existsSync:h});I!==B?(await t(p,I,"utf-8"),console.log(`
231
+ \u2705 ${T?"Updated":"Written"}: ${r}`)):console.log(`
232
+ \u2713 Already configured: ${r} (no change)`)}const b=await Tt(m,d);for(const[r,p]of Object.entries(b)){const h=p==="updated"?"\u2705 Updated":p==="appended"?"\u2705 Appended to":"\u2705 Written",T=r.split(/[\\/]/).pop()??r;console.log(`${h}: ${T}`)}try{const r=await Ve(m,d,w||void 0);r==="written"?console.log("\u2705 Written: .git/hooks/post-commit (CLS hook)"):r==="upgraded"?console.log(`\u2705 Upgraded: .git/hooks/post-commit (CLS hook \u2192 ${Ze})`):r==="appended"?console.log("\u2705 Appended: .git/hooks/post-commit (CLS hook)"):r==="unchanged"&&console.log("\u2713 CLS hook already current in .git/hooks/post-commit")}catch{}if(l==="claude")try{const r=await Xe(m,d),p=r.scripts==="written"?"\u2705 Written":r.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${et})`:"\u2713 Unchanged";console.log(`${p}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),r.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):r.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 pe(l,m,d,"");const u=((Date.now()-e)/1e3).toFixed(1);console.log(`
233
+ \u{1F9E0} Cachly AI Brain configured for ${l==="claude"?"Claude Code":l}! (${u}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(`
234
234
  \u{1F4DB} Add a live badge to your README:`),console.log(` npx @cachly-dev/mcp-server@latest badge
235
235
  `),process.exit(0)}if(process.argv[2]==="status"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
236
236
  \u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
237
- `),process.exit(1));try{const[n,s]=await Promise.all([fetch(`${x}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)}),fetch(`${x}/api/v1/referral/me`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)})]);if(!n.ok)throw new Error(`stats HTTP ${n.status}`);const o=await n.json(),c=s.ok?await s.json():null,i=o.lesson_count??0,a=o.total_recall_count??0,d=Math.round(o.iq_boost_pct??0),g=o.team_authors??[],l=c?.referral_count??0,u=c?.url??"",y=i===0?"Intern \u{1F331}":i<10?"Junior Dev \u{1F527}":i<30?"Mid Dev \u26A1":i<60?"Senior Dev \u{1F9E0}":i<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}",v=i>0?"\x1B[32m\u25CF\x1B[0m":"\x1B[33m\u25CF\x1B[0m";if(console.log(""),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log(`\u2502 ${v} \x1B[1mBrain status\x1B[0m \xB7 instance ${t.slice(0,8)}... \u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Lessons : \x1B[33m${String(i).padEnd(8)}\x1B[0m Level : \x1B[32m${y.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Recalls : \x1B[36m${String(a).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(d).padEnd(3)}%\x1B[0m \u2502`),g.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");const b=g.slice(0,4).join(", ");console.log(`\u2502 \x1B[36m\u{1F465} Team Brain\x1B[0m \xB7 ${String(g.length).padEnd(2)} developer${g.length===1?" ":"s"} sharing lessons${" ".repeat(Math.max(0,19-b.length))} \u2502`),console.log(`\u2502 ${b.slice(0,56).padEnd(56)} \u2502`)}if(u){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");const b=`${u.slice(0,44)}${u.length>44?"\u2026":""}`;console.log(`\u2502 \x1B[35m\u{1F517} Invite link\x1B[0m \xB7 ${l>0?`\x1B[32m${l} joined\x1B[0m`:"share to grow your team"}${" ".repeat(Math.max(0,35-String(l).length))} \u2502`),console.log(`\u2502 \x1B[2m${b.padEnd(56)}\x1B[0m \u2502`)}console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log(""),i===0&&(console.log(" \x1B[33m\u{1F4A1} No lessons yet.\x1B[0m Run a session with cachly connected to start learning."),console.log(""))}catch(n){console.log(`
237
+ `),process.exit(1));try{const[n,s]=await Promise.all([fetch(`${x}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)}),fetch(`${x}/api/v1/referral/me`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)})]);if(!n.ok)throw new Error(`stats HTTP ${n.status}`);const o=await n.json(),c=s.ok?await s.json():null,i=o.lesson_count??0,a=o.total_recall_count??0,d=Math.round(o.iq_boost_pct??0),g=o.team_authors??[],l=c?.referral_count??0,m=c?.url??"",y=i===0?"Intern \u{1F331}":i<10?"Junior Dev \u{1F527}":i<30?"Mid Dev \u26A1":i<60?"Senior Dev \u{1F9E0}":i<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}",v=i>0?"\x1B[32m\u25CF\x1B[0m":"\x1B[33m\u25CF\x1B[0m";if(console.log(""),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log(`\u2502 ${v} \x1B[1mBrain status\x1B[0m \xB7 instance ${t.slice(0,8)}... \u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Lessons : \x1B[33m${String(i).padEnd(8)}\x1B[0m Level : \x1B[32m${y.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Recalls : \x1B[36m${String(a).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(d).padEnd(3)}%\x1B[0m \u2502`),g.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");const b=g.slice(0,4).join(", ");console.log(`\u2502 \x1B[36m\u{1F465} Team Brain\x1B[0m \xB7 ${String(g.length).padEnd(2)} developer${g.length===1?" ":"s"} sharing lessons${" ".repeat(Math.max(0,19-b.length))} \u2502`),console.log(`\u2502 ${b.slice(0,56).padEnd(56)} \u2502`)}if(m){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");const b=`${m.slice(0,44)}${m.length>44?"\u2026":""}`;console.log(`\u2502 \x1B[35m\u{1F517} Invite link\x1B[0m \xB7 ${l>0?`\x1B[32m${l} joined\x1B[0m`:"share to grow your team"}${" ".repeat(Math.max(0,35-String(l).length))} \u2502`),console.log(`\u2502 \x1B[2m${b.padEnd(56)}\x1B[0m \u2502`)}console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log(""),i===0&&(console.log(" \x1B[33m\u{1F4A1} No lessons yet.\x1B[0m Run a session with cachly connected to start learning."),console.log(""))}catch(n){console.log(`
238
238
  \u274C Could not fetch status: ${n.message}
239
- `),process.exit(1)}process.exit(0)}if(process.argv[2]==="health"){const{existsSync:e}=await import("node:fs"),{readFile:t}=await import("node:fs/promises"),{resolve:n}=await import("node:path"),s=process.cwd();let o=0,c=0;const i=p=>{console.log(` \u2705 ${p}`),o++},a=p=>{console.log(` \u26A0\uFE0F ${p}`)},d=p=>{console.log(` \u274C ${p}`),c++};console.log(`
239
+ `),process.exit(1)}process.exit(0)}if(process.argv[2]==="health"){const{existsSync:e}=await import("node:fs"),{readFile:t}=await import("node:fs/promises"),{resolve:n}=await import("node:path"),s=process.cwd();let o=0,c=0;const i=u=>{console.log(` \u2705 ${u}`),o++},a=u=>{console.log(` \u26A0\uFE0F ${u}`)},d=u=>{console.log(` \u274C ${u}`),c++};console.log(`
240
240
  \u{1F9E0} cachly health check
241
- `),console.log("\u{1F511} Auth token");const g=process.env.CACHLY_JWT??"";if(!g)d("CACHLY_JWT not set \u2014 run: npx @cachly-dev/mcp-server@latest autopilot");else if(g.startsWith("cky_"))i("Long-lived API key set (cky_\u2026) \u2014 no client-side expiry");else try{const p=g.split(".");if(p.length!==3)throw new Error("not a JWT");const r=JSON.parse(Buffer.from(p[1],"base64url").toString("utf-8")),m=r.exp?r.exp*1e3:null,h=m?Math.floor((m-Date.now())/6e4):null;m&&m<Date.now()?d(`JWT expired ${Math.abs(h)} minute(s) ago \u2014 get a new one: ${N("/setup-ai","health")}`):h!==null&&h<30?a(`JWT expires in ${h} minute(s) \u2014 refresh soon at ${N("/setup-ai","health")}`):i(`JWT valid${h!==null?` (expires in ${Math.floor(h/60)}h ${h%60}m)`:""}`)}catch{d("CACHLY_JWT format invalid (expected a cky_ API key or a 3-part JWT)")}console.log(`
242
- \u{1F310} Brain API`);const l=process.env.CACHLY_API_URL??"https://api.cachly.dev";try{const p=await fetch(`${l}/health`,{signal:AbortSignal.timeout(5e3)});if(p.ok){const r=await p.json();i(`${l} reachable (status: ${r.status??"ok"})`)}else p.status===401||p.status===403?i(`${l} reachable (auth required \u2014 expected)`):d(`${l}/health returned HTTP ${p.status}`)}catch(p){d(`${l} unreachable \u2014 ${p.message}`)}console.log(`
243
- \u{1F9E0} Brain instance`);const u=process.env.CACHLY_BRAIN_INSTANCE_ID??"";if(!u)a("CACHLY_BRAIN_INSTANCE_ID not set \u2014 will auto-resolve on first tool call");else if(g)try{const p=await fetch(`${l}/api/v1/instances/${u}`,{headers:{Authorization:`Bearer ${g}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(p.ok){const r=await p.json();if(r.status==="running")if(i(`Instance "${r.name}" (${u.slice(0,8)}\u2026) is running`),console.log(`
244
- \u{1F50C} Redis connectivity`),r.host&&r.port)try{let m,h=r.tls_enabled!==!1;try{const I=await fetch(`${l}/api/v1/instances/${u}/connection`,{headers:{Authorization:`Bearer ${g}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(I.ok){const A=await I.json();m=A.password,h=A.tls_enabled!==!1}}catch{}const k=new Ye({host:r.host,port:r.port,password:m,...h?{tls:{}}:{},lazyConnect:!0,connectTimeout:5e3,retryStrategy:()=>null});await k.connect();const B=await k.ping();k.disconnect(),B==="PONG"?i(`Redis PING \u2192 PONG (${r.host}:${r.port})`):a(`Redis responded but not PONG: ${B}`)}catch(m){d(`Redis unreachable \u2014 ${m.message}`)}else a("Instance has no host/port yet");else a(`Instance "${r.name}" status: ${r.status}`)}else d(`Instance ${u.slice(0,8)}\u2026 not found (HTTP ${p.status})`)}catch(p){d(`Could not check instance \u2014 ${p.message}`)}console.log(`
245
- \u{1F6E0} Editor configs (project dir)`);const y=[{editor:"Claude Code",path:".mcp.json"},{editor:"Cursor",path:".cursor/mcp.json"},{editor:"Windsurf",path:".windsurf/mcp.json"},{editor:"Copilot / Cline",path:".vscode/mcp.json"},{editor:"Zed",path:".zed/settings.json"},{editor:"Continue.dev",path:".continue/config.json"}];let v=0;for(const{editor:p,path:r}of y){const m=n(s,r);if(e(m))try{const h=await t(m,"utf-8");h.includes("@cachly-dev/mcp-server")||h.includes("cachly")?(i(`${p}: ${r}`),v++):a(`${p}: ${r} exists but cachly not found inside`)}catch{a(`${p}: ${r} exists but could not read`)}}v===0&&d("No editor MCP configs found \u2014 run: npx @cachly-dev/mcp-server@latest autopilot"),console.log(`
241
+ `),console.log("\u{1F511} Auth token");const g=process.env.CACHLY_JWT??"";if(!g)d("CACHLY_JWT not set \u2014 run: npx @cachly-dev/mcp-server@latest autopilot");else if(g.startsWith("cky_"))i("Long-lived API key set (cky_\u2026) \u2014 no client-side expiry");else try{const u=g.split(".");if(u.length!==3)throw new Error("not a JWT");const r=JSON.parse(Buffer.from(u[1],"base64url").toString("utf-8")),p=r.exp?r.exp*1e3:null,h=p?Math.floor((p-Date.now())/6e4):null;p&&p<Date.now()?d(`JWT expired ${Math.abs(h)} minute(s) ago \u2014 get a new one: ${N("/setup-ai","health")}`):h!==null&&h<30?a(`JWT expires in ${h} minute(s) \u2014 refresh soon at ${N("/setup-ai","health")}`):i(`JWT valid${h!==null?` (expires in ${Math.floor(h/60)}h ${h%60}m)`:""}`)}catch{d("CACHLY_JWT format invalid (expected a cky_ API key or a 3-part JWT)")}console.log(`
242
+ \u{1F310} Brain API`);const l=process.env.CACHLY_API_URL??"https://api.cachly.dev";try{const u=await fetch(`${l}/health`,{signal:AbortSignal.timeout(5e3)});if(u.ok){const r=await u.json();i(`${l} reachable (status: ${r.status??"ok"})`)}else u.status===401||u.status===403?i(`${l} reachable (auth required \u2014 expected)`):d(`${l}/health returned HTTP ${u.status}`)}catch(u){d(`${l} unreachable \u2014 ${u.message}`)}console.log(`
243
+ \u{1F9E0} Brain instance`);const m=process.env.CACHLY_BRAIN_INSTANCE_ID??"";if(!m)a("CACHLY_BRAIN_INSTANCE_ID not set \u2014 will auto-resolve on first tool call");else if(g)try{const u=await fetch(`${l}/api/v1/instances/${m}`,{headers:{Authorization:`Bearer ${g}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(u.ok){const r=await u.json();if(r.status==="running")if(i(`Instance "${r.name}" (${m.slice(0,8)}\u2026) is running`),console.log(`
244
+ \u{1F50C} Redis connectivity`),r.host&&r.port)try{let p,h=r.tls_enabled!==!1;try{const I=await fetch(`${l}/api/v1/instances/${m}/connection`,{headers:{Authorization:`Bearer ${g}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(I.ok){const S=await I.json();p=S.password,h=S.tls_enabled!==!1}}catch{}const T=new Ye({host:r.host,port:r.port,password:p,...h?{tls:{}}:{},lazyConnect:!0,connectTimeout:5e3,retryStrategy:()=>null});await T.connect();const B=await T.ping();T.disconnect(),B==="PONG"?i(`Redis PING \u2192 PONG (${r.host}:${r.port})`):a(`Redis responded but not PONG: ${B}`)}catch(p){d(`Redis unreachable \u2014 ${p.message}`)}else a("Instance has no host/port yet");else a(`Instance "${r.name}" status: ${r.status}`)}else d(`Instance ${m.slice(0,8)}\u2026 not found (HTTP ${u.status})`)}catch(u){d(`Could not check instance \u2014 ${u.message}`)}console.log(`
245
+ \u{1F6E0} Editor configs (project dir)`);const y=[{editor:"Claude Code",path:".mcp.json"},{editor:"Cursor",path:".cursor/mcp.json"},{editor:"Windsurf",path:".windsurf/mcp.json"},{editor:"Copilot / Cline",path:".vscode/mcp.json"},{editor:"Zed",path:".zed/settings.json"},{editor:"Continue.dev",path:".continue/config.json"}];let v=0;for(const{editor:u,path:r}of y){const p=n(s,r);if(e(p))try{const h=await t(p,"utf-8");h.includes("@cachly-dev/mcp-server")||h.includes("cachly")?(i(`${u}: ${r}`),v++):a(`${u}: ${r} exists but cachly not found inside`)}catch{a(`${u}: ${r} exists but could not read`)}}v===0&&d("No editor MCP configs found \u2014 run: npx @cachly-dev/mcp-server@latest autopilot"),console.log(`
246
246
  \u{1FA9D} Git hook (ambient learning)`);const b=n(s,".git","hooks","post-commit");if(!e(n(s,".git")))a("Not in a git repository \u2014 skip");else if(e(b))try{(await t(b,"utf-8")).includes("cachly")?i(".git/hooks/post-commit (cachly CLS hook present)"):a(".git/hooks/post-commit exists but cachly hook not found \u2014 run setup to add it")}catch{a(".git/hooks/post-commit exists but could not read")}else a(".git/hooks/post-commit not found \u2014 run: npx @cachly-dev/mcp-server@latest autopilot");console.log(`
247
- \u{1F9EC} Embedding provider (semantic search)`);{const p=[["OPENAI_API_KEY","openai"],["GEMINI_API_KEY","gemini"],["MISTRAL_API_KEY","mistral"],["COHERE_API_KEY","cohere"],["OLLAMA_BASE_URL","ollama"]],r=(process.env.CACHLY_EMBED_PROVIDER??"").toLowerCase(),m=p.find(([h])=>process.env[h]);if(r&&r!=="cachly"){const h=p.find(([,k])=>k===r)?.[0];h&&process.env[h]?i(`BYOK: ${r} (key present in ${h})`):a(`CACHLY_EMBED_PROVIDER=${r} but its key env var is not set \u2014 semantic search will fail`)}else i(m?`BYOK: ${m[1]} auto-detected (${m[0]} present)`:"Server-side embeddings (cachly) \u2014 no key needed, uses your JWT")}console.log(`
247
+ \u{1F9EC} Embedding provider (semantic search)`);{const u=[["OPENAI_API_KEY","openai"],["GEMINI_API_KEY","gemini"],["MISTRAL_API_KEY","mistral"],["COHERE_API_KEY","cohere"],["OLLAMA_BASE_URL","ollama"]],r=(process.env.CACHLY_EMBED_PROVIDER??"").toLowerCase();if(r&&r!=="cachly"){const p=u.find(([,h])=>h===r)?.[0];p&&process.env[p]?i(`BYOK: ${r} (key present in ${p})`):a(`CACHLY_EMBED_PROVIDER=${r} but its key env var is not set \u2014 semantic search will fail`)}else{Ge==="ollama"?i("Local Ollama (OLLAMA_BASE_URL) \u2014 text stays on your machine"):Ge==="cachly"?i("Server-side embeddings (cachly, EU) \u2014 no key needed, uses your JWT"):a("No embedding provider active \u2014 sign in (CACHLY_JWT) for EU-hosted embeddings; search runs on words until then");for(const[p,h]of u)h!=="ollama"&&process.env[p]&&i(`${p} is set but not used \u2014 ${h} runs only if you name it with CACHLY_EMBED_PROVIDER=${h}`)}}console.log(`
248
248
  ${"\u2500".repeat(40)}`),c===0?console.log(`\u2705 All checks passed (${o} ok)
249
249
  `):(console.log(`\u274C ${c} check(s) failed, ${o} passed
250
250
  `),console.log(`\u{1F4A1} Fix issues with: npx @cachly-dev/mcp-server@latest autopilot
251
- `),process.exit(1)),process.exit(0)}if(process.argv[2]==="claim"){const{readFile:e,writeFile:t}=await import("node:fs/promises"),{existsSync:n}=await import("node:fs"),{resolve:s}=await import("node:path"),{homedir:o}=await import("node:os"),c=r=>{const m=process.argv.indexOf(`--${r}`);return m!==-1?process.argv[m+1]:void 0};x=(c("api-url")??"https://api.cachly.dev").replace(/\/+$/,"");const i=(c("auth-url")??nt).replace(/\/+$/,"");console.log(`
251
+ `),process.exit(1)),process.exit(0)}if(process.argv[2]==="claim"){const{readFile:e,writeFile:t}=await import("node:fs/promises"),{existsSync:n}=await import("node:fs"),{resolve:s}=await import("node:path"),{homedir:o}=await import("node:os"),c=r=>{const p=process.argv.indexOf(`--${r}`);return p!==-1?process.argv[p+1]:void 0};x=(c("api-url")??"https://api.cachly.dev").replace(/\/+$/,"");const i=(c("auth-url")??st).replace(/\/+$/,"");console.log(`
252
252
  \u{1F9E0} cachly \u2014 keep your test Brain in your own account
253
- `),(x!=="https://api.cachly.dev"||i!==nt)&&console.log(`\u26A0\uFE0F Not the cachly servers: API ${x}, sign-in ${i}
254
- `);const a=Wo({argument:c("key"),credentials:Yo()});a||(console.log("No test key (cky_trial_\u2026) was found in ~/.cachly/credentials.json."),console.log("If you already use your own cachly account, there is nothing to claim."),console.log(`Otherwise pass the key: npx @cachly-dev/mcp-server@latest claim --key cky_trial_\u2026
253
+ `),(x!=="https://api.cachly.dev"||i!==st)&&console.log(`\u26A0\uFE0F Not the cachly servers: API ${x}, sign-in ${i}
254
+ `);const a=Fo({argument:c("key"),credentials:Uo()});a||(console.log("No test key (cky_trial_\u2026) was found in ~/.cachly/credentials.json."),console.log("If you already use your own cachly account, there is nothing to claim."),console.log(`Otherwise pass the key: npx @cachly-dev/mcp-server@latest claim --key cky_trial_\u2026
255
255
  `),process.exit(1));const d=a.schluessel,g={argument:"--key",credentials:"~/.cachly/credentials.json"}[a.quelle];console.log(`Test key: ${d.slice(0,14)}\u2026 (from ${g})
256
256
  `);let l="";try{console.log(`Step 1: Sign in to your cachly account
257
- `);const r=await Fo(fetch,i);console.log(` Code: \x1B[1;33m${r.userCode}\x1B[0m`),console.log(" Open this URL and confirm the code:"),console.log(`${r.adresse}
258
- `),re(r.adresse,(m,h)=>{m||console.log(`
259
- \u2139\uFE0F No browser could be opened here (${h??"unknown"}) \u2014 please open the URL yourself.`)}),process.stdout.write(" Waiting for sign-in"),l=await zo(fetch,r,{basis:i,puls:()=>process.stdout.write(".")}),console.log(` \x1B[32m\u2713\x1B[0m
257
+ `);const r=await zo(fetch,i);console.log(` Code: \x1B[1;33m${r.userCode}\x1B[0m`),console.log(" Open this URL and confirm the code:"),console.log(`${r.adresse}
258
+ `),re(r.adresse,(p,h)=>{p||console.log(`
259
+ \u2139\uFE0F No browser could be opened here (${h??"unknown"}) \u2014 please open the URL yourself.`)}),process.stdout.write(" Waiting for sign-in"),l=await qo(fetch,r,{basis:i,puls:()=>process.stdout.write(".")}),console.log(` \x1B[32m\u2713\x1B[0m
260
260
  `)}catch(r){console.error(`
261
261
 
262
262
  ${r.message}. Nothing was changed.
263
- `),process.exit(1)}process.stdout.write("Step 2: Moving the test Brain into your account (it restarts once, up to a minute)\u2026");let u;try{u=await qo(fetch,x,l,d,"mcp",`cachly-mcp/${D}`),console.log(` \x1B[32m\u2713\x1B[0m
263
+ `),process.exit(1)}process.stdout.write("Step 2: Moving the test Brain into your account (it restarts once, up to a minute)\u2026");let m;try{m=await Ko(fetch,x,l,d,"mcp",`cachly-mcp/${D}`),console.log(` \x1B[32m\u2713\x1B[0m
264
264
  `)}catch(r){console.error(`
265
265
 
266
- ${Vo(r)}
267
- `),process.exit(1)}w=u.apiKey,te(u.apiKey),ot(u.instanceId,{apiKey:u.apiKey}),await ge(u.apiKey),await fe(u.instanceId);const y=o(),v=new Set([...Object.values(be).map(r=>s(process.cwd(),r)),s(y,".claude.json"),s(y,".claude","mcp.json"),s(y,".cursor","mcp.json"),s(y,".codeium","windsurf","mcp_config.json")]);let b=0;for(const r of v)if(n(r))try{const m=Zo(await e(r,"utf-8"),d,u.apiKey);m.ersetzt&&(await t(r,m.text,"utf-8"),b++)}catch{}const p=await Ko(fetch,x,u.apiKey,u.instanceId);console.log(Go(u,p)),console.log(`
266
+ ${Zo(r)}
267
+ `),process.exit(1)}w=m.apiKey,te(m.apiKey),nt(m.instanceId,{apiKey:m.apiKey}),await ge(m.apiKey),await fe(m.instanceId);const y=o(),v=new Set([...Object.values(be).map(r=>s(process.cwd(),r)),s(y,".claude.json"),s(y,".claude","mcp.json"),s(y,".cursor","mcp.json"),s(y,".codeium","windsurf","mcp_config.json")]);let b=0;for(const r of v)if(n(r))try{const p=Qo(await e(r,"utf-8"),d,m.apiKey);p.ersetzt&&(await t(r,p.text,"utf-8"),b++)}catch{}const u=await Go(fetch,x,m.apiKey,m.instanceId);console.log(Vo(m,u)),console.log(`
268
268
  New key stored in ~/.cachly/credentials.json${b?` and in ${b} editor config file(s) that held the test key`:""}.`),console.log(`Restart your editor (or reload its MCP servers) so it uses the new key.
269
269
  `),process.exit(0)}const ve=process.argv[2]==="autopilot";if(process.argv[2]==="autosetup"||process.argv[2]==="setup"||ve){const{writeFile:e,mkdir:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o,dirname:c}=await import("node:path"),{createInterface:i}=await import("node:readline"),a=Date.now(),d=ve?"autopilot":"setup",g=process.argv.indexOf("--api-url");g!==-1&&process.argv[g+1]&&(x=process.argv[g+1].replace(/\/+$/,""),console.log(`\u2139\uFE0F Using self-hosted backend: ${x}
270
- `)),S("setup_started");const l=process.stdin.isTTY===!0,u=ve||process.argv.includes("--yes")||process.argv.includes("-y")||!l;ve?console.log(`\u{1F916} Autopilot \u2014 one-command setup (auth \u2192 instance \u2192 configs \u2192 Brain), zero prompts.
270
+ `)),A("setup_started");const l=process.stdin.isTTY===!0,m=ve||process.argv.includes("--yes")||process.argv.includes("-y")||!l;ve?console.log(`\u{1F916} Autopilot \u2014 one-command setup (auth \u2192 instance \u2192 configs \u2192 Brain), zero prompts.
271
271
  `):!l&&!process.argv.includes("--yes")&&!process.argv.includes("-y")&&console.log(`\u2139\uFE0F Non-interactive terminal detected \u2014 running in automatic mode (no prompts).
272
- `);const y=i({input:process.stdin,output:process.stdout}),v=(f,_="")=>u?(console.log(`${f}${_}`),Promise.resolve(_)):new Promise(R=>y.question(f,J=>R(J.trim()||_)));console.log(`
272
+ `);const y=i({input:process.stdin,output:process.stdout}),v=(f,_="")=>m?(console.log(`${f}${_}`),Promise.resolve(_)):new Promise(R=>y.question(f,J=>R(J.trim()||_)));console.log(`
273
273
  \u{1F9E0} cachly AI Brain \u2014 Setup`),console.log(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
274
274
  `);let b=process.env.CACHLY_JWT??"";if(b)console.log(`\u2713 Using token from CACHLY_JWT env var
275
275
  `);else{console.log(`Step 1: Sign in to cachly (free, no credit card)
276
- `),S("setup_auth_started");let f="",_="",R="",J=5e3,Y=!1,Z="cachly";try{const q=await fetch(`${x}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({}),signal:AbortSignal.timeout(8e3)});if(q.ok){const L=await q.json();f=L.device_code,_=L.user_code;const M=L.verification_uri||N("/device",d);R=`${M}${M.includes("?")?"&":"?"}code=${encodeURIComponent(_)}`,J=(L.interval??5)*1e3,Y=!!f}}catch{}if(!Y)try{const L=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(L.ok){const M=await L.json();f=M.device_code,_=M.user_code,R=M.verification_uri_complete,J=(M.interval??5)*1e3,Y=!0,Z="keycloak"}}catch{}if(Y&&f){console.log(` Code: \x1B[1;33m${_}\x1B[0m`),console.log(" Open this URL and confirm the code:"),console.log(`${R}
277
- `),re(R,(L,M)=>{if(L){S("device_browser_opened",{stelle:"setup"});return}S("device_browser_failed",{reason:M??"unknown",stelle:"setup"}),console.log(` \u2139\uFE0F No browser could be opened here (${M??"unknown"}) \u2014 please open the URL yourself.
276
+ `),A("setup_auth_started");let f="",_="",R="",J=5e3,Y=!1,Z="cachly";try{const q=await fetch(`${x}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({}),signal:AbortSignal.timeout(8e3)});if(q.ok){const L=await q.json();f=L.device_code,_=L.user_code;const M=L.verification_uri||N("/device",d);R=`${M}${M.includes("?")?"&":"?"}code=${encodeURIComponent(_)}`,J=(L.interval??5)*1e3,Y=!!f}}catch{}if(!Y)try{const L=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(L.ok){const M=await L.json();f=M.device_code,_=M.user_code,R=M.verification_uri_complete,J=(M.interval??5)*1e3,Y=!0,Z="keycloak"}}catch{}if(Y&&f){console.log(` Code: \x1B[1;33m${_}\x1B[0m`),console.log(" Open this URL and confirm the code:"),console.log(`${R}
277
+ `),re(R,(L,M)=>{if(L){A("device_browser_opened",{stelle:"setup"});return}A("device_browser_failed",{reason:M??"unknown",stelle:"setup"}),console.log(` \u2139\uFE0F No browser could be opened here (${M??"unknown"}) \u2014 please open the URL yourself.
278
278
  `)}),process.stdout.write(" Waiting for authorization");const q=Date.now()+600*1e3;for(;Date.now()<q;){await new Promise(L=>setTimeout(L,J)),process.stdout.write(".");try{let L=null;if(Z==="cachly")try{const M=await fetch(`${x}/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:f}),signal:AbortSignal.timeout(8e3)});M.status<500&&(L=await M.json())}catch{}else{const M="https://auth.cachly.dev/realms/cachly/protocol/openid-connect";try{L=await(await fetch(`${M}/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=${f}`,signal:AbortSignal.timeout(8e3)})).json()}catch{}}if(L?.access_token){b=L.access_token,console.log(` \x1B[32m\u2713 Authorized!\x1B[0m
279
- `),S("setup_auth_completed"),S("device_flow_completed");break}L?.error==="slow_down"?J=Math.min(J+2e3,15e3):L?.error&&L.error!=="authorization_pending"&&(S("device_flow_failed",{reason:L.error}),console.error(`
279
+ `),A("setup_auth_completed"),A("device_flow_completed");break}L?.error==="slow_down"?J=Math.min(J+2e3,15e3):L?.error&&L.error!=="authorization_pending"&&(A("device_flow_failed",{reason:L.error}),console.error(`
280
280
  Auth error: ${L.error}. Aborting.
281
- `),y.close(),process.exit(1))}catch{}}b||(S("device_flow_failed",{reason:"timeout"}),console.error(`
281
+ `),y.close(),process.exit(1))}catch{}}b||(A("device_flow_failed",{reason:"timeout"}),console.error(`
282
282
  Timed out waiting for authorization. Aborting.
283
- `),y.close(),process.exit(1)),console.log("")}else{S("device_flow_failed",{reason:"device_flow_unavailable"});const q=N("/setup-ai",d);console.log(` \u26A0\uFE0F Could not start automatic sign-in. Opening browser for web sign-in...
283
+ `),y.close(),process.exit(1)),console.log("")}else{A("device_flow_failed",{reason:"device_flow_unavailable"});const q=N("/setup-ai",d);console.log(` \u26A0\uFE0F Could not start automatic sign-in. Opening browser for web sign-in...
284
284
  `),console.log(` URL: \x1B[36m${q}\x1B[0m`),console.log(" 1. Sign up / log in at the URL above"),console.log(" 2. Go to Settings \u2192 API Keys \u2192 Create new key"),console.log(` 3. Copy the key (starts with cky_live_...)
285
- `),re(q),u?(S("device_flow_failed",{reason:"non_interactive_no_key"}),console.error(`
285
+ `),re(q),m?(A("device_flow_failed",{reason:"non_interactive_no_key"}),console.error(`
286
286
  \u26A0\uFE0F This terminal is non-interactive, so the key cannot be pasted here.`),console.error(` Get your key at the URL above, then set it and re-run setup:
287
287
  `),console.error(` \x1B[1mCACHLY_JWT=cky_live_xxx npx @cachly-dev/mcp-server@latest autopilot\x1B[0m
288
288
  `),console.error(` Or add it to your editor's MCP config under env.CACHLY_JWT.
289
289
  `),y.close(),process.exit(1)):(b=await v(" Paste API key (cky_live_...): "),b||(console.error(`
290
290
  API key is required. Aborting.
291
- `),y.close(),process.exit(1)),S("setup_auth_completed"),console.log(""))}}if(b.startsWith("eyJ")){process.stdout.write("\u23F3 Generating your API key...");try{const f=await fetch(`${x}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${b}`},body:JSON.stringify({name:"cachly-mcp-setup",scope:"read_write"})});if(!f.ok)throw new Error(`HTTP ${f.status}`);const _=await f.json();if(!_.key)throw new Error("no key in response");b=_.key,console.log(` \u2713
291
+ `),y.close(),process.exit(1)),A("setup_auth_completed"),console.log(""))}}if(b.startsWith("eyJ")){process.stdout.write("\u23F3 Generating your API key...");try{const f=await fetch(`${x}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${b}`},body:JSON.stringify({name:"cachly-mcp-setup",scope:"read_write"})});if(!f.ok)throw new Error(`HTTP ${f.status}`);const _=await f.json();if(!_.key)throw new Error("no key in response");b=_.key,console.log(` \u2713
292
292
  `)}catch{console.log(` (skipped)
293
- `)}}process.stdout.write("\u23F3 Fetching your instances...");let p=[];try{const f=await fetch(`${x}/api/v1/instances`,{headers:{Authorization:`Bearer ${b}`}});if(!f.ok)throw new Error(`HTTP ${f.status}`);p=((await f.json()).data??[]).filter(R=>R.status==="running")}catch(f){const _=f.message;console.error(`
293
+ `)}}process.stdout.write("\u23F3 Fetching your instances...");let u=[];try{const f=await fetch(`${x}/api/v1/instances`,{headers:{Authorization:`Bearer ${b}`}});if(!f.ok)throw new Error(`HTTP ${f.status}`);u=((await f.json()).data??[]).filter(R=>R.status==="running")}catch(f){const _=f.message;console.error(`
294
294
 
295
295
  Failed to fetch instances: ${_}`),_.includes("401")&&(console.error(`Token rejected. Get a valid token at ${N("/setup-ai",d)}
296
- `),re(N("/setup-ai",d))),y.close(),process.exit(1)}if(console.log(` found ${p.length}
297
- `),p.length===0){process.stdout.write("\u23F3 Creating your free Brain instance...");try{const f=await fetch(`${x}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${b}`,"Content-Type":"application/json"}});if(!f.ok)throw new Error(`HTTP ${f.status}`);const _=await f.json();if(_.instance)p=[_.instance];else if(_.instance_id){const R=_.instance_id;console.log(` \u2713 created (${R.slice(0,8)}\u2026)
298
- `),process.stdout.write("\u23F3 Waiting for instance to start");for(let J=0;J<45;J++){await new Promise(Y=>setTimeout(Y,3e3)),process.stdout.write(".");try{const Y=await fetch(`${x}/api/v1/instances/${R}`,{headers:{Authorization:`Bearer ${b}`}});if(Y.ok){const Z=await Y.json();if(Z.status==="running"){p=[Z];break}}}catch{}}console.log("")}}catch(f){console.log(` failed: ${f.message}
299
- `)}p.length===0&&(console.error(`
296
+ `),re(N("/setup-ai",d))),y.close(),process.exit(1)}if(console.log(` found ${u.length}
297
+ `),u.length===0){process.stdout.write("\u23F3 Creating your free Brain instance...");try{const f=await fetch(`${x}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${b}`,"Content-Type":"application/json"}});if(!f.ok)throw new Error(`HTTP ${f.status}`);const _=await f.json();if(_.instance)u=[_.instance];else if(_.instance_id){const R=_.instance_id;console.log(` \u2713 created (${R.slice(0,8)}\u2026)
298
+ `),process.stdout.write("\u23F3 Waiting for instance to start");for(let J=0;J<45;J++){await new Promise(Y=>setTimeout(Y,3e3)),process.stdout.write(".");try{const Y=await fetch(`${x}/api/v1/instances/${R}`,{headers:{Authorization:`Bearer ${b}`}});if(Y.ok){const Z=await Y.json();if(Z.status==="running"){u=[Z];break}}}catch{}}console.log("")}}catch(f){console.log(` failed: ${f.message}
299
+ `)}u.length===0&&(console.error(`
300
300
  Could not create an instance automatically. Opening ${N("/instances",d)} \u2026
301
- `),re(N("/instances",d)),y.close(),process.exit(1))}const r=p[0];p.length>1&&(console.log(`\u2139\uFE0F Multiple instances found \u2014 using most recent: ${r.name}`),console.log(` (Run with --instance-id <id> to use a different one)
301
+ `),re(N("/instances",d)),y.close(),process.exit(1))}const r=u[0];u.length>1&&(console.log(`\u2139\uFE0F Multiple instances found \u2014 using most recent: ${r.name}`),console.log(` (Run with --instance-id <id> to use a different one)
302
302
  `)),console.log(`\u2713 Instance: ${r.name} (${r.id.slice(0,8)}\u2026)
303
- `),S("setup_instance_ready",{instance_id:r.id});const m=process.cwd(),h=[],{homedir:k}=await import("node:os"),B=k();h.push("claude"),s(o(m,".cursor"))&&h.push("cursor"),s(o(m,".windsurf"))&&h.push("windsurf"),s(o(m,".vscode"))&&h.push("copilot"),s(o(m,".continue"))&&h.push("continue");const I=process.platform==="darwin"?o(B,"Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev"):o(B,".vscode/extensions");(s(I)&&!h.includes("copilot")||s(I))&&h.push("cline");const A=process.platform==="darwin"?o(B,"Library/Application Support/Zed"):o(B,".config/zed");s(A)&&h.push("zed");const T=f=>({claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",copilot:"GitHub Copilot",continue:"Continue.dev",cline:"Cline (VSCode)",zed:"Zed"})[f]??f,E=h;console.log(`Step 3: Configuring for: ${E.map(T).join(", ")}
304
- `);const{existsSync:$}=await import("node:fs"),C=[];let j=0;te(b);for(const f of E){const _=be[f]??".mcp.json",R=o(m,_);try{await t(c(R),{recursive:!0});const J=$(R),Y=await St(R,b,r.id,f,{readFile:n,existsSync:$});await e(R,Y,"utf-8"),console.log(`\u2705 ${J?"Updated":"Written"}: ${_}`),j++}catch(J){const Y=J.message;console.log(`\u26A0\uFE0F Could not write ${_}: ${Y}`),console.log(" Fix permissions or run with sudo, then re-run setup."),C.push({file:_,reason:Y})}}const F=o(B,".claude","mcp.json");try{await t(c(F),{recursive:!0});let f={};if(s(F))try{f=JSON.parse(await n(F,"utf-8"))}catch{}f.mcpServers??={},f.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(b,r.id,{includeApiKey:!0})},await e(F,JSON.stringify(f,null,2),"utf-8"),console.log("\u2705 Written: ~/.claude/mcp.json (global \u2014 works in every project)"),j++}catch(f){const _=f.message;console.log(`\u26A0\uFE0F Could not write ~/.claude/mcp.json: ${_}`),C.push({file:"~/.claude/mcp.json",reason:_})}const z=await kt(m,r.id);for(const[f,_]of Object.entries(z))console.log(`${_==="updated"?"\u2705 Updated":_==="appended"?"\u2705 Appended to":"\u2705 Written"}: ${f}`);w=b;let ue=0;if(s(o(m,".git"))){process.stdout.write("\u23F3 Bootstrapping Brain from git history (~10s)...");try{const f=await U("brain_from_git",{instance_id:r.id,repo_path:m,limit:100}),_=f.match(/Ingested: \*\*(\d+)\*\*/);ue=_?parseInt(_[1],10):0,console.log(` \u2713 ${ue} lesson${ue===1?"":"s"} extracted from git history`);const R=So(f);R&&(console.log(""),console.log(R))}catch(f){console.log(` (skipped: ${f.message.slice(0,80)})`)}}if(ue===0){process.stdout.write("\u{1F331} Seeding 16 universal engineering lessons (first recall works instantly)...");try{await U("brain_seed_starter",{instance_id:r.id}),console.log(" \u2713");try{const f=await U("smart_recall",{instance_id:r.id,query:"docker build slow"}),_=En(f);_&&(console.log(""),console.log(Ao(_.topic,_.what)))}catch{}}catch(f){console.log(` (skipped: ${f.message.slice(0,60)})`)}}process.stdout.write(`
303
+ `),A("setup_instance_ready",{instance_id:r.id});const p=process.cwd(),h=[],{homedir:T}=await import("node:os"),B=T();h.push("claude"),s(o(p,".cursor"))&&h.push("cursor"),s(o(p,".windsurf"))&&h.push("windsurf"),s(o(p,".vscode"))&&h.push("copilot"),s(o(p,".continue"))&&h.push("continue");const I=process.platform==="darwin"?o(B,"Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev"):o(B,".vscode/extensions");(s(I)&&!h.includes("copilot")||s(I))&&h.push("cline");const S=process.platform==="darwin"?o(B,"Library/Application Support/Zed"):o(B,".config/zed");s(S)&&h.push("zed");const k=f=>({claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",copilot:"GitHub Copilot",continue:"Continue.dev",cline:"Cline (VSCode)",zed:"Zed"})[f]??f,E=h;console.log(`Step 3: Configuring for: ${E.map(k).join(", ")}
304
+ `);const{existsSync:$}=await import("node:fs"),C=[];let j=0;te(b);for(const f of E){const _=be[f]??".mcp.json",R=o(p,_);try{await t(c(R),{recursive:!0});const J=$(R),Y=await St(R,b,r.id,f,{readFile:n,existsSync:$});await e(R,Y,"utf-8"),console.log(`\u2705 ${J?"Updated":"Written"}: ${_}`),j++}catch(J){const Y=J.message;console.log(`\u26A0\uFE0F Could not write ${_}: ${Y}`),console.log(" Fix permissions or run with sudo, then re-run setup."),C.push({file:_,reason:Y})}}const F=o(B,".claude","mcp.json");try{await t(c(F),{recursive:!0});let f={};if(s(F))try{f=JSON.parse(await n(F,"utf-8"))}catch{}f.mcpServers??={},f.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(b,r.id,{includeApiKey:!0})},await e(F,JSON.stringify(f,null,2),"utf-8"),console.log("\u2705 Written: ~/.claude/mcp.json (global \u2014 works in every project)"),j++}catch(f){const _=f.message;console.log(`\u26A0\uFE0F Could not write ~/.claude/mcp.json: ${_}`),C.push({file:"~/.claude/mcp.json",reason:_})}const z=await Tt(p,r.id);for(const[f,_]of Object.entries(z))console.log(`${_==="updated"?"\u2705 Updated":_==="appended"?"\u2705 Appended to":"\u2705 Written"}: ${f}`);w=b;let ue=0;if(s(o(p,".git"))){process.stdout.write("\u23F3 Bootstrapping Brain from git history (~10s)...");try{const f=await U("brain_from_git",{instance_id:r.id,repo_path:p,limit:100}),_=f.match(/Ingested: \*\*(\d+)\*\*/);ue=_?parseInt(_[1],10):0,console.log(` \u2713 ${ue} lesson${ue===1?"":"s"} extracted from git history`);const R=So(f);R&&(console.log(""),console.log(R))}catch(f){console.log(` (skipped: ${f.message.slice(0,80)})`)}}if(ue===0){process.stdout.write("\u{1F331} Seeding 16 universal engineering lessons (first recall works instantly)...");try{await U("brain_seed_starter",{instance_id:r.id}),console.log(" \u2713");try{const f=await U("smart_recall",{instance_id:r.id,query:"docker build slow"}),_=Rn(f);_&&(console.log(""),console.log(ko(_.topic,_.what)))}catch{}}catch(f){console.log(` (skipped: ${f.message.slice(0,60)})`)}}process.stdout.write(`
305
305
  \u23F3 Fetching your Brain health preview...`);try{const f=await fetch(`${x}/api/v1/instances/${r.id}/memory`,{headers:{Authorization:`Bearer ${b}`},signal:AbortSignal.timeout(6e3)});if(f.ok){const _=await f.json(),R=_.lesson_count??0,J=_.context_count??0,Y=Math.round(_.iq_boost_pct??0),Z=R===0?"Intern \u{1F331}":R<10?"Junior Dev \u{1F527}":R<30?"Mid Dev \u26A1":R<60?"Senior Dev \u{1F9E0}":R<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}";if(console.log(` \u2713
306
306
  `),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 \u{1F9E0} Brain Health Report \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Lessons stored : ${String(R).padEnd(6)} \u2502 Level: ${Z.padEnd(20)}\u2502`),console.log(`\u2502 Context entries : ${String(J).padEnd(6)} \u2502 Quality score: ${String(Y).padEnd(3)}% \u2502`),R===0&&(console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 Your Brain is empty and ready to learn. \u2502"),console.log("\u2502 After your first coding session it will contain: \u2502"),console.log("\u2502 \u2022 Lessons from every bug you fixed \u2502"),console.log("\u2502 \u2022 Your project's indexed files \u2502"),console.log("\u2502 \u2022 A session summary for next time \u2502")),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),R>=5){process.stdout.write(`
307
307
  \u23F3 Running predictive risk scan...`);try{const L=(await U("brain_predict",{instance_id:r.id,context:"starting a new development session"})).split(`
@@ -311,15 +311,15 @@ Could not create an instance automatically. Opening ${N("/instances",d)} \u2026
311
311
  `),console.log(` No more re-explaining your stack. No repeated mistakes.
312
312
  `),console.log(` Dashboard: ${N(`/instances/${r.id}`,d)}`),console.log(`
313
313
  \u{1F4DB} Add a live badge to your README:`),console.log(` npx @cachly-dev/mcp-server@latest badge
314
- `),!u)try{if(console.log(`
314
+ `),!m)try{if(console.log(`
315
315
  \u{1F451} Governance (optional \u2014 role model: admin \xB7 reviewer \xB7 contributor \xB7 viewer)`),console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),(await v(" Set yourself as the first admin? (y/N): ","N")).toLowerCase()==="y"){const _=await v(' Your handle (e.g. "alice"): ');_.trim()&&await U("team_assign_role",{instance_id:r.id,handle:_.trim(),role:"admin"}).catch(()=>"")&&(console.log(` \u2705 ${_.trim()} is now admin. Invite teammates:
316
316
  `),console.log(` team_assign_role(instance_id="${r.id}", handle="<teammate>", role="contributor", assigned_by="${_.trim()}")
317
317
  `))}else console.log(` Skipped \u2014 run team_assign_role at any time.
318
- `)}catch{}if(!u){const f=await v(" \u{1F4EC} Stay in the loop? Email for release notes [Enter to skip]: ");if(f&&f.includes("@"))try{await fetch(`${x}/api/newsletter/subscribe`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:f.trim().toLowerCase(),source:"mcp-setup"}),signal:AbortSignal.timeout(5e3)}),console.log(` \u2705 Subscribed \u2014 you'll only hear from us when it matters.
319
- `)}catch{}}try{const f=await Ge(process.cwd(),r.id,b||void 0);f==="written"?console.log(`
318
+ `)}catch{}if(!m){const f=await v(" \u{1F4EC} Stay in the loop? Email for release notes [Enter to skip]: ");if(f&&f.includes("@"))try{await fetch(`${x}/api/newsletter/subscribe`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:f.trim().toLowerCase(),source:"mcp-setup"}),signal:AbortSignal.timeout(5e3)}),console.log(` \u2705 Subscribed \u2014 you'll only hear from us when it matters.
319
+ `)}catch{}}try{const f=await Ve(process.cwd(),r.id,b||void 0);f==="written"?console.log(`
320
320
  \u2705 CLS git hook installed \u2014 your brain will learn from every commit.`):f==="upgraded"?console.log(`
321
- \u2705 CLS git hook upgraded to ${Ve}.`):f==="appended"&&console.log(`
322
- \u2705 CLS git hook appended to existing post-commit.`)}catch{}if(E.includes("claude"))try{const f=await Qe(process.cwd(),r.id),_=f.scripts==="written"?"\u2705 Written":f.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${Xe})`:"\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{}E.includes("cursor")&&await pe("cursor",process.cwd(),r.id," "),E.includes("copilot")&&await pe("copilot",process.cwd(),r.id," "),(s(o(B,".codex"))||s(o(m,".codex")))&&await pe("codex",process.cwd(),r.id," "),(s(o(B,".gemini"))||s(o(m,".gemini")))&&await pe("gemini",process.cwd(),r.id," "),w=b;const Re=Math.round((Date.now()-a)/1e3);if(C.length>0&&S("setup_config_write_failed",{instance_id:r.id,failed:C.length,succeeded:j}),S("setup_completed",{instance_id:r.id,elapsed_s:Re,config_failures:C.length}),C.length>0&&j===0){console.log(`
321
+ \u2705 CLS git hook upgraded to ${Ze}.`):f==="appended"&&console.log(`
322
+ \u2705 CLS git hook appended to existing post-commit.`)}catch{}if(E.includes("claude"))try{const f=await Xe(process.cwd(),r.id),_=f.scripts==="written"?"\u2705 Written":f.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${et})`:"\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{}E.includes("cursor")&&await pe("cursor",process.cwd(),r.id," "),E.includes("copilot")&&await pe("copilot",process.cwd(),r.id," "),(s(o(B,".codex"))||s(o(p,".codex")))&&await pe("codex",process.cwd(),r.id," "),(s(o(B,".gemini"))||s(o(p,".gemini")))&&await pe("gemini",process.cwd(),r.id," "),w=b;const Re=Math.round((Date.now()-a)/1e3);if(C.length>0&&A("setup_config_write_failed",{instance_id:r.id,failed:C.length,succeeded:j}),A("setup_completed",{instance_id:r.id,elapsed_s:Re,config_failures:C.length}),C.length>0&&j===0){console.log(`
323
323
  \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(`
324
324
  Your Brain instance exists, but no editor knows about it yet.`),console.log(" Failed writes:");for(const f of C)console.log(` \u2022 ${f.file} \u2014 ${f.reason}`);console.log(`
325
325
  Fix the permissions above and re-run, or configure manually:`),console.log(` CACHLY_JWT=${b.slice(0,12)}\u2026 CACHLY_BRAIN_INSTANCE_ID=${r.id}`),console.log(` Docs: ${N("/docs/mcp",d)}
@@ -339,17 +339,17 @@ Could not create an instance automatically. Opening ${N("/instances",d)} \u2026
339
339
  `),console.error(" export CACHLY_BRAIN_INSTANCE_ID=<uuid>"),console.error(" export CACHLY_JWT=<cky_live_...>"),console.error(` npx @cachly-dev/mcp-server@latest learn-git .
340
340
  `),process.exit(1)),console.log(`
341
341
  \u{1F9E0} Learning from git history: ${s}`),console.log(` Instance: ${o.slice(0,8)}\u2026 Max commits: ${c}
342
- `);try{const i=await U("brain_from_git",{instance_id:o,repo_path:s,limit:c});console.log(i),S("brain_from_git",{api_key:w,instance_id:o}),console.log(`
342
+ `);try{const i=await U("brain_from_git",{instance_id:o,repo_path:s,limit:c});console.log(i),A("brain_from_git",{api_key:w,instance_id:o}),console.log(`
343
343
  \u2705 Brain learned from your commits.
344
344
  `),await new Promise(a=>setTimeout(a,300))}catch(i){console.error(`
345
345
  \u274C learn-git failed: ${i.message}
346
- `),process.exit(1)}process.exit(0)}if(process.argv[2]==="ambient-recall"&&await Ho(process.argv.slice(3),process.argv[1]),process.argv[2]==="ambient-auffrischen"&&await Po(),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),n=process.argv.slice(4).join(" ").slice(0,200)||void 0,s={ts:new Date().toISOString(),event:"credit",injected:0,prevented:t,note:n};await Mo(s),await Nn(process.env.CACHLY_BRAIN_INSTANCE_ID??H,s),console.log(`\u2705 ambient credit recorded: ${t} tokens${n?` (${n})`:""}`)}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 et(),t=Sn(e),n=e.slice(-5);if(console.log(`
346
+ `),process.exit(1)}process.exit(0)}if(process.argv[2]==="ambient-recall"&&await Po(process.argv.slice(3),process.argv[1]),process.argv[2]==="ambient-auffrischen"&&await Oo(),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),n=process.argv.slice(4).join(" ").slice(0,200)||void 0,s={ts:new Date().toISOString(),event:"credit",injected:0,prevented:t,note:n};await Do(s),await Ln(process.env.CACHLY_BRAIN_INSTANCE_ID??H,s),console.log(`\u2705 ambient credit recorded: ${t} tokens${n?` (${n})`:""}`)}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 tt(),t=Sn(e),n=e.slice(-5);if(console.log(`
347
347
  \u{1F9E0} Ambient Recall \u2014 net-token ledger
348
348
  `),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`),n.length>0){console.log(`
349
- Last entries:`);for(const s of n){const o=s.prevented>0?`+${s.prevented} prevented`:`-${s.injected} injected`;console.log(` \u2022 ${s.ts.slice(0,19)} ${s.event}: ${o}${s.note?` (${s.note})`:""}`)}}console.log(""),process.exit(0)}if(process.argv[2]==="doctor"){const{checkNodeVersion:e,checkCredential:t,checkApiReachable:n,checkAuthAccepted:s,checkInstance:o,checkVectorCoverage:c,inspectAmbientHooks:i,checkHooks:a,checkLedger:d,renderDoctorReport:g,doctorExitCode:l}=await import("./doctor.js"),u=[e(),t(w),await n(x),await s(x,w),o(process.env.CACHLY_BRAIN_INSTANCE_ID??H),await c(x,w,process.env.CACHLY_BRAIN_INSTANCE_ID??H),a(i(process.cwd())),d(await et(),Do())];console.log(g(u)),process.exit(l(u))}if(process.argv[2]==="cls-ingest"){try{const e=process.argv[3];(!e||!w)&&process.exit(0);let t;try{t=JSON.parse(e)}catch{process.exit(0)}const n=t.instance_id??H;(!n||!t.source)&&process.exit(0),await U("cls_ingest",{instance_id:n,source:t.source,payload:t.payload??{}})}catch{}process.exit(0)}if(!w){const e=Nt();if(e)try{const t=await fetch(Bt(e),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:Lt(e),signal:AbortSignal.timeout(8e3)});if(t.ok){const n=await t.json();n.access_token&&(w=n.access_token,ae(n.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).
349
+ Last entries:`);for(const s of n){const o=s.prevented>0?`+${s.prevented} prevented`:`-${s.injected} injected`;console.log(` \u2022 ${s.ts.slice(0,19)} ${s.event}: ${o}${s.note?` (${s.note})`:""}`)}}console.log(""),process.exit(0)}if(process.argv[2]==="doctor"){const{checkNodeVersion:e,checkCredential:t,checkApiReachable:n,checkAuthAccepted:s,checkInstance:o,checkVectorCoverage:c,inspectAmbientHooks:i,checkHooks:a,checkLedger:d,renderDoctorReport:g,doctorExitCode:l}=await import("./doctor.js"),m=[e(),t(w),await n(x),await s(x,w),o(process.env.CACHLY_BRAIN_INSTANCE_ID??H),await c(x,w,process.env.CACHLY_BRAIN_INSTANCE_ID??H),a(i(process.cwd())),d(await tt(),Jo())];console.log(g(m)),process.exit(l(m))}if(process.argv[2]==="cls-ingest"){try{const e=process.argv[3];(!e||!w)&&process.exit(0);let t;try{t=JSON.parse(e)}catch{process.exit(0)}const n=t.instance_id??H;(!n||!t.source)&&process.exit(0),await U("cls_ingest",{instance_id:n,source:t.source,payload:t.payload??{}})}catch{}process.exit(0)}if(!w){const e=Lt();if(e)try{const t=await fetch(jt(e),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:Bt(e),signal:AbortSignal.timeout(8e3)});if(t.ok){const n=await t.json();n.access_token&&(w=n.access_token,ae(n.access_token),A("m2m_auth_completed",{grant:"client_credentials",client_id:e.clientId}),process.stderr.write(`\u{1F916} cachly: authenticated via client_credentials (M2M, headless).
350
350
  `))}else process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth failed (${t.status}). Check CACHLY_CLIENT_ID / CACHLY_CLIENT_SECRET.
351
- `),S("m2m_auth_failed",{status:t.status})}catch(t){process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth error: ${t.message}
352
- `),S("m2m_auth_failed",{reason:"network"})}}const Vn=["demo","share","publish","health","autosetup","setup","autopilot","init","digest","invite","badge","join","upgrade","bench","tool-specs","openapi","ambient-credit","ambient-stats","doctor"];if(!w&&!Vn.includes(process.argv[2]??""))if(!process.argv[2]&&process.stdout.isTTY===!0&&Jt){const s=`
351
+ `),A("m2m_auth_failed",{status:t.status})}catch(t){process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth error: ${t.message}
352
+ `),A("m2m_auth_failed",{reason:"network"})}}const Zn=["demo","share","publish","health","autosetup","setup","autopilot","init","digest","invite","badge","join","upgrade","bench","tool-specs","openapi","ambient-credit","ambient-stats","doctor"];if(!w&&!Zn.includes(process.argv[2]??""))if(!process.argv[2]&&process.stdout.isTTY===!0&&Yt){const s=`
353
353
  \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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
354
354
  \u2551 \u{1F9E0} cachly AI Brain \u2014 Setup required \u2551
355
355
  \u2560\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563
@@ -369,7 +369,7 @@ Could not create an instance automatically. Opening ${N("/instances",d)} \u2026
369
369
  \u{1F9E0} cachly: no API key yet \u2014 the first cachly tool call creates a test Brain on EU servers, no sign-up.
370
370
  (Own account: npx @cachly-dev/mcp-server@latest autopilot)
371
371
 
372
- `);else{const e=It(w);if(e!==null){const t=Math.floor((e-Date.now())/6e4);t<=0?process.stderr.write(`
372
+ `);else{const e=Et(w);if(e!==null){const t=Math.floor((e-Date.now())/6e4);t<=0?process.stderr.write(`
373
373
  \u26A0\uFE0F cachly: CACHLY_JWT expired ${Math.abs(t)} minute(s) ago.
374
374
  All tool calls will fail. Get a fresh token at ${N("/setup-ai","jwt-expiry")}
375
375
 
@@ -377,7 +377,7 @@ Could not create an instance automatically. Opening ${N("/instances",d)} \u2026
377
377
  \u26A0\uFE0F cachly: CACHLY_JWT expires in ${t} minute(s).
378
378
  Refresh it soon at ${N("/setup-ai","jwt-expiry")} to avoid interruptions.
379
379
 
380
- `)}}process.env.PORT||pn({aktuelle:dn(D)});const we=process.env.PORT?parseInt(process.env.PORT,10):void 0;if(we){const{createServer:e}=await import("node:http");e((n,s)=>{const o=new URL(n.url??"/",`http://localhost:${we}`);if(o.pathname==="/health"){s.writeHead(200,{"Content-Type":"application/json"}),s.end(JSON.stringify({status:"ok",version:D,zeroResults:{total:mo,last10:uo.slice(-10).map(c=>({query:c.query,ts:new Date(c.ts).toISOString()}))}}));return}if(o.pathname==="/mcp"||o.pathname==="/"){(async()=>{const c=Un(),i=new Ut({sessionIdGenerator:void 0});s.on("close",()=>{i.close().catch(()=>{}),c.close().catch(()=>{})});try{await c.connect(i),await i.handleRequest(n,s)}catch(a){process.stderr.write(`cachly-mcp HTTP: ${a.message}
380
+ `)}}process.env.PORT||un({aktuelle:pn(D)});const we=process.env.PORT?parseInt(process.env.PORT,10):void 0;if(we){const{createServer:e}=await import("node:http");e((n,s)=>{const o=new URL(n.url??"/",`http://localhost:${we}`);if(o.pathname==="/health"){s.writeHead(200,{"Content-Type":"application/json"}),s.end(JSON.stringify({status:"ok",version:D,zeroResults:{total:go,last10:mo.slice(-10).map(c=>({query:c.query,ts:new Date(c.ts).toISOString()}))}}));return}if(o.pathname==="/mcp"||o.pathname==="/"){(async()=>{const c=Wn(),i=new Wt({sessionIdGenerator:void 0});s.on("close",()=>{i.close().catch(()=>{}),c.close().catch(()=>{})});try{await c.connect(i),await i.handleRequest(n,s)}catch(a){process.stderr.write(`cachly-mcp HTTP: ${a.message}
381
381
  `),s.headersSent||(s.writeHead(500,{"Content-Type":"application/json"}),s.end(JSON.stringify({error:a.message})))}})();return}s.writeHead(404),s.end("not found")}).listen(we,()=>{process.stderr.write(`cachly-mcp HTTP server listening on :${we}
382
- `)})}else{const e=new Yt;W("start: Module geladen, stdio verbinden"),await G.connect(e),typeof process.argv[2]=="string"&&!process.argv[2].startsWith("-")||(Ue=!0,fn(),mn(process.stdin,n=>{process.stderr.write(`[cachly-mcp] ${n} \u2014 Session zu Ende, Server geht mit
383
- `),(async()=>{await Ie().catch(()=>{});for(const[,s]of ee)await s.quit().catch(()=>{});process.exit(0)})()}))}Be("cachly","startup",{version:D,mode:process.env.MCP_HTTP_PORT?"http":"stdio"}).catch(()=>{});export{_t as CLAUDE_MD_MARKER_END,Ee as CLAUDE_MD_MARKER_START,po as CROSS_LINGUAL_MAP,be as EDITOR_FILES,io as STOPWORDS,co as arabicLightStem,At as buildClaudeMdBlock,zn as buildMcpConfig,oe as buildServerEnv,lo as expandCrossLingual,ro as extractTimestamp,ao as katakanaToRomaji,no as levenshtein,Fn as mcpAddBefehl,St as mergeMcpConfig,so as recencyBoost,go as reconnectOnce,oo as splitMultiQuery,Zt as startBackgroundDevicePoll,to as tokenize,kt as writeInstructions};
382
+ `)})}else{const e=new Ut;W("start: Module geladen, stdio verbinden"),await G.connect(e),typeof process.argv[2]=="string"&&!process.argv[2].startsWith("-")||(Ue=!0,hn(),gn(process.stdin,n=>{process.stderr.write(`[cachly-mcp] ${n} \u2014 Session zu Ende, Server geht mit
383
+ `),(async()=>{await Ie().catch(()=>{});for(const[,s]of ee)await s.quit().catch(()=>{});process.exit(0)})()}))}Be("cachly","startup",{version:D,mode:process.env.MCP_HTTP_PORT?"http":"stdio"}).catch(()=>{});export{$t as CLAUDE_MD_MARKER_END,Ee as CLAUDE_MD_MARKER_START,uo as CROSS_LINGUAL_MAP,be as EDITOR_FILES,ao as STOPWORDS,lo as arabicLightStem,kt as buildClaudeMdBlock,qn as buildMcpConfig,oe as buildServerEnv,po as expandCrossLingual,io as extractTimestamp,co as katakanaToRomaji,so as levenshtein,zn as mcpAddBefehl,St as mergeMcpConfig,ro as recencyBoost,fo as reconnectOnce,no as splitMultiQuery,Qt as startBackgroundDevicePoll,oo as tokenize,Tt as writeInstructions};