@cachly-dev/mcp-server 0.10.227 → 0.10.229

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,58 +1,58 @@
1
1
  #!/usr/bin/env node
2
- import{setzeClientKennung as zt}from"./herkunft.js";import{jwtExpiryMs as Ut,checkJwt as Jt,handleApiError as Wt,diagnoseAuth as Te,planAuthHeal as Je,readClientCredentialsFromEnv as Ft,buildClientCredentialsBody as Yt,clientCredentialsTokenUrl as Kt}from"./auth.js";import{cachlyUrl as E}from"./cachly-url.js";import{nutzungsSchluessel as qt}from"./werkzeug-nutzung.js";import{istLieferung as Gt,lieferSchluessel as Vt,tokenDerAntwort as Zt,hatTreffer as Qt,trefferSchluessel as We}from"./geliefert.js";import{notify as Fe}from"./notifier.js";import{fileURLToPath as Ye}from"node:url";import{createRequire as Xt}from"node:module";import{execFile as Ie}from"node:child_process";const eo=process.argv[1]!=null&&(process.argv[1]===Ye(import.meta.url)||process.argv[1].endsWith("/dist/index.js")||process.argv[1].endsWith("/src/index.ts"));import{Server as Ke}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as to}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as oo}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{CallToolRequestSchema as qe,ErrorCode as se,ListPromptsRequestSchema as Ge,ListResourceTemplatesRequestSchema as Ve,ListResourcesRequestSchema as Ze,ListToolsRequestSchema as Qe,McpError as X}from"@modelcontextprotocol/sdk/types.js";import{Redis as Xe}from"ioredis";let v=process.env.CACHLY_API_URL??"https://api.cachly.dev",y=Ne()??"";ce(y);const qs=process.env.CACHLY_EMBED_MODEL??"",M=(()=>{try{const e=Xt(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"})(),no=Number(process.env.CACHLY_PROVISION_TIMEOUT_MS??9e4);let L=ke(process.env.CACHLY_BRAIN_INSTANCE_ID);function ee(){return y||Ne()||""}function J(){return ke(process.env.CACHLY_BRAIN_INSTANCE_ID)||$e()||""}let V=0,ue=null,et=!1;async function tt(){let e=[];try{q.getClientCapabilities()?.roots&&(e=(await q.listRoots(void 0,{timeout:3e3})).roots)}catch{}return Fn({wurzeln:e,env:process.env,cwd:process.cwd(),dateiPfad:Ye})}function ie(){return et?ht(process.env):!1}function Ee(e,t,n){!e||!ie()||zn({instanzId:e,vomHook:n,verbindung:H,ausGit:s=>Pe("brain_from_git",s,H,O),projektOrdner:t?async()=>t:tt,einbetten:s=>st(s,{geduld:"lang"}),hatEinbettung:yo,einbettenZweit:s=>st(s,{geduld:"lang",modell:bo}),melde:s=>$("brain_from_git",{...y?{api_key:y}:{},instance_id:e,total:s,auto:"startwissen"}),startvorrat:s=>He("brain_seed_starter",s,H,O),meldeStartvorrat:s=>$("brain_seed_starter",{...y?{api_key:y}:{},instance_id:e,auto:!0},{seeded_count:s,auto:!0})})}function Re(){return ie()&&Yn()}const so=7e3,io=12e3,ro=18e4;let we=null;function je(e){return we||(we=ao(e).finally(()=>{we=null})),we}async function ao(e){try{if(!y){const t=Date.now()+e;for(;!_e()&&Pn({})&&Date.now()<t;)await new Promise(o=>setTimeout(o,jn));const n=_e();if(!n)return!1;y=n,ce(n);const s=$e();s&&!L&&(L=s,V=0),await pe(n),s&&await me(s),$("instant_trial_started",{tool:"sessionstart-hook",...s?{instance_id:s}:{}})}if(ie()&&ft()){const t=Bn();t&&(Oe(t.instanzId,ie(),Re()),Ee(t.instanzId,t.projekt||void 0,t.vomHook))}}catch{}return!!y}function co(){if(!ht(process.env))return;const e=Date.now()+ro,t=setInterval(()=>{if(Date.now()>e){clearInterval(t);return}y&&!ft()||je(0)},500);t.unref(),je(0)}async function lo(){if(!y)return"";try{const e=await fetch(`${v}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${y}`,"Content-Type":"application/json"},signal:AbortSignal.timeout(12e3)});if(e.ok){const t=await e.json(),n=t.instance?.id??t.instance_id;if(n)return n}else fetch(`${v}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${y}`},body:JSON.stringify({event:"auto_provision_failed",status:e.status,version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}catch{fetch(`${v}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"auto_provision_failed",status:0,reason:"network_error",version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}return""}async function ot(){if(L)return L;if(!y)return"";if(ue)return ue;const e=Date.now();if(V>0&&e-V<3e4)return"";V=e,ue=(async()=>{try{const t=await fetch(`${v}/api/v1/instances`,{headers:{Authorization:`Bearer ${y}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(t.ok){const s=(await t.json())?.data??[],o=s.find(c=>c.status==="running")??s.find(c=>c.status==="provisioning");if(o)return L=o.id,V=0,L;const i=await lo();if(i)return L=i,V=0,Oe(i,ie(),Re()),me(i),Ee(i),L}}catch{}return""})();try{return await ue}finally{ue=null}}let Be=0;const uo=6e4;let re="";async function pe(e){try{const{writeFile:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),i=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!i)return;const c=[o(i,".claude","mcp.json"),o(i,".cursor","mcp.json"),o(i,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(c.map(async r=>{if(s(r))try{const u=await n(r,"utf-8"),m=JSON.parse(u),l=m?.mcpServers?.cachly;l?.env&&(l.env.CACHLY_JWT=e,await t(r,JSON.stringify(m,null,2),"utf-8"))}catch{}}))}catch{}}async function me(e){if(e){xe(e,{apiKey:y});try{const{writeFile:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),i=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!i)return;const c=[o(i,".claude","mcp.json"),o(i,".cursor","mcp.json"),o(i,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(c.map(async r=>{if(s(r))try{const u=JSON.parse(await n(r,"utf-8")),m=u?.mcpServers?.cachly;m?.env&&(m.env.CACHLY_BRAIN_INSTANCE_ID=e,await t(r,JSON.stringify(u,null,2),"utf-8"))}catch{}}))}catch{}}}async function po(){try{const e=await fetch(`${v}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${y}`},body:JSON.stringify({name:"cachly-mcp-selfheal",scope:"read_write"}),signal:AbortSignal.timeout(8e3)});if(!e.ok)return!1;const t=await e.json();return t.key?(y=t.key,ce(t.key),pe(t.key),$("auth_self_healed",{reason:"near_expiry_refresh"}),!0):!1}catch{return!1}}async function Le(){const e=Te(y),t=Je(e);if(t==="none")return re="",!0;if(t==="refresh"){const n=Date.now();return n-Be>=uo&&(Be=n,await po())?(re="",!0):(re=e.message,e.usable)}return re=e.message,!1}function ae(e,t){const n=(c,r)=>{try{t?.(c,r)}catch{}},s=c=>{c?n(!1,c.code??c.message):n(!0)},o=on(e);if(!o){n(!1,"keine-http-adresse");return}const i=nn(o);try{process.platform==="win32"?Ie("cmd",["/c","start","",i],{windowsHide:!0},s):process.platform==="darwin"?Ie("open",[o],s):Ie("xdg-open",[o],s)}catch(c){n(!1,c instanceof Error?c.message:"unknown")}}let K=null;async function mo(){try{const e=await fetch(`${v}/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||E("/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 go(e){if(Date.now()>e.deadline)return"expired";const t=async()=>{const s=await fetch(`${v}/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 i=await fetch(`${v}/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(i.ok){const c=await i.json();c.key&&(o=c.key)}}catch{}return y=o,ce(o),K=null,$("device_flow_completed"),pe(o),oe(o),V=0,await ot(),L&&me(L),"done"}return s.error==="slow_down"&&(e.pollInterval=Math.min(e.pollInterval+2e3,15e3)),"pending"}catch{return"pending"}}async function nt(e){if(e.polling)return"pending";e.polling=!0;try{return await go(e)}finally{e.polling=!1}}function fo(e,t=nt,n=o=>K===o,s=ho){const o=async()=>{if(!n(e))return;let i="pending";try{i=await t(e)}catch{}if(i!=="done"){if(i==="expired"){n(e)&&(K=null);return}n(e)&&s(o,e.pollInterval)}};s(o,e.pollInterval)}function ho(e,t){const n=setTimeout(e,t);typeof n.unref=="function"&&n.unref()}import{setEmbedJwt as ce,computeEmbedding as st,hasEmbedProvider as yo,EMBED_PROVIDER as it}from"./embeddings.js";import{ZWEIT_MODELL as bo}from"./rangfolge-stellschrauben.js";import{tokenize as wo,splitMultiQuery as vo,levenshtein as xo,recencyBoost as _o,extractTimestamp as $o,STOPWORDS as ko,katakanaToRomaji as So,arabicLightStem as Ao,expandCrossLingual as Co,CROSS_LINGUAL_MAP as To,ZERO_RESULTS_LOG as Io,zeroResultsTotal as Eo}from"./search.js";const te=new Map;function Ro(e){return e<=1?200:null}async function H(e){if(!e)throw new X(se.InvalidRequest,`\u23F3 Your Brain instance is still being set up.
2
+ import{setzeClientKennung as zt}from"./herkunft.js";import{jwtExpiryMs as Ut,checkJwt as Jt,handleApiError as Wt,diagnoseAuth as Te,planAuthHeal as Je,readClientCredentialsFromEnv as Ft,buildClientCredentialsBody as Yt,clientCredentialsTokenUrl as Kt}from"./auth.js";import{cachlyUrl as j}from"./cachly-url.js";import{nutzungsSchluessel as qt}from"./werkzeug-nutzung.js";import{istLieferung as Gt,lieferSchluessel as Vt,tokenDerAntwort as Zt,hatTreffer as Qt,trefferSchluessel as We}from"./geliefert.js";import{notify as Fe}from"./notifier.js";import{fileURLToPath as Ye}from"node:url";import{createRequire as Xt}from"node:module";import{execFile as Ie}from"node:child_process";const eo=process.argv[1]!=null&&(process.argv[1]===Ye(import.meta.url)||process.argv[1].endsWith("/dist/index.js")||process.argv[1].endsWith("/src/index.ts"));import{Server as Ke}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as to}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as oo}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{CallToolRequestSchema as qe,ErrorCode as se,ListPromptsRequestSchema as Ge,ListResourceTemplatesRequestSchema as Ve,ListResourcesRequestSchema as Ze,ListToolsRequestSchema as Qe,McpError as X}from"@modelcontextprotocol/sdk/types.js";import{Redis as Xe}from"ioredis";let _=process.env.CACHLY_API_URL??"https://api.cachly.dev",b=Ne()??"";ce(b);const Vs=process.env.CACHLY_EMBED_MODEL??"",M=(()=>{try{const e=Xt(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"})(),no=Number(process.env.CACHLY_PROVISION_TIMEOUT_MS??9e4);let L=ke(process.env.CACHLY_BRAIN_INSTANCE_ID);function ee(){return b||Ne()||""}function J(){return ke(process.env.CACHLY_BRAIN_INSTANCE_ID)||$e()||""}let V=0,pe=null,et=!1;async function tt(){let e=[];try{q.getClientCapabilities()?.roots&&(e=(await q.listRoots(void 0,{timeout:3e3})).roots)}catch{}return Yn({wurzeln:e,env:process.env,cwd:process.cwd(),dateiPfad:Ye})}function ie(){return et?ht(process.env):!1}function Ee(e,t,n){!e||!ie()||Un({instanzId:e,vomHook:n,verbindung:H,ausGit:s=>Pe("brain_from_git",s,H,O),projektOrdner:t?async()=>t:tt,einbetten:s=>st(s,{geduld:"lang"}),hatEinbettung:yo,einbettenZweit:s=>st(s,{geduld:"lang",modell:bo}),melde:s=>k("brain_from_git",{...b?{api_key:b}:{},instance_id:e,total:s,auto:"startwissen"}),startvorrat:s=>He("brain_seed_starter",s,H,O),meldeStartvorrat:s=>k("brain_seed_starter",{...b?{api_key:b}:{},instance_id:e,auto:!0},{seeded_count:s,auto:!0})})}function Re(){return ie()&&Kn()}const so=7e3,io=12e3,ro=18e4;let we=null;function je(e){return we||(we=ao(e).finally(()=>{we=null})),we}async function ao(e){try{if(!b){const t=Date.now()+e;for(;!_e()&&Nn({})&&Date.now()<t;)await new Promise(o=>setTimeout(o,Bn));const n=_e();if(!n)return!1;b=n,ce(n);const s=$e();s&&!L&&(L=s,V=0),await me(n),s&&await ge(s),k("instant_trial_started",{tool:"sessionstart-hook",...s?{instance_id:s}:{}})}if(ie()&&ft()){const t=Ln();t&&(Oe(t.instanzId,ie(),Re()),Ee(t.instanzId,t.projekt||void 0,t.vomHook))}}catch{}return!!b}function co(){if(!ht(process.env))return;const e=Date.now()+ro,t=setInterval(()=>{if(Date.now()>e){clearInterval(t);return}b&&!ft()||je(0)},500);t.unref(),je(0)}async function lo(){if(!b)return"";try{const e=await fetch(`${_}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${b}`,"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(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${b}`},body:JSON.stringify({event:"auto_provision_failed",status:e.status,version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}catch{fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"auto_provision_failed",status:0,reason:"network_error",version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}return""}async function ot(){if(L)return L;if(!b)return"";if(pe)return pe;const e=Date.now();if(V>0&&e-V<3e4)return"";V=e,pe=(async()=>{try{const t=await fetch(`${_}/api/v1/instances`,{headers:{Authorization:`Bearer ${b}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(t.ok){const s=(await t.json())?.data??[],o=s.find(c=>c.status==="running")??s.find(c=>c.status==="provisioning");if(o)return L=o.id,V=0,L;const i=await lo();if(i)return L=i,V=0,Oe(i,ie(),Re()),ge(i),Ee(i),L}}catch{}return""})();try{return await pe}finally{pe=null}}let Be=0;const uo=6e4;let re="";async function me(e){try{const{writeFile:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),i=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!i)return;const c=[o(i,".claude","mcp.json"),o(i,".cursor","mcp.json"),o(i,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(c.map(async a=>{if(s(a))try{const d=await n(a,"utf-8"),g=JSON.parse(d),l=g?.mcpServers?.cachly;l?.env&&(l.env.CACHLY_JWT=e,await t(a,JSON.stringify(g,null,2),"utf-8"))}catch{}}))}catch{}}async function ge(e){if(e){xe(e,{apiKey:b});try{const{writeFile:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),i=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!i)return;const c=[o(i,".claude","mcp.json"),o(i,".cursor","mcp.json"),o(i,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(c.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 po(){try{const e=await fetch(`${_}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${b}`},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?(b=t.key,ce(t.key),me(t.key),k("auth_self_healed",{reason:"near_expiry_refresh"}),!0):!1}catch{return!1}}async function Le(){const e=Te(b),t=Je(e);if(t==="none")return re="",!0;if(t==="refresh"){const n=Date.now();return n-Be>=uo&&(Be=n,await po())?(re="",!0):(re=e.message,e.usable)}return re=e.message,!1}function ae(e,t){const n=(c,a)=>{try{t?.(c,a)}catch{}},s=c=>{c?n(!1,c.code??c.message):n(!0)},o=nn(e);if(!o){n(!1,"keine-http-adresse");return}const i=sn(o);try{process.platform==="win32"?Ie("cmd",["/c","start","",i],{windowsHide:!0},s):process.platform==="darwin"?Ie("open",[o],s):Ie("xdg-open",[o],s)}catch(c){n(!1,c instanceof Error?c.message:"unknown")}}let K=null;async function mo(){try{const e=await fetch(`${_}/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||j("/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 go(e){if(Date.now()>e.deadline)return"expired";const t=async()=>{const s=await fetch(`${_}/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 i=await fetch(`${_}/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(i.ok){const c=await i.json();c.key&&(o=c.key)}}catch{}return b=o,ce(o),K=null,k("device_flow_completed"),me(o),oe(o),V=0,await ot(),L&&ge(L),"done"}return s.error==="slow_down"&&(e.pollInterval=Math.min(e.pollInterval+2e3,15e3)),"pending"}catch{return"pending"}}async function nt(e){if(e.polling)return"pending";e.polling=!0;try{return await go(e)}finally{e.polling=!1}}function fo(e,t=nt,n=o=>K===o,s=ho){const o=async()=>{if(!n(e))return;let i="pending";try{i=await t(e)}catch{}if(i!=="done"){if(i==="expired"){n(e)&&(K=null);return}n(e)&&s(o,e.pollInterval)}};s(o,e.pollInterval)}function ho(e,t){const n=setTimeout(e,t);typeof n.unref=="function"&&n.unref()}import{setEmbedJwt as ce,computeEmbedding as st,hasEmbedProvider as yo,EMBED_PROVIDER as it}from"./embeddings.js";import{ZWEIT_MODELL as bo}from"./rangfolge-stellschrauben.js";import{tokenize as wo,splitMultiQuery as vo,levenshtein as xo,recencyBoost as _o,extractTimestamp as $o,STOPWORDS as ko,katakanaToRomaji as So,arabicLightStem as Ao,expandCrossLingual as Co,CROSS_LINGUAL_MAP as To,ZERO_RESULTS_LOG as Io,zeroResultsTotal as Eo}from"./search.js";const te=new Map;function Ro(e){return e<=1?200:null}async function H(e){if(!e)throw new X(se.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=te.get(e);return t||Hn(jo,e,()=>Bo(e))}const jo=new Map;async function Bo(e){Y("verbindung: Instanz abfragen");let t=await O(`/api/v1/instances/${e}`);if(Y(`verbindung: Instanz ${t.status}`),t=await On(t,()=>O(`/api/v1/instances/${e}`),{fristMs:no,melde:r=>Y(`verbindung: Instanz ${r.status}`)}),t.status!=="running"){fetch(`${v}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...y?{Authorization:`Bearer ${y}`}:{}},body:JSON.stringify({event:"instance_not_reachable",instance_id:e,status:t.status,version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{});let r;throw t.status==="provisioning"?r=`\u23F3 Brain instance "${t.name}" is still starting up.
9
+ \u2022 Reach us at support@cachly.dev.`);const t=te.get(e);return t||Mn(jo,e,()=>Bo(e))}const jo=new Map;async function Bo(e){Y("verbindung: Instanz abfragen");let t=await O(`/api/v1/instances/${e}`);if(Y(`verbindung: Instanz ${t.status}`),t=await Hn(t,()=>O(`/api/v1/instances/${e}`),{fristMs:no,melde:a=>Y(`verbindung: Instanz ${a.status}`)}),t.status!=="running"){fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...b?{Authorization:`Bearer ${b}`}:{}},body:JSON.stringify({event:"instance_not_reachable",instance_id:e,status:t.status,version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{});let a;throw t.status==="provisioning"?a=`\u23F3 Brain instance "${t.name}" is still starting up.
10
10
 
11
- First-time provisioning typically takes 1\u20133 minutes. Please retry in a moment \u2014 the instance will be ready soon.`:t.status==="failed"?r=`\u274C Brain instance "${t.name}" failed to start.
11
+ First-time provisioning typically takes 1\u20133 minutes. Please retry in a moment \u2014 the instance will be ready soon.`:t.status==="failed"?a=`\u274C Brain instance "${t.name}" failed to start.
12
12
 
13
- Our system will retry automatically. Check status at: ${E("/instances","instance-error")}
14
- If this persists, contact support@cachly.dev.`:t.status==="suspended"?r=`\u23F8 Brain instance "${t.name}" is suspended (billing issue).
13
+ Our system will retry automatically. Check status at: ${j("/instances","instance-error")}
14
+ If this persists, contact support@cachly.dev.`:t.status==="suspended"?a=`\u23F8 Brain instance "${t.name}" is suspended (billing issue).
15
15
 
16
- Update your payment method at: ${E("/billing","upgrade")}`:t.status==="pending_payment"?r=`\u{1F4B3} Brain instance "${t.name}" is waiting for payment.
16
+ Update your payment method at: ${j("/billing","upgrade")}`:t.status==="pending_payment"?a=`\u{1F4B3} Brain instance "${t.name}" is waiting for payment.
17
17
 
18
- Complete your checkout at: ${E("/instances","upgrade")}`:r=`Brain instance "${t.name}" is not reachable (status: ${t.status}).
18
+ Complete your checkout at: ${j("/instances","upgrade")}`:a=`Brain instance "${t.name}" is not reachable (status: ${t.status}).
19
19
 
20
- \u2022 View your instance at: ${E("/instances","instance-error")}
21
- \u2022 Run \`get_api_status\` for a full diagnostic.`,new X(se.InvalidRequest,r)}if(!t.host||!t.port)throw new X(se.InternalError,`Instance "${t.name}" is running but has no host/port \u2014 contact support@cachly.dev.`);let n,s;try{const r=await O(`/api/v1/instances/${e}/connection`);n=r.password??void 0,s=r,Y("verbindung: Zugangsdaten da")}catch(r){const u=r instanceof Error?r.message:String(r);if(u.includes("401")||u.includes("403")||u.includes("Unauthorized"))throw new X(se.InvalidRequest,"API key rejected \u2014 run `cachly setup` to refresh your credentials.")}const o=vt({host:t.host,port:t.port,tls_enabled:t.tls_enabled},s),i=new Xe({host:o.host,port:o.port,password:n||void 0,commandTimeout:8e3,...o.tls?{tls:o.tls}:{},lazyConnect:!0,enableReadyCheck:!0,connectTimeout:8e3,retryStrategy:Ro,maxRetriesPerRequest:1,keepAlive:15e3}),c=()=>{te.delete(e),i.disconnect()};i.on("error",c),i.on("end",c);try{await i.connect()}catch(r){i.disconnect();const u=r instanceof Error?r.message:String(r);throw fetch(`${v}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...y?{Authorization:`Bearer ${y}`}:{}},body:JSON.stringify({event:"redis_connect_failed",instance_id:e,host:t.host,port:t.port,error:u,version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{}),new X(se.InternalError,`Could not reach Brain instance "${t.name}" (${t.host}:${t.port}).
20
+ \u2022 View your instance at: ${j("/instances","instance-error")}
21
+ \u2022 Run \`get_api_status\` for a full diagnostic.`,new X(se.InvalidRequest,a)}if(!t.host||!t.port)throw new X(se.InternalError,`Instance "${t.name}" is running but has no host/port \u2014 contact support@cachly.dev.`);let n,s;try{const a=await O(`/api/v1/instances/${e}/connection`);n=a.password??void 0,s=a,Y("verbindung: Zugangsdaten da")}catch(a){const d=a instanceof Error?a.message:String(a);if(d.includes("401")||d.includes("403")||d.includes("Unauthorized"))throw new X(se.InvalidRequest,"API key rejected \u2014 run `cachly setup` to refresh your credentials.")}const o=vt({host:t.host,port:t.port,tls_enabled:t.tls_enabled},s),i=new Xe({host:o.host,port:o.port,password:n||void 0,commandTimeout:8e3,...o.tls?{tls:o.tls}:{},lazyConnect:!0,enableReadyCheck:!0,connectTimeout:8e3,retryStrategy:Ro,maxRetriesPerRequest:1,keepAlive:15e3}),c=()=>{te.delete(e),i.disconnect()};i.on("error",c),i.on("end",c);try{await i.connect()}catch(a){i.disconnect();const d=a instanceof Error?a.message:String(a);throw fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...b?{Authorization:`Bearer ${b}`}:{}},body:JSON.stringify({event:"redis_connect_failed",instance_id:e,host:t.host,port:t.port,error:d,version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{}),new X(se.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: ${u}`)}return te.set(e,i),Y("verbindung: Valkey verbunden"),i}async function O(e,t={},n=!1){n||Je(Te(y))!=="none"&&await Le(),Jt(y);const s=Number(process.env.CACHLY_API_TIMEOUT_MS??15e3),o=await fetch(`${v}${e}`,{...t,signal:AbortSignal.timeout(s),headers:{"Content-Type":"application/json",Authorization:`Bearer ${y}`,...t.headers}});if(!o.ok){if(o.status===401&&!n&&(Be=0,await Le()))return O(e,t,!0);const c=(await o.json().catch(()=>({error:o.statusText}))).error??o.statusText;Wt(o.status,c)}if(o.status!==204)return o.json()}import{handleBrainTool as Lo}from"./handlers/brain.js";import{handleContextTool as Po}from"./handlers/context.js";import{handleInstanceTool as No}from"./handlers/instances.js";import{handleCacheTool as Oo}from"./handlers/cache.js";import{handleTeamTool as Ho}from"./handlers/team.js";import{handleRoadmapTool as Mo}from"./handlers/roadmap.js";import{handleAdvancedTool as Do}from"./handlers/advanced.js";import{handleSyndicateTool as zo}from"./handlers/syndicate.js";import{handleFedbrainTool as Pe,_lastBrainFromGitCounts as ve}from"./handlers/fedbrain.js";import{extractFirstRecallProof as Uo,extractTopHit as Jo,fuersTerminal as rt,renderFirstRecallProof as Wo}from"./first-recall-proof.js";import{aussetzerLeise as Fo}from"./aussetzer.js";import{installClsPostCommitHook as at,CLS_HOOK_VERSION as ct}from"./cls-hook.js";import{CLAUDE_MD_MARKER_START as Yo,CLAUDE_MD_MARKER_END as Ko,EDITOR_FILES as le,ANWEISUNGS_DATEIEN as qo,buildClaudeMdBlock as lt,setzeAnweisungsblock as Go,sollSchreiben as Vo}from"./projektdateien.js";import{klassiereArgument as Zo,leseFlag as Qo,flagsOhneWert as Xo,pruefeInitEingaben as en}from"./cli-argumente.js";import{uninstallBefehl as tn}from"./uninstall.js";import{gitLesen as dt}from"./git-ohne-shell.js";import{browserAdresse as on,fuerCmd as nn}from"./browser-adresse.js";import{installAmbientHooks as ut,installCursorHooks as sn,installCopilotHooks as rn,installCodexHooks as an,installGeminiHooks as cn,AMBIENT_HOOK_VERSION as pt,COPILOT_HOOKS_DATEI as ln,CODEX_HOOKS_DATEI as dn,GEMINI_SETTINGS_DATEI as un}from"./ambient-hooks.js";import{hookHauptlauf as pn,auffrischenHauptlauf as mn,startwissenImportHauptlauf as gn}from"./ambient-hook.js";import{STARTWISSEN_IMPORT as fn}from"./startwissen-hook.js";import{rahmeAntwort as hn}from"./antwort-rahmen.js";import{appendLedgerEntry as yn,readLedger as mt,defaultLedgerPath as bn,reportLedgerEntry as wn,teileNachInstanz as vn}from"./ambient-ledger.js";import{installCodexMcp as xn,installGeminiMcp as _n}from"./editor-mcp-eintrag.js";import{resolveApiKey as Ne,saveApiKey as oe,saveInstanceId as xe,readSavedApiKey as _e,readInstanceId as $e}from"./credentials.js";import{KEYCLOAK_BASIS as gt,istTestSchluessel as $n,waehleTestSchluessel as kn,starteKeycloakAnmeldung as Sn,warteAufKeycloakAnmeldung as An,uebernimm as Cn,brainImKonto as Tn,erfolgsText as In,fehlerText as En,ersetzeSchluessel as Rn}from"./uebernahme.js";import{WARTE_TAKT_MS as jn,auftragLiegt as ft,nimmAuftrag as Bn,sichereKonto as Ln,sperreLiegt as Pn,startwissenEingeschaltet as ht}from"./konto-anlegen.js";import{sichereZugang as Nn,echterWert as ke}from"./zugang.js";import{zeitpunkt as Y}from"./zeitmessung.js";import{warteAufLaufendeInstanz as On,gemeinsamerAufbau as Hn}from"./instanz-warten.js";import{merkeNeuesBrain as Oe,startetLautLetztemBlick as Mn,setzeCommitQuelle as Dn}from"./leeres-brain.js";import{starteStartwissen as zn,startwissenGestartet as Un,beanspruchStartwissen as Jn,holeStartwissenHinweis as Wn,waehleProjektOrdner as Fn,startvorratErlaubt as Yn,projektCommits as Kn}from"./startwissen.js";import{eigeneFassung as qn,pruefeNeueFassung as Gn,holeNeueFassungHinweis as Vn}from"./neue-fassung.js";import{beiStdinEnde as Zn}from"./stdin-ende.js";import{merkeWerkzeugAufruf as Qn,starteBrandWachhund as Xn}from"./brand-wachhund.js";import{sichtbareWerkzeuge as es,VERTEILER as yt}from"./werkzeug-auswahl.js";import{buildLessonsMarkdown as ts,buildLessonsJsonl as os,vonRohLektion as ns}from"./brain-export.js";import{detectEditor as ss}from"./editor.js";import{milestoneSent as bt,markMilestoneSent as wt}from"./funnel-milestones.js";import{kostprobeUebrig as is,kostprobeVerbrauchen as rs,kostprobeHinweis as as,schrankeNachKostproben as cs}from"./kostprobe.js";import{netBalance as ls}from"./ambient-recall.js";import{handleShareTool as He}from"./handlers/share.js";import{handleVizTool as ds}from"./handlers/viz.js";import{commitArt as us,istRueckbau as ps,zaehleLektionen as ms}from"./commit-art.js";import{TOOLS as ge}from"./tools.js";import{verbindungsWeg as vt}from"./brains-tls.js";let xt=!1,_t=!1,Se=!1;function $t(){return ss()}function gs(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 $(e,t,n){if(process.env.CACHLY_NO_TELEMETRY==="1")return;const s=y?gs(y):void 0;fetch(`${v}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:e,version:M,editor:$t(),...y?{jwt:y}:{},...s?{user_fingerprint:s}:{},...n?{metrics:n}:{},...t}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}function fs(e,t){return wn({apiUrl:v,jwt:y,instanceId:e},t)}async function hs(e){if(!xt&&process.env.CACHLY_NO_TELEMETRY!=="1"){xt=!0;try{await fetch(`${v}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"first_call_no_jwt",version:M,editor:$t(),tool:e}),signal:AbortSignal.timeout(3e3)})}catch{}}}const ys=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"]),bs={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."},kt=E("/billing","upgrade"),St=new Map;async function ws(e){const t=St.get(e);if(t&&t.expiresAt>Date.now())return t.info;try{const s=((await O(`/api/v1/instances/${e}`))?.tier??"free").toLowerCase(),o={tier:s,isFree:s==="free"||s===""};return St.set(e,{info:o,expiresAt:Date.now()+6e4}),o}catch{return{tier:"unknown",isFree:!1}}}async function vs(e,t){if(!ys.has(e)||!t)return null;const{isFree:n}=await ws(t);if(!n)return null;const s=bs[e]??"A Premium intelligence feature.";if(is(e)){const o=rs(e);return{kostprobe:as(e,o,kt)}}return{sperre:cs(e,s,kt)}}async function xs(e,t){try{await(await H(e)).hincrby(qt(e),t,1)}catch{}}async function _s(e,t,n){if(Gt(t))try{const s=await H(e),o=Qt(n);await s.incrby(Vt(e),o?Zt(n):0),await s.hincrby(We(e),"abrufe",1),o&&await s.hincrby(We(e),"treffer",1)}catch{}}async function $s(e){const t=await mo();return t?(K=t,$("device_flow_started",{tool:e}),ae(t.verifyUrl,(n,s)=>{if(n){$("device_browser_opened",{stelle:"tool"});return}$("device_browser_failed",{reason:s??"unknown",stelle:"tool"}),process.stderr.write(`
25
+ \u2022 Technical detail: ${d}`)}return te.set(e,i),Y("verbindung: Valkey verbunden"),i}async function O(e,t={},n=!1){n||Je(Te(b))!=="none"&&await Le(),Jt(b);const s=Number(process.env.CACHLY_API_TIMEOUT_MS??15e3),o=await fetch(`${_}${e}`,{...t,signal:AbortSignal.timeout(s),headers:{"Content-Type":"application/json",Authorization:`Bearer ${b}`,...t.headers}});if(!o.ok){if(o.status===401&&!n&&(Be=0,await Le()))return O(e,t,!0);const c=(await o.json().catch(()=>({error:o.statusText}))).error??o.statusText;Wt(o.status,c)}if(o.status!==204)return o.json()}import{handleBrainTool as Lo}from"./handlers/brain.js";import{handleContextTool as Po}from"./handlers/context.js";import{handleInstanceTool as No}from"./handlers/instances.js";import{handleCacheTool as Oo}from"./handlers/cache.js";import{handleTeamTool as Ho}from"./handlers/team.js";import{handleRoadmapTool as Mo}from"./handlers/roadmap.js";import{handleAdvancedTool as Do}from"./handlers/advanced.js";import{handleSyndicateTool as zo}from"./handlers/syndicate.js";import{handleFedbrainTool as Pe,_lastBrainFromGitCounts as ve}from"./handlers/fedbrain.js";import{extractFirstRecallProof as Uo,extractTopHit as Jo,fuersTerminal as rt,renderFirstRecallProof as Wo}from"./first-recall-proof.js";import{aussetzerLeise as Fo}from"./aussetzer.js";import{gitHookOrdner as Yo,installClsPostCommitHook as at,CLS_HOOK_VERSION as ct}from"./cls-hook.js";import{CLAUDE_MD_MARKER_START as Ko,CLAUDE_MD_MARKER_END as qo,EDITOR_FILES as le,ANWEISUNGS_DATEIEN as Go,buildClaudeMdBlock as lt,setzeAnweisungsblock as Vo,sollSchreiben as Zo}from"./projektdateien.js";import{klassiereArgument as Qo,leseFlag as Xo,flagsOhneWert as en,pruefeInitEingaben as tn}from"./cli-argumente.js";import{uninstallBefehl as on}from"./uninstall.js";import{gitLesen as dt}from"./git-ohne-shell.js";import{browserAdresse as nn,fuerCmd as sn}from"./browser-adresse.js";import{installAmbientHooks as ut,installCursorHooks as rn,installCopilotHooks as an,installCodexHooks as cn,installGeminiHooks as ln,AMBIENT_HOOK_VERSION as pt,COPILOT_HOOKS_DATEI as dn,CODEX_HOOKS_DATEI as un,GEMINI_SETTINGS_DATEI as pn}from"./ambient-hooks.js";import{hookHauptlauf as mn,auffrischenHauptlauf as gn,startwissenImportHauptlauf as fn}from"./ambient-hook.js";import{STARTWISSEN_IMPORT as hn}from"./startwissen-hook.js";import{rahmeAntwort as yn}from"./antwort-rahmen.js";import{appendLedgerEntry as bn,readLedger as mt,defaultLedgerPath as wn,reportLedgerEntry as vn,teileNachInstanz as xn}from"./ambient-ledger.js";import{installCodexMcp as _n,installGeminiMcp as $n}from"./editor-mcp-eintrag.js";import{resolveApiKey as Ne,saveApiKey as oe,saveInstanceId as xe,readSavedApiKey as _e,readInstanceId as $e}from"./credentials.js";import{KEYCLOAK_BASIS as gt,istTestSchluessel as kn,waehleTestSchluessel as Sn,starteKeycloakAnmeldung as An,warteAufKeycloakAnmeldung as Cn,uebernimm as Tn,brainImKonto as In,erfolgsText as En,fehlerText as Rn,ersetzeSchluessel as jn}from"./uebernahme.js";import{WARTE_TAKT_MS as Bn,auftragLiegt as ft,nimmAuftrag as Ln,sichereKonto as Pn,sperreLiegt as Nn,startwissenEingeschaltet as ht}from"./konto-anlegen.js";import{sichereZugang as On,echterWert as ke}from"./zugang.js";import{zeitpunkt as Y}from"./zeitmessung.js";import{warteAufLaufendeInstanz as Hn,gemeinsamerAufbau as Mn}from"./instanz-warten.js";import{merkeNeuesBrain as Oe,startetLautLetztemBlick as Dn,setzeCommitQuelle as zn}from"./leeres-brain.js";import{starteStartwissen as Un,startwissenGestartet as Jn,beanspruchStartwissen as Wn,holeStartwissenHinweis as Fn,waehleProjektOrdner as Yn,startvorratErlaubt as Kn,projektCommits as qn}from"./startwissen.js";import{eigeneFassung as Gn,pruefeNeueFassung as Vn,holeNeueFassungHinweis as Zn}from"./neue-fassung.js";import{beiStdinEnde as Qn}from"./stdin-ende.js";import{merkeWerkzeugAufruf as Xn,starteBrandWachhund as es}from"./brand-wachhund.js";import{sichtbareWerkzeuge as ts,VERTEILER as yt}from"./werkzeug-auswahl.js";import{fehlendePflichtfelder as os}from"./pflichtfelder.js";import{buildLessonsMarkdown as ns,buildLessonsJsonl as ss,vonRohLektion as is}from"./brain-export.js";import{detectEditor as rs}from"./editor.js";import{milestoneSent as bt,markMilestoneSent as wt}from"./funnel-milestones.js";import{kostprobeUebrig as as,kostprobeVerbrauchen as cs,kostprobeHinweis as ls,schrankeNachKostproben as ds}from"./kostprobe.js";import{netBalance as us}from"./ambient-recall.js";import{handleShareTool as He}from"./handlers/share.js";import{handleVizTool as ps}from"./handlers/viz.js";import{commitArt as ms,istRueckbau as gs,zaehleLektionen as fs}from"./commit-art.js";import{TOOLS as de}from"./tools.js";import{verbindungsWeg as vt}from"./brains-tls.js";let xt=!1,_t=!1,Se=!1;function $t(){return rs()}function hs(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 k(e,t,n){if(process.env.CACHLY_NO_TELEMETRY==="1")return;const s=b?hs(b):void 0;fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:e,version:M,editor:$t(),...b?{jwt:b}:{},...s?{user_fingerprint:s}:{},...n?{metrics:n}:{},...t}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}function ys(e,t){return vn({apiUrl:_,jwt:b,instanceId:e},t)}async function bs(e){if(!xt&&process.env.CACHLY_NO_TELEMETRY!=="1"){xt=!0;try{await fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"first_call_no_jwt",version:M,editor:$t(),tool:e}),signal:AbortSignal.timeout(3e3)})}catch{}}}const ws=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"]),vs={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."},kt=j("/billing","upgrade"),St=new Map;async function xs(e){const t=St.get(e);if(t&&t.expiresAt>Date.now())return t.info;try{const s=((await O(`/api/v1/instances/${e}`))?.tier??"free").toLowerCase(),o={tier:s,isFree:s==="free"||s===""};return St.set(e,{info:o,expiresAt:Date.now()+6e4}),o}catch{return{tier:"unknown",isFree:!1}}}async function _s(e,t){if(!ws.has(e)||!t)return null;const{isFree:n}=await xs(t);if(!n)return null;const s=vs[e]??"A Premium intelligence feature.";if(as(e)){const o=cs(e);return{kostprobe:ls(e,o,kt)}}return{sperre:ds(e,s,kt)}}async function $s(e,t){try{await(await H(e)).hincrby(qt(e),t,1)}catch{}}async function ks(e,t,n){if(Gt(t))try{const s=await H(e),o=Qt(n);await s.incrby(Vt(e),o?Zt(n):0),await s.hincrby(We(e),"abrufe",1),o&&await s.hincrby(We(e),"treffer",1)}catch{}}async function Ss(e){const t=await mo();return t?(K=t,k("device_flow_started",{tool:e}),ae(t.verifyUrl,(n,s)=>{if(n){k("device_browser_opened",{stelle:"tool"});return}k("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
- `)}),fo(t),["\u{1F9E0} **cachly AI Brain \u2014 the user must sign in once.**","","**Show the following link and code to the user verbatim \u2014 they cannot","continue without them.**","",`\u{1F449} **${t.verifyUrl}**`,"",`Code: **${t.userCode}**`,"","A browser may have opened automatically with the code pre-filled. If it","did not, the link above is the whole step.","","Once signed in, the Brain activates on its own \u2014 no further action, no","restart. The next request arrives brain-powered.","",`\u2728 ${ge.length} MCP tools \xB7 GDPR \xB7 EU servers \xB7 free tier, no credit card`].join(`
32
- `)):["\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: ${E("/setup-ai","ambient-signin")}`,"","\u2728 Free tier includes: 1 Brain instance, persistent memory, semantic search."].join(`
33
- `)}async function ks(e){if(!e)return!0;if(Un(e))return!1;try{return await Jn(await H(e),"sitzungsstart")}catch{return!0}}async function W(e,t){if(!y&&await je(so))return W(e,t);if(!y){if(hs(e),K){const a=await nt(K);return a==="done"?W(e,t):a==="expired"?($("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 Nn({schluessel:y,konfigurierteInstanz:L,aufrufInstanz:t.instance_id,werkzeugName:e,holeSofortTest:async()=>{Y("sofort-test: Anfang");const a=await Ln({apiUrl:v,version:M,fristMs:io}),g=a.art==="angelegt"?a.test:a.art==="vorhanden"&&a.instanzId?{apiKey:a.apiKey,instanzId:a.instanzId}:null;return Y(`sofort-test: ${g?"Brain angelegt":"kein Test"}`),g&&Oe(g.instanzId,ie(),Re()),g},ablagen:{setzeSchluessel:a=>{y=a},setEmbedJwt:ce,saveApiKey:a=>oe(a),persistApiKeyToConfig:pe,merkeInstanz:a=>{L=a,V=0},persistInstanceIdToConfig:me},meldeEreignis:$,werkzeug:()=>W(e,t),anmelden:()=>$s(e),neuesBrain:Ee})}if(!t.instance_id){const a=await ot();a&&(t={...t,instance_id:a})}const n=await vs(e,t.instance_id);let s="";if(n!==null){if("sperre"in n)return $("premium_gate_hit",{tool:e,instance_id:t.instance_id??""}),n.sperre;s=n.kostprobe,$("premium_taste_used",{tool:e,instance_id:t.instance_id??""})}typeof t.instance_id=="string"&&t.instance_id&&xs(t.instance_id,e),Y(`werkzeug ${e}: Zugang und Tarif geklaert`);const o=await Lo(e,t,H,O);if(Y(`werkzeug ${e}: Brain-Werkzeug fertig`),o!==null){typeof t.instance_id=="string"&&t.instance_id&&_s(t.instance_id,e,String(o??"")),!Se&&y&&(Se=!0,bt("first_call_success")||(wt("first_call_success"),$("first_call_success",{tool:e,instance_id:t.instance_id??L??""})));const a=t.instance_id??L??"",g=y?{api_key:y,instance_id:a}:{instance_id:a};if(e==="recall_best_solution")$("recall_best_solution",g);else if(e==="learn_from_attempts")$("learn_from_attempts",g);else if(e==="session_start"){$("session_start",g,{born_at:void 0,recalls_total:void 0,starter_seeded:!1});const d=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),S=d.includes("Welcome! Your AI Brain is live.");if(!Mn(a)){if(!S&&d.length>100)$("recall_best_solution",g);else if(S&&t.workspace_path&&await ks(a))try{const I=await Pe("brain_from_git",{instance_id:a,repo_path:t.workspace_path,limit:50},H,O);if(I!==null){$("brain_from_git",{...g,...ve??{}}),$("recall_best_solution",g);let T="";if((ve?.total??0)===0)try{const P=await He("brain_seed_starter",{instance_id:a},H,O);P&&($("brain_seed_starter",{...g,auto:!0},{seeded_count:16,auto:!0}),T=`
31
+ `)}),fo(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 ${de.length} MCP tools \xB7 GDPR \xB7 EU servers \xB7 free tier, no credit card`].join(`
32
+ `)):["\u{1F9E0} **cachly AI Brain \u2014 Setup required**","","Run the setup wizard once in your terminal:"," ```"," npx @cachly-dev/mcp-server@latest autopilot"," ```","",`Or get your API key at: ${j("/setup-ai","ambient-signin")}`,"","\u2728 Free tier includes: 1 Brain instance, persistent memory, semantic search."].join(`
33
+ `)}async function As(e){if(!e)return!0;if(Jn(e))return!1;try{return await Wn(await H(e),"sitzungsstart")}catch{return!0}}async function W(e,t){if(!b&&await je(so))return W(e,t);if(!b){if(bs(e),K){const r=await nt(K);return r==="done"?W(e,t):r==="expired"?(k("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 On({schluessel:b,konfigurierteInstanz:L,aufrufInstanz:t.instance_id,werkzeugName:e,holeSofortTest:async()=>{Y("sofort-test: Anfang");const r=await Pn({apiUrl:_,version:M,fristMs:io}),p=r.art==="angelegt"?r.test:r.art==="vorhanden"&&r.instanzId?{apiKey:r.apiKey,instanzId:r.instanzId}:null;return Y(`sofort-test: ${p?"Brain angelegt":"kein Test"}`),p&&Oe(p.instanzId,ie(),Re()),p},ablagen:{setzeSchluessel:r=>{b=r},setEmbedJwt:ce,saveApiKey:r=>oe(r),persistApiKeyToConfig:me,merkeInstanz:r=>{L=r,V=0},persistInstanceIdToConfig:ge},meldeEreignis:k,werkzeug:()=>W(e,t),anmelden:()=>Ss(e),neuesBrain:Ee})}if(!t.instance_id){const r=await ot();r&&(t={...t,instance_id:r})}const n=await _s(e,t.instance_id);let s="";if(n!==null){if("sperre"in n)return k("premium_gate_hit",{tool:e,instance_id:t.instance_id??""}),n.sperre;s=n.kostprobe,k("premium_taste_used",{tool:e,instance_id:t.instance_id??""})}typeof t.instance_id=="string"&&t.instance_id&&$s(t.instance_id,e),Y(`werkzeug ${e}: Zugang und Tarif geklaert`);const o=await Lo(e,t,H,O);if(Y(`werkzeug ${e}: Brain-Werkzeug fertig`),o!==null){typeof t.instance_id=="string"&&t.instance_id&&ks(t.instance_id,e,String(o??"")),!Se&&b&&(Se=!0,bt("first_call_success")||(wt("first_call_success"),k("first_call_success",{tool:e,instance_id:t.instance_id??L??""})));const r=t.instance_id??L??"",p=b?{api_key:b,instance_id:r}:{instance_id:r};if(e==="recall_best_solution")k("recall_best_solution",p);else if(e==="learn_from_attempts")k("learn_from_attempts",p);else if(e==="session_start"){k("session_start",p,{born_at:void 0,recalls_total:void 0,starter_seeded:!1});const v=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),w=v.includes("Welcome! Your AI Brain is live.");if(!Dn(r)){if(!w&&v.length>100)k("recall_best_solution",p);else if(w&&t.workspace_path&&await As(r))try{const E=await Pe("brain_from_git",{instance_id:r,repo_path:t.workspace_path,limit:50},H,O);if(E!==null){k("brain_from_git",{...p,...ve??{}}),k("recall_best_solution",p);let I="";if((ve?.total??0)===0)try{const P=await He("brain_seed_starter",{instance_id:r},H,O);P&&(k("brain_seed_starter",{...p,auto:!0},{seeded_count:16,auto:!0}),I=`
35
35
  ---
36
- `+String(P))}catch{}const R=String(I),_=ve?.total??0,k=_>0?`
37
- \u2705 **Brain bootstrapped from git \u2014 ${_} lesson${_===1?"":"s"} loaded.** Your AI already knows your history.`:"";if(R||T||k)return String(o)+k+`
36
+ `+String(P))}catch{}const R=String(E),$=ve?.total??0,S=$>0?`
37
+ \u2705 **Brain bootstrapped from git \u2014 ${$} lesson${$===1?"":"s"} loaded.** Your AI already knows your history.`:"";if(R||I||S)return String(o)+S+`
38
38
  ---
39
- `+R+T}}catch(I){return $("brain_from_git_failed",{...g,reason:I instanceof Error?I.message.slice(0,120):"unknown"}),String(o)+`
39
+ `+R+I}}catch(E){return k("brain_from_git_failed",{...p,reason:E instanceof Error?E.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="`+a+'", 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")$("session_end",g);else if(e==="smart_recall"){const d=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),S=d.length>50&&!d.includes("No lessons found")&&!d.includes("no lessons")&&!d.includes("No matches found");if($("smart_recall",g,{hit:S,topic:String(t.query??"").slice(0,80)}),S&&$("recall_best_solution",g),re&&typeof o=="string")return`> \u26A0\uFE0F **Brain auth degraded** \u2014 ${re.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")k("session_end",p);else if(e==="smart_recall"){const v=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),w=v.length>50&&!v.includes("No lessons found")&&!v.includes("no lessons")&&!v.includes("No matches found");if(k("smart_recall",p,{hit:w,topic:String(t.query??"").slice(0,80)}),w&&k("recall_best_solution",p),re&&typeof o=="string")return`> \u26A0\uFE0F **Brain auth degraded** \u2014 ${re.split(`
43
43
  `)[0]}
44
44
 
45
- ${o}`}return o}const i=await Po(e,t,H,O);if(i!==null)return!Se&&y&&(Se=!0,bt("first_call_success")||(wt("first_call_success"),$("first_call_success",{tool:e,instance_id:t.instance_id??L??""}))),i;const c=await No(e,t,H,O);if(c!==null)return c;const r=await Oo(e,t,H,O);if(r!==null)return r;const u=a=>s?a+s:a,m=await Ho(e,t,H,O);if(m!==null)return u(m);const l=await Mo(e,t,H,O);if(l!==null)return l;const p=await Do(e,t,H,O);if(p!==null)return u(p);const x=await zo(e,t,H,O);if(x!==null){if(e==="brain_predict"){const a=t.instance_id??L??"";$("brain_predict",y?{api_key:y,instance_id:a}:{instance_id:a})}return u(x)}const b=await He(e,t,H,O);if(b!==null)return b;const w=await ds(e,t,H,O);if(w!==null)return w;const f=await Pe(e,t,H,O);if(f!==null){const a=t.instance_id??L??"",g=y?{api_key:y,instance_id:a}:{instance_id:a};if(e==="brain_from_git"){const d=ve;$("brain_from_git",{...g,...d??{}},d?{fixes:d.fixes,features:d.features,refactors:d.refactors,total:d.total}:void 0)}else e==="brain_predict_failures"&&$("brain_predict_failures",g);return f}switch(e){case"get_api_status":{let a="unknown";try{const I=await fetch(`${v}/health`,{signal:AbortSignal.timeout(8e3)});if(I.ok){const C=await I.json();a=`${C.status??"ok"} (db: ${C.db??"?"})`}else a=`HTTP ${I.status}`}catch(I){a=`unreachable: ${I.message}`}if(!y)return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${v}`,` \u{1F493} Health: ${a}`," \u{1F511} Auth: \u274C CACHLY_JWT not set","",`\u{1F4A1} Get your API token at ${E("/instances","api-status")} \u2192 Settings \u2192 API Token`].join(`
46
- `);let g="\u274C invalid JWT format";try{const I=y.split(".");if(I.length===3){const C=JSON.parse(Buffer.from(I[1],"base64url").toString("utf-8")),T=C.sub??"(unknown)",R=C.iss??"(unknown)",_=R.includes("keycloak")?"Keycloak":"OIDC",k=C.exp?new Date(C.exp*1e3):null,P=k?k<new Date:!1;g=["\u2705 JWT decoded",` Sub (user ID): ${T}`,` Provider: ${_}`,` Issuer: ${R}`,` Expires: ${k?k.toISOString():"never"} ${P?"\u26A0\uFE0F EXPIRED \u2013 get a new token!":"\u2705"}`].join(`
47
- `)}}catch{g="\u274C JWT decode failed \u2013 check CACHLY_JWT format"}let d="";try{const C=(await O("/api/v1/instances")).data??[];if(C.length===0)d=`
45
+ ${o}`}return o}const i=await Po(e,t,H,O);if(i!==null)return!Se&&b&&(Se=!0,bt("first_call_success")||(wt("first_call_success"),k("first_call_success",{tool:e,instance_id:t.instance_id??L??""}))),i;const c=await No(e,t,H,O);if(c!==null)return c;const a=await Oo(e,t,H,O);if(a!==null)return a;const d=r=>s?r+s:r,g=await Ho(e,t,H,O);if(g!==null)return d(g);const l=await Mo(e,t,H,O);if(l!==null)return l;const u=await Do(e,t,H,O);if(u!==null)return d(u);const h=await zo(e,t,H,O);if(h!==null){if(e==="brain_predict"){const r=t.instance_id??L??"";k("brain_predict",b?{api_key:b,instance_id:r}:{instance_id:r})}return d(h)}const y=await He(e,t,H,O);if(y!==null)return y;const x=await ps(e,t,H,O);if(x!==null)return x;const m=await Pe(e,t,H,O);if(m!==null){const r=t.instance_id??L??"",p=b?{api_key:b,instance_id:r}:{instance_id:r};if(e==="brain_from_git"){const v=ve;k("brain_from_git",{...p,...v??{}},v?{fixes:v.fixes,features:v.features,refactors:v.refactors,total:v.total}:void 0)}else e==="brain_predict_failures"&&k("brain_predict_failures",p);return m}switch(e){case"get_api_status":{let r="unknown";try{const E=await fetch(`${_}/health`,{signal:AbortSignal.timeout(8e3)});if(E.ok){const T=await E.json();r=`${T.status??"ok"} (db: ${T.db??"?"})`}else r=`HTTP ${E.status}`}catch(E){r=`unreachable: ${E.message}`}if(!b)return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${_}`,` \u{1F493} Health: ${r}`," \u{1F511} Auth: \u274C CACHLY_JWT not set","",`\u{1F4A1} Get your API token at ${j("/instances","api-status")} \u2192 Settings \u2192 API Token`].join(`
46
+ `);let p="\u274C invalid JWT format";try{const E=b.split(".");if(E.length===3){const T=JSON.parse(Buffer.from(E[1],"base64url").toString("utf-8")),I=T.sub??"(unknown)",R=T.iss??"(unknown)",$=R.includes("keycloak")?"Keycloak":"OIDC",S=T.exp?new Date(T.exp*1e3):null,P=S?S<new Date:!1;p=["\u2705 JWT decoded",` Sub (user ID): ${I}`,` Provider: ${$}`,` Issuer: ${R}`,` Expires: ${S?S.toISOString():"never"} ${P?"\u26A0\uFE0F EXPIRED \u2013 get a new token!":"\u2705"}`].join(`
47
+ `)}}catch{p="\u274C JWT decode failed \u2013 check CACHLY_JWT format"}let v="";try{const T=(await O("/api/v1/instances")).data??[];if(T.length===0)v=`
48
48
 
49
- \u{1F9E0} **Brain Instances:** none \u2014 create one at ${E("/instances","api-status")}`;else{const T=[`
49
+ \u{1F9E0} **Brain Instances:** none \u2014 create one at ${j("/instances","api-status")}`;else{const I=[`
50
50
 
51
- \u{1F9E0} **Brain Instances:**`];for(const R of C){const _=R.status==="running"?"\u{1F7E2}":R.status==="provisioning"?"\u{1F7E1}":"\u{1F534}",k=R.id===L?" \u2190 active":"";if(T.push(` ${_} **${R.name}** (\`${R.id}\`) \xB7 ${R.status}${k}`),R.status==="running"&&R.host){const P=te.get(R.id);if(P)try{await P.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 R.status==="provisioning"?T.push(" \u23F3 Still provisioning \u2014 check back in ~30 s"):R.status!=="running"&&T.push(` \u274C Not reachable (status: ${R.status})`)}d=T.join(`
52
- `)}}catch(I){d=`
51
+ \u{1F9E0} **Brain Instances:**`];for(const R of T){const $=R.status==="running"?"\u{1F7E2}":R.status==="provisioning"?"\u{1F7E1}":"\u{1F534}",S=R.id===L?" \u2190 active":"";if(I.push(` ${$} **${R.name}** (\`${R.id}\`) \xB7 ${R.status}${S}`),R.status==="running"&&R.host){const P=te.get(R.id);if(P)try{await P.ping(),I.push(" \u{1F493} Redis: connected")}catch{I.push(" \u26A0\uFE0F Redis: pooled but ping failed \u2014 will reconnect on next use")}else I.push(" \u{1F4A4} Redis: not connected yet (connects on first tool use)")}else R.status==="provisioning"?I.push(" \u23F3 Still provisioning \u2014 check back in ~30 s"):R.status!=="running"&&I.push(` \u274C Not reachable (status: ${R.status})`)}v=I.join(`
52
+ `)}}catch(E){v=`
53
53
 
54
- \u{1F9E0} **Brain Instances:** could not fetch \u2014 ${I.message}`}await Le();const S=Te(y),B=S.state==="long_lived"?"\u{1F6E1}\uFE0F Self-healing: \u2705 long-lived API key (won't expire silently)":S.state==="healthy"?`\u{1F6E1}\uFE0F Self-healing: \u2705 token valid${S.expiresInMs?` (${Math.round(S.expiresInMs/36e5)}h left)`:""}`:S.state==="near_expiry"?"\u{1F6E1}\uFE0F Self-healing: \u267B\uFE0F token near expiry \u2014 auto-refresh attempted":`\u{1F6E1}\uFE0F Self-healing: \u26A0\uFE0F ${S.message.split(`
55
- `)[0]}`;return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${v}`,` \u{1F493} Health: ${a}`,` ${B}`,"","\u{1F511} **Auth:**",g,d].join(`
54
+ \u{1F9E0} **Brain Instances:** could not fetch \u2014 ${E.message}`}await Le();const w=Te(b),C=w.state==="long_lived"?"\u{1F6E1}\uFE0F Self-healing: \u2705 long-lived API key (won't expire silently)":w.state==="healthy"?`\u{1F6E1}\uFE0F Self-healing: \u2705 token valid${w.expiresInMs?` (${Math.round(w.expiresInMs/36e5)}h left)`:""}`:w.state==="near_expiry"?"\u{1F6E1}\uFE0F Self-healing: \u267B\uFE0F token near expiry \u2014 auto-refresh attempted":`\u{1F6E1}\uFE0F Self-healing: \u26A0\uFE0F ${w.message.split(`
55
+ `)[0]}`;return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${_}`,` \u{1F493} Health: ${r}`,` ${C}`,"","\u{1F511} **Auth:**",p,v].join(`
56
56
  `)}default:throw new At(`Unknown tool: ${e}`)}}class At extends Error{}const Ct=`REQUIRED FIRST STEP for every task in this project: before you read or edit any file, call the cachly tool smart_recall with one line describing the task (if it is not loaded yet, load it with your tool search first). It returns fixes, decisions and known traps from earlier sessions in THIS codebase. Do this even for small tasks.
57
57
 
58
58
  This project has a Cachly AI Brain \u2014 persistent, cross-session memory of past fixes, decisions, and gotchas for THIS codebase.
@@ -62,62 +62,63 @@ This project has a Cachly AI Brain \u2014 persistent, cross-session memory of pa
62
62
  - AFTER a fix, deploy, or discovery: call learn_from_attempts so the knowledge persists.
63
63
  - BEFORE a risky op (deploy, migration, dependency bump): call brain_predict.
64
64
 
65
- The Brain instance id comes from the CACHLY_BRAIN_INSTANCE_ID environment variable.`,Tt={tools:{},resources:{},prompts:{}},It=async()=>{const{katalog:e,unbekannteKernnamen:t}=es(ge);return t.length>0&&console.error(`cachly: ${t.length} Kernwerkzeug(e) gibt es gar nicht: ${t.join(", ")}`),{tools:e}};async function Et(){return{resources:[]}}async function Rt(){return{resourceTemplates:[]}}async function jt(){return{prompts:[]}}function Ss(e){e.setRequestHandler(Qe,It),e.setRequestHandler(qe,Pt),e.setRequestHandler(Ze,Et),e.setRequestHandler(Ve,Rt),e.setRequestHandler(Ge,jt)}function As(){const e=new Ke({name:"cachly-mcp",version:M},{capabilities:Tt,instructions:Ct});return Ss(e),Bt(e),e}function Bt(e){const t=e.oninitialized;e.oninitialized=()=>{let n;try{n=e.getClientVersion(),zt(n?.name,n?.version)}catch{}_t||(_t=!0,$("mcp_verbunden",{client:String(n?.name??"unbekannt").slice(0,60),client_version:String(n?.version??"").slice(0,30)})),t?.()}}const q=new Ke({name:"cachly-mcp",version:M},{capabilities:Tt,instructions:Ct});Bt(q),q.setRequestHandler(Qe,It),q.setRequestHandler(Ze,Et),q.setRequestHandler(Ve,Rt),q.setRequestHandler(Ge,jt);let Me=null,fe=!1,Z=null,Lt=0;async function Cs(e){if(!fe){if(Z){await Z;return}Z=(async()=>{fe=!0,Me=e;try{await W("session_start",{instance_id:e,focus:"auto (MCP session)",workspace_path:process.cwd()})}catch{}finally{Z=null}})(),await Z,process.env.CACHLY_AUTO_INDEX!=="false"&&(async()=>{const t=await H(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 W("index_project",{instance_id:e,dir:process.cwd(),max_files:150,ttl:86400*7,namespace:"cachly:sem:code",hintergrund:!0}))})().catch(()=>{})}}async function De(){if(!(!fe||!Me)){fe=!1;try{await W("session_end",{instance_id:Me,summary:`Auto-ended after ${Lt} tool call(s). Session was started automatically.`,files_changed:[],lessons_learned:0})}catch{}}}const Pt=async e=>{let{name:t,arguments:n}=e.params;if(t===yt){const o=n??{},i=typeof o.tool=="string"?o.tool:"";if(!i)return{content:[{type:"text",text:'cachly_tool braucht das Feld "tool" \u2014 den Namen des Werkzeugs.'}],isError:!0};const c=ge.find(r=>r.name===i);if(!c)return{content:[{type:"text",text:`Kein Werkzeug namens "${i}". Die Liste steht in der Beschreibung von ${yt}.`}],isError:!0};if(o.describe===!0)return{content:[{type:"text",text:JSON.stringify({name:c.name,description:c.description,inputSchema:c.inputSchema},null,2)}]};t=i,n=o.arguments??{}}const s=new Set(["session_start","session_start_summary","session_end","auto_learn_session"]);if(!s.has(t)&&!fe&&!Z){const o=ke(n?.instance_id)||L||ke(process.env.CACHLY_BRAIN_INSTANCE_ID);o&&await Cs(o).catch(()=>{})}else Z&&await Z.catch(()=>{});s.has(t)||Lt++;try{Qn(),Y(`werkzeug ${t}: Anfang`);const o=await W(t,n??{});return Y(`werkzeug ${t}: Antwort fertig`),{content:[{type:"text",text:hn(t,o)+Wn()+Vn(t)}]}}catch(o){if(o instanceof At)return{content:[{type:"text",text:o.message}],isError:!0};if(o instanceof X)throw o;const i=o.message??String(o);throw Fe("cachly","tool_error",{tool:t,error:i}).catch(()=>{}),new X(se.InternalError,i)}};q.setRequestHandler(qe,Pt),process.on("SIGTERM",async()=>{await De().catch(()=>{});for(const[,e]of te)await e.quit().catch(()=>{});process.exit(0)}),process.on("SIGINT",async()=>{await De().catch(()=>{});for(const[,e]of te)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}
65
+ You do not need to pass instance_id: the server uses CACHLY_BRAIN_INSTANCE_ID if it is set, and otherwise the Brain saved by \`cachly setup\` in ~/.cachly/credentials.json.
66
+ session_start gives a briefing at the start of a session; it does not replace smart_recall for a concrete task.`,Tt={tools:{},resources:{},prompts:{}},It=async()=>{const{katalog:e,unbekannteKernnamen:t}=ts(de);return t.length>0&&console.error(`cachly: ${t.length} Kernwerkzeug(e) gibt es gar nicht: ${t.join(", ")}`),{tools:e}};async function Et(){return{resources:[]}}async function Rt(){return{resourceTemplates:[]}}async function jt(){return{prompts:[]}}function Cs(e){e.setRequestHandler(Qe,It),e.setRequestHandler(qe,Pt),e.setRequestHandler(Ze,Et),e.setRequestHandler(Ve,Rt),e.setRequestHandler(Ge,jt)}function Ts(){const e=new Ke({name:"cachly-mcp",version:M},{capabilities:Tt,instructions:Ct});return Cs(e),Bt(e),e}function Bt(e){const t=e.oninitialized;e.oninitialized=()=>{let n;try{n=e.getClientVersion(),zt(n?.name,n?.version)}catch{}_t||(_t=!0,k("mcp_verbunden",{client:String(n?.name??"unbekannt").slice(0,60),client_version:String(n?.version??"").slice(0,30)})),t?.()}}const q=new Ke({name:"cachly-mcp",version:M},{capabilities:Tt,instructions:Ct});Bt(q),q.setRequestHandler(Qe,It),q.setRequestHandler(Ze,Et),q.setRequestHandler(Ve,Rt),q.setRequestHandler(Ge,jt);let Me=null,fe=!1,Z=null,Lt=0;async function Is(e){if(!fe){if(Z){await Z;return}Z=(async()=>{fe=!0,Me=e;try{await W("session_start",{instance_id:e,focus:"auto (MCP session)",workspace_path:process.cwd()})}catch{}finally{Z=null}})(),await Z,process.env.CACHLY_AUTO_INDEX!=="false"&&(async()=>{const t=await H(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 W("index_project",{instance_id:e,dir:process.cwd(),max_files:150,ttl:86400*7,namespace:"cachly:sem:code",hintergrund:!0}))})().catch(()=>{})}}async function De(){if(!(!fe||!Me)){fe=!1;try{await W("session_end",{instance_id:Me,summary:`Auto-ended after ${Lt} tool call(s). Session was started automatically.`,files_changed:[],lessons_learned:0})}catch{}}}const Pt=async e=>{let{name:t,arguments:n}=e.params;if(t===yt){const o=n??{},i=typeof o.tool=="string"?o.tool:"";if(!i)return{content:[{type:"text",text:'cachly_tool braucht das Feld "tool" \u2014 den Namen des Werkzeugs.'}],isError:!0};const c=de.find(a=>a.name===i);if(!c)return{content:[{type:"text",text:`Kein Werkzeug namens "${i}". Die Liste steht in der Beschreibung von ${yt}.`}],isError:!0};if(o.describe===!0)return{content:[{type:"text",text:JSON.stringify({name:c.name,description:c.description,inputSchema:c.inputSchema},null,2)}]};t=i,n=o.arguments??{}}if(!["learn_from_attempts","smart_recall","recall_feedback"].includes(t)){const o=de.find(c=>c.name===t),i=o?os(t,o.inputSchema,n??{}):null;if(i)return{content:[{type:"text",text:i}],isError:!0}}const s=new Set(["session_start","session_start_summary","session_end","auto_learn_session"]);if(!s.has(t)&&!fe&&!Z){const o=ke(n?.instance_id)||L||ke(process.env.CACHLY_BRAIN_INSTANCE_ID);o&&await Is(o).catch(()=>{})}else Z&&await Z.catch(()=>{});s.has(t)||Lt++;try{Xn(),Y(`werkzeug ${t}: Anfang`);const o=await W(t,n??{});return Y(`werkzeug ${t}: Antwort fertig`),{content:[{type:"text",text:yn(t,o)+Fn()+Zn(t)}]}}catch(o){if(o instanceof At)return{content:[{type:"text",text:o.message}],isError:!0};if(o instanceof X)throw o;const i=o.message??String(o);throw Fe("cachly","tool_error",{tool:t,error:i}).catch(()=>{}),new X(se.InternalError,i)}};q.setRequestHandler(qe,Pt),process.on("SIGTERM",async()=>{await De().catch(()=>{});for(const[,e]of te)await e.quit().catch(()=>{});process.exit(0)}),process.on("SIGINT",async()=>{await De().catch(()=>{});for(const[,e]of te)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}
66
67
  `)}),process.on("uncaughtException",e=>{process.stderr.write(`[cachly-mcp] uncaughtException: ${e?.stack??String(e)}
67
- `)}),process.stdout.on("error",()=>{}),process.stdin.on("error",()=>{});function Ts(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 Nt="https://api.cachly.dev";function Q(e,t,n={}){const s={CACHLY_BRAIN_INSTANCE_ID:t};return n.includeApiKey&&(s.CACHLY_JWT=e),v&&v!==Nt&&(s.CACHLY_API_URL=v),s}function Is(e,t,n){return n==="continue"?JSON.stringify({experimental:{modelContextProtocolServers:[{transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:Q(e,t)}]}},null,2):n==="zed"?JSON.stringify({context_servers:{cachly:{command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:Q(e,t)},settings:{}}}},null,2):Ot(n)?JSON.stringify({servers:{cachly:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:Q(e,t)}}},null,2):JSON.stringify({mcpServers:{cachly:{command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:Q(e,t)}}},null,2)}function Ot(e){return le[e]===".vscode/mcp.json"}function he(e,t){$n(e)||oe(e,t)}async function Ht(e,t,n,s,o,i={}){const c={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:Q(t,n)};if(!o.existsSync(e))return Is(t,n,s);let r={};try{r=JSON.parse(await o.readFile(e,"utf-8"))}catch{try{const{rename:p}=await import("node:fs/promises");await p(e,e+".bak"),process.stderr.write(`\u26A0\uFE0F ${e} was not valid JSON \u2014 backed up to ${e}.bak
68
- `)}catch{}}if(s==="continue"){const p=r.experimental??{},x=p.modelContextProtocolServers??[];let b;for(const f of x){const a=f.env??{};if(a.CACHLY_JWT){b=a.CACHLY_JWT;break}}b&&he(b,i);const w=x.filter(f=>{const a=f.env??{};return!a.CACHLY_JWT&&!a.CACHLY_BRAIN_INSTANCE_ID});return w.push({transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:c.env}),r.experimental={...p,modelContextProtocolServers:w},JSON.stringify(r,null,2)}if(s==="zed"){const p=r.context_servers??{},b=p.cachly?.command?.env?.CACHLY_JWT;return b&&he(b,i),p.cachly={command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:c.env},settings:{}},r.context_servers=p,JSON.stringify(r,null,2)}if(Ot(s)){const p=r.mcpServers??void 0,b=p?.cachly?.env?.CACHLY_JWT;b&&he(b,i),p&&"cachly"in p&&(delete p.cachly,Object.keys(p).length===0&&delete r.mcpServers);const w=r.servers??{},f=w.cachly,a=f?.env?.CACHLY_JWT;return a&&he(a,i),w.cachly=f?.envFile?{type:"stdio",...c,envFile:f.envFile}:{type:"stdio",...c},r.servers=w,JSON.stringify(r,null,2)}const u=r.mcpServers??{},l=u.cachly?.env?.CACHLY_JWT;return l&&he(l,i),u.cachly=c,r.mcpServers=u,JSON.stringify(r,null,2)}async function Mt(e,t,n){const{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),{homedir:i}=await import("node:os"),c=n??i(),r=qo.filter(l=>Vo(l,e,c,s,o)).map(l=>({path:o(e,...l.pfad),prefix:l.prefix})),u=lt(t),m={};for(const{path:l,prefix:p}of r)try{m[l]=await Go(l,u,p)}catch(x){m[l]=`failed:${x.message}`}return m}function Dt(e,t){return t.startsWith("failed:")?`\u26A0\uFE0F Could not write ${e}: ${t.slice(7)} (the rest of the setup continues)`:t==="unchanged"?`\u2713 Unchanged: ${e}`:`${t==="updated"?"\u2705 Updated":t==="appended"?"\u2705 Appended to":"\u2705 Written"}: ${e}`}if(process.argv[2]==="digest"){const e=ee(),t=J();(!e||!t)&&(console.log(`
68
+ `)}),process.stdout.on("error",()=>{}),process.stdin.on("error",()=>{});function Es(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 Nt="https://api.cachly.dev";function Q(e,t,n={}){const s={CACHLY_BRAIN_INSTANCE_ID:t};return n.includeApiKey&&(s.CACHLY_JWT=e),_&&_!==Nt&&(s.CACHLY_API_URL=_),s}function Rs(e,t,n){return n==="continue"?JSON.stringify({experimental:{modelContextProtocolServers:[{transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:Q(e,t)}]}},null,2):n==="zed"?JSON.stringify({context_servers:{cachly:{command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:Q(e,t)},settings:{}}}},null,2):Ot(n)?JSON.stringify({servers:{cachly:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:Q(e,t)}}},null,2):JSON.stringify({mcpServers:{cachly:{command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:Q(e,t)}}},null,2)}function Ot(e){return le[e]===".vscode/mcp.json"}function he(e,t){kn(e)||oe(e,t)}async function Ht(e,t,n,s,o,i={}){const c={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:Q(t,n)};if(!o.existsSync(e))return Rs(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
69
+ `)}catch{}}if(s==="continue"){const u=a.experimental??{},h=u.modelContextProtocolServers??[];let y;for(const m of h){const r=m.env??{};if(r.CACHLY_JWT){y=r.CACHLY_JWT;break}}y&&he(y,i);const x=h.filter(m=>{const r=m.env??{};return!r.CACHLY_JWT&&!r.CACHLY_BRAIN_INSTANCE_ID});return x.push({transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:c.env}),a.experimental={...u,modelContextProtocolServers:x},JSON.stringify(a,null,2)}if(s==="zed"){const u=a.context_servers??{},y=u.cachly?.command?.env?.CACHLY_JWT;return y&&he(y,i),u.cachly={command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:c.env},settings:{}},a.context_servers=u,JSON.stringify(a,null,2)}if(Ot(s)){const u=a.mcpServers??void 0,y=u?.cachly?.env?.CACHLY_JWT;y&&he(y,i),u&&"cachly"in u&&(delete u.cachly,Object.keys(u).length===0&&delete a.mcpServers);const x=a.servers??{},m=x.cachly,r=m?.env?.CACHLY_JWT;return r&&he(r,i),x.cachly=m?.envFile?{type:"stdio",...c,envFile:m.envFile}:{type:"stdio",...c},a.servers=x,JSON.stringify(a,null,2)}const d=a.mcpServers??{},l=d.cachly?.env?.CACHLY_JWT;return l&&he(l,i),d.cachly=c,a.mcpServers=d,JSON.stringify(a,null,2)}async function Mt(e,t,n){const{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),{homedir:i}=await import("node:os"),c=n??i(),a=Go.filter(l=>Zo(l,e,c,s,o)).map(l=>({path:o(e,...l.pfad),prefix:l.prefix})),d=lt(t),g={};for(const{path:l,prefix:u}of a)try{g[l]=await Vo(l,d,u)}catch(h){g[l]=`failed:${h.message}`}return g}function Dt(e,t){return t.startsWith("failed:")?`\u26A0\uFE0F Could not write ${e}: ${t.slice(7)} (the rest of the setup continues)`:t==="unchanged"?`\u2713 Unchanged: ${e}`:`${t==="updated"?"\u2705 Updated":t==="appended"?"\u2705 Appended to":"\u2705 Written"}: ${e}`}if(process.argv[2]==="digest"){const e=ee(),t=J();(!e||!t)&&(console.log(`
69
70
  \u26A0\uFE0F No cachly key or Brain instance found (environment or ~/.cachly/credentials.json).`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
70
71
  `),process.exit(1)),process.stdout.write(`
71
72
  \u{1F9E0} Fetching your weekly Brain digest...
72
73
 
73
- `);try{const n=await fetch(`${v}/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,i=s.total_recall_count??0,c=Math.round(s.iq_boost_pct??0),r=(s.top_lessons??[]).slice(0,5),u=s.team_authors??[],m=i*1200,l=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}",p=new Date,x=new Date(p);x.setDate(p.getDate()-7);const b=g=>g.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(x)} \u2013 ${b(p)}\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${l.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Total recalls : \x1B[36m${String(i).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(c).padEnd(3)}%\x1B[0m \u2502`),console.log(`\u2502 Tokens saved : \x1B[32m${("~"+Math.round(m/1e3)+"K (est.)").padEnd(42)}\x1B[0m\u2502`),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[36m\u{1F465} Team contributors:\x1B[0m ${u.slice(0,5).join(", ").slice(0,42).padEnd(42)} \u2502`)),r.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 g of r){const d=`${g.topic}: ${g.what_worked}`.slice(0,57);console.log(`\u2502 \x1B[90m\u2022 ${d.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 w=r[0],f=[`\u{1F9E0} My AI Brain weekly digest (${b(x)} \u2013 ${b(p)}):`,"",` \u{1F4DA} ${o} lessons learned`,` \u{1F501} ${i} recalls \xB7 ~${Math.round(m/1e3)}K tokens saved`,` \u{1F3AF} Brain Level: ${l}`,w?` \u{1F525} Top lesson: "${w.topic}: ${w.what_worked.slice(0,60)}${w.what_worked.length>60?"\u2026":""}"`:"","","Built with @cachly_dev \u2014 AI that actually remembers \u{1F680}","cachly.dev"].filter(Boolean).join(`
74
- `),a="https://twitter.com/intent/tweet?text="+encodeURIComponent(f);console.log("\x1B[1m\u{1F4E3} Share your digest:\x1B[0m"),console.log(""),console.log("\x1B[90m"+"\u2500".repeat(63)+"\x1B[0m");for(const g of f.split(`
75
- `))console.log(` ${g}`);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${a.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(`
74
+ `);try{const n=await fetch(`${_}/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,i=s.total_recall_count??0,c=Math.round(s.iq_boost_pct??0),a=(s.top_lessons??[]).slice(0,5),d=s.team_authors??[],g=i*1200,l=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}",u=new Date,h=new Date(u);h.setDate(u.getDate()-7);const y=p=>p.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${y(h)} \u2013 ${y(u)}\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${l.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Total recalls : \x1B[36m${String(i).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(c).padEnd(3)}%\x1B[0m \u2502`),console.log(`\u2502 Tokens saved : \x1B[32m${("~"+Math.round(g/1e3)+"K (est.)").padEnd(42)}\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 p of a){const v=`${p.topic}: ${p.what_worked}`.slice(0,57);console.log(`\u2502 \x1B[90m\u2022 ${v.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 x=a[0],m=[`\u{1F9E0} My AI Brain weekly digest (${y(h)} \u2013 ${y(u)}):`,"",` \u{1F4DA} ${o} lessons learned`,` \u{1F501} ${i} recalls \xB7 ~${Math.round(g/1e3)}K tokens saved`,` \u{1F3AF} Brain Level: ${l}`,x?` \u{1F525} Top lesson: "${x.topic}: ${x.what_worked.slice(0,60)}${x.what_worked.length>60?"\u2026":""}"`:"","","Built with @cachly_dev \u2014 AI that actually remembers \u{1F680}","cachly.dev"].filter(Boolean).join(`
75
+ `),r="https://twitter.com/intent/tweet?text="+encodeURIComponent(m);console.log("\x1B[1m\u{1F4E3} Share your digest:\x1B[0m"),console.log(""),console.log("\x1B[90m"+"\u2500".repeat(63)+"\x1B[0m");for(const p of m.split(`
76
+ `))console.log(` ${p}`);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${r.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(`
76
77
  \u274C Could not fetch digest: ${n.message}
77
- `),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=m=>{const l=s.indexOf(`--${m}`);return l!==-1?s[l+1]:void 0},i=o("format")??"both";i!=="md"&&i!=="jsonl"&&i!=="both"&&(console.log(`
78
+ `),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},i=o("format")??"both";i!=="md"&&i!=="jsonl"&&i!=="both"&&(console.log(`
78
79
  \u274C Unknown --format "${i}" \u2014 use md, jsonl, or both.
79
- `),process.exit(1));const c=n(o("out")??"."),r=y||Ne()||"",u=J();(!r||!u)&&(console.log(`
80
+ `),process.exit(1));const c=n(o("out")??"."),a=b||Ne()||"",d=J();(!a||!d)&&(console.log(`
80
81
  \u26A0\uFE0F No cachly key or Brain instance found (environment or ~/.cachly/credentials.json).`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
81
82
  `),process.exit(1)),process.stdout.write(`
82
83
  \u{1F4E4} Exporting your Brain...
83
84
 
84
- `);try{let m=[],l="";const p=await fetch(`${v}/api/v1/instances/${u}/export`,{headers:{Authorization:`Bearer ${r}`},signal:AbortSignal.timeout(12e4)});if(p.ok){const b=await p.json();m=(b.lessons??[]).map(ns).filter(w=>w!==null),b.complete===!1?l=b.note??"the server reported an incomplete read":typeof b.lesson_count=="number"&&m.length<b.lesson_count&&(l=`the server counts ${b.lesson_count} lessons, but only ${m.length} could be read as lessons`)}else if(p.status===404){const b=await fetch(`${v}/api/v1/instances/${u}/memory`,{headers:{Authorization:`Bearer ${r}`},signal:AbortSignal.timeout(8e3)});if(!b.ok)throw new Error(`memory HTTP ${b.status}`);m=((await b.json()).top_lessons??[]).map(f=>({topic:f.topic,outcome:f.outcome,severity:f.severity,tags:f.tags,whatWorked:f.what_worked,ts:f.ts,author:f.author,recallCount:f.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 ${p.status}`);m.length===0&&(console.log(` No lessons in this Brain yet \u2014 nothing to export.
85
- `),process.exit(0)),await t(c,{recursive:!0});const x=[];if(i==="md"||i==="both"){const b=n(c,"lessons.md");await e(b,ts(m),"utf-8"),x.push(`${m.length} lesson${m.length===1?"":"s"} \u2192 ${b}`)}if(i==="jsonl"||i==="both"){const b=n(c,"lessons.jsonl");await e(b,os(m),"utf-8"),x.push(`${m.length} lesson${m.length===1?"":"s"} \u2192 ${b}`)}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 b of x)console.log(` ${b}`);console.log("")}catch(m){console.log(`
86
- \u274C Could not export your Brain: ${m.message}
85
+ `);try{let g=[],l="";const u=await fetch(`${_}/api/v1/instances/${d}/export`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(12e4)});if(u.ok){const y=await u.json();g=(y.lessons??[]).map(is).filter(x=>x!==null),y.complete===!1?l=y.note??"the server reported an incomplete read":typeof y.lesson_count=="number"&&g.length<y.lesson_count&&(l=`the server counts ${y.lesson_count} lessons, but only ${g.length} could be read as lessons`)}else if(u.status===404){const y=await fetch(`${_}/api/v1/instances/${d}/memory`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(8e3)});if(!y.ok)throw new Error(`memory HTTP ${y.status}`);g=((await y.json()).top_lessons??[]).map(m=>({topic:m.topic,outcome:m.outcome,severity:m.severity,tags:m.tags,whatWorked:m.what_worked,ts:m.ts,author:m.author,recallCount:m.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.
86
+ `),process.exit(0)),await t(c,{recursive:!0});const h=[];if(i==="md"||i==="both"){const y=n(c,"lessons.md");await e(y,ns(g),"utf-8"),h.push(`${g.length} lesson${g.length===1?"":"s"} \u2192 ${y}`)}if(i==="jsonl"||i==="both"){const y=n(c,"lessons.jsonl");await e(y,ss(g),"utf-8"),h.push(`${g.length} lesson${g.length===1?"":"s"} \u2192 ${y}`)}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 y of h)console.log(` ${y}`);console.log("")}catch(g){console.log(`
87
+ \u274C Could not export your Brain: ${g.message}
87
88
  `),process.exit(1)}process.exit(0)}if(process.argv[2]==="invite"){const e=ee();e||(console.log(`
88
89
  \u26A0\uFE0F No cachly key found (environment or ~/.cachly/credentials.json).`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
89
- `),process.exit(1));try{const t=await fetch(`${v}/api/v1/referral/me`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)});if(!t.ok)throw new Error(`HTTP ${t.status}`);const n=await t.json(),s=n.url??E(`/r/${n.code}`,"invite"),o=n.referral_count??0,i=`Hey, I've been using cachly to give my AI persistent memory across sessions \u2014 no more re-explaining my stack every morning.
90
+ `),process.exit(1));try{const t=await fetch(`${_}/api/v1/referral/me`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)});if(!t.ok)throw new Error(`HTTP ${t.status}`);const n=await t.json(),s=n.url??j(`/r/${n.code}`,"invite"),o=n.referral_count??0,i=`Hey, I've been using cachly to give my AI persistent memory across sessions \u2014 no more re-explaining my stack every morning.
90
91
 
91
92
  You get a free Brain: ${s}`,c=encodeURIComponent(`I gave my AI persistent memory. It remembers fixes, patterns, and context across every session \u2014 no more re-explaining.
92
93
 
93
94
  Try it free: ${s}
94
95
 
95
- @cachlydev`);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} Your cachly Brain invite link \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 ${s.padEnd(61)}\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"),o>0&&(console.log(`\u2502 \x1B[32m\u2713 ${o} developer${o===1?"":"s"} joined via your link so far\x1B[0m`.padEnd(72)+"\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[33mSlack / DM message:\x1B[0m \u2502"),console.log("\u2502 \u2502");for(const r of i.split(`
96
- `))console.log(`\u2502 \x1B[90m${r.slice(0,58).padEnd(58)}\x1B[0m \u2502`);console.log("\u2502 \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[36m\u{1D54F} Tweet:\x1B[0m https://twitter.com/intent/tweet?text=${c.slice(0,10)}... \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[2m Each developer who signs up via your link earns you 1 month Pro.\x1B[0m"),console.log("")}catch(t){console.log(`
96
+ @cachlydev`);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} Your cachly Brain invite link \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 ${s.padEnd(61)}\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"),o>0&&(console.log(`\u2502 \x1B[32m\u2713 ${o} developer${o===1?"":"s"} joined via your link so far\x1B[0m`.padEnd(72)+"\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[33mSlack / DM message:\x1B[0m \u2502"),console.log("\u2502 \u2502");for(const a of i.split(`
97
+ `))console.log(`\u2502 \x1B[90m${a.slice(0,58).padEnd(58)}\x1B[0m \u2502`);console.log("\u2502 \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[36m\u{1D54F} Tweet:\x1B[0m https://twitter.com/intent/tweet?text=${c.slice(0,10)}... \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[2m Each developer who signs up via your link earns you 1 month Pro.\x1B[0m"),console.log("")}catch(t){console.log(`
97
98
  \u274C Could not fetch invite link: ${t.message}
98
- `),process.exit(1)}process.exit(0)}if(process.argv[2]==="join"){const{writeFile:e,readFile:t,mkdir:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o,dirname:i}=await import("node:path"),{homedir:c}=await import("node:os"),{createInterface:r}=await import("node:readline"),u=process.argv[3]??"";u||(console.log(`
99
+ `),process.exit(1)}process.exit(0)}if(process.argv[2]==="join"){const{writeFile:e,readFile:t,mkdir:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o,dirname:i}=await import("node:path"),{homedir:c}=await import("node:os"),{createInterface:a}=await import("node:readline"),d=process.argv[3]??"";d||(console.log(`
99
100
  \u274C Usage: npx @cachly-dev/mcp-server@latest join <token>
100
101
  `),console.log(` Get a token from a teammate: npx @cachly-dev/mcp-server@latest invite
101
102
  `),process.exit(1)),console.log(`
102
- \u23F3 Looking up invite...`);let m;try{const C=await fetch(`${v}/api/invite/${u}`,{signal:AbortSignal.timeout(8e3)});C.status===404&&(console.log(`
103
+ \u23F3 Looking up invite...`);let g;try{const T=await fetch(`${_}/api/invite/${d}`,{signal:AbortSignal.timeout(8e3)});T.status===404&&(console.log(`
103
104
  \u274C Invite not found \u2014 the link may be invalid.
104
- `),process.exit(1)),C.status===410&&(console.log(`
105
+ `),process.exit(1)),T.status===410&&(console.log(`
105
106
  \u274C This invite link has expired (7-day limit).
106
- `),process.exit(1)),C.ok||(console.log(`
107
- \u274C Could not fetch invite: HTTP ${C.status}
108
- `),process.exit(1)),m=await C.json()}catch(C){console.log(`
109
- \u274C Network error: ${C.message}
110
- `),process.exit(1)}const{instance_id:l,instance_name:p,tier:x,label:b}=m,w=new Date(m.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${p}\x1B[0m`),console.log(` Tier : ${x}`),b&&console.log(` Note : ${b}`),console.log(` Expires : ${w}`),console.log("");const f=r({input:process.stdin,output:process.stdout}),a=await new Promise(C=>{f.question(" Join this Brain? [Y/n] ",T=>{f.close(),C(T.trim().toLowerCase()||"y")})});a!=="y"&&a!=="yes"&&(console.log(`
107
+ `),process.exit(1)),T.ok||(console.log(`
108
+ \u274C Could not fetch invite: HTTP ${T.status}
109
+ `),process.exit(1)),g=await T.json()}catch(T){console.log(`
110
+ \u274C Network error: ${T.message}
111
+ `),process.exit(1)}const{instance_id:l,instance_name:u,tier:h,label:y}=g,x=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 : ${h}`),y&&console.log(` Note : ${y}`),console.log(` Expires : ${x}`),console.log("");const m=a({input:process.stdin,output:process.stdout}),r=await new Promise(T=>{m.question(" Join this Brain? [Y/n] ",I=>{m.close(),T(I.trim().toLowerCase()||"y")})});r!=="y"&&r!=="yes"&&(console.log(`
111
112
  Cancelled.
112
- `),process.exit(0));let g=y;if(!g){console.log(`
113
+ `),process.exit(0));let p=b;if(!p){console.log(`
113
114
  No API key found \u2014 starting sign-in (10 seconds)...
114
- `);try{const C=await fetch(`${v}/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(C.ok){const T=await C.json();console.log(` \u{1F449} Open: \x1B[36m${T.verification_uri}\x1B[0m`),console.log(` Code: \x1B[1m${T.user_code}\x1B[0m
115
- `);const R=(T.interval??5)*1e3;for(let _=0;_<24;_++){await new Promise(k=>setTimeout(k,R));try{const k=await fetch(`${v}/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(k.ok){const P=await k.json();if(P.access_token){g=P.access_token;break}}}catch{}}g||(console.log(`
115
+ `);try{const T=await fetch(`${_}/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(T.ok){const I=await T.json();console.log(` \u{1F449} Open: \x1B[36m${I.verification_uri}\x1B[0m`),console.log(` Code: \x1B[1m${I.user_code}\x1B[0m
116
+ `);const R=(I.interval??5)*1e3;for(let $=0;$<24;$++){await new Promise(S=>setTimeout(S,R));try{const S=await fetch(`${_}/api/v1/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:I.device_code,client_id:"cachly-mcp-cli"}),signal:AbortSignal.timeout(8e3)});if(S.ok){const P=await S.json();if(P.access_token){p=P.access_token;break}}}catch{}}p||(console.log(`
116
117
  \u274C Sign-in timed out. Run the command again.
117
118
  `),process.exit(1)),console.log(` \u2705 Signed in!
118
- `)}}catch(C){console.log(`
119
- \u26A0\uFE0F Could not start sign-in: ${C.message}`),console.log(` Set CACHLY_JWT manually from ${E("/setup-ai","join")}
120
- `),process.exit(1)}}g&&g!==y&&oe(g);const d=process.cwd(),S=c(),B=[{label:".mcp.json (Claude Code project)",path:o(d,".mcp.json")},{label:".cursor/mcp.json",path:o(d,".cursor","mcp.json")},{label:".windsurf/mcp.json",path:o(d,".windsurf","mcp.json")},{label:".vscode/mcp.json (Copilot/Cline)",path:o(d,".vscode","mcp.json")},{label:"~/.claude/mcp.json (global)",path:o(S,".claude","mcp.json"),global:!0}];let I=0;for(const{label:C,path:T,global:R}of B){const _=i(T);if(!(!R&&!s(_)&&!s(T)))try{await n(_,{recursive:!0});let k={};if(s(T))try{k=JSON.parse(await t(T,"utf-8"))}catch{try{await(await import("node:fs/promises")).rename(T,T+".bak")}catch{}}const P=k.mcpServers??{},ne=P.cachly??{},F=ne.env??{};F.CACHLY_BRAIN_INSTANCE_ID=l,g&&R&&!F.CACHLY_JWT&&(F.CACHLY_JWT=g),v!==Nt&&(F.CACHLY_API_URL=v),P.cachly={...ne,command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:F},k.mcpServers=P,await e(T,JSON.stringify(k,null,2),"utf-8"),console.log(` \u2705 ${C}`),I++}catch(k){k.code!=="ENOENT"&&console.log(` \u26A0\uFE0F ${C}: ${k.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${p}\x1B[0m`),console.log(` Restart your editor \u2014 your AI arrives pre-briefed from the team Brain.
119
+ `)}}catch(T){console.log(`
120
+ \u26A0\uFE0F Could not start sign-in: ${T.message}`),console.log(` Set CACHLY_JWT manually from ${j("/setup-ai","join")}
121
+ `),process.exit(1)}}p&&p!==b&&oe(p);const v=process.cwd(),w=c(),C=[{label:".mcp.json (Claude Code project)",path:o(v,".mcp.json")},{label:".cursor/mcp.json",path:o(v,".cursor","mcp.json")},{label:".windsurf/mcp.json",path:o(v,".windsurf","mcp.json")},{label:".vscode/mcp.json (Copilot/Cline)",path:o(v,".vscode","mcp.json")},{label:"~/.claude/mcp.json (global)",path:o(w,".claude","mcp.json"),global:!0}];let E=0;for(const{label:T,path:I,global:R}of C){const $=i(I);if(!(!R&&!s($)&&!s(I)))try{await n($,{recursive:!0});let S={};if(s(I))try{S=JSON.parse(await t(I,"utf-8"))}catch{try{await(await import("node:fs/promises")).rename(I,I+".bak")}catch{}}const P=S.mcpServers??{},ne=P.cachly??{},F=ne.env??{};F.CACHLY_BRAIN_INSTANCE_ID=l,p&&R&&!F.CACHLY_JWT&&(F.CACHLY_JWT=p),_!==Nt&&(F.CACHLY_API_URL=_),P.cachly={...ne,command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:F},S.mcpServers=P,await e(I,JSON.stringify(S,null,2),"utf-8"),console.log(` \u2705 ${T}`),E++}catch(S){S.code!=="ENOENT"&&console.log(` \u26A0\uFE0F ${T}: ${S.message}`)}}console.log(""),E===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.
121
122
  `),console.log(" \u{1F4DB} Add the badge to your README:"),console.log(` npx @cachly-dev/mcp-server@latest badge
122
123
  `)),process.exit(0)}if(process.argv[2]==="upgrade"){process.stdout.write(`
123
124
  \u23F3 Checking for updates...
@@ -125,181 +126,181 @@ Try it free: ${s}
125
126
  \u2705 Already on the latest version: \x1B[32mv${M}\x1B[0m
126
127
  `):(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${M}\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(`
127
128
  \u274C Could not check for updates: ${e.message}
128
- `),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"),i=process.argv.includes("--json"),c=process.argv.slice(3).find(m=>!m.startsWith("--")),r=t(e(import.meta.url)),u=c?n(process.cwd(),c):n(r,"bench","external","sample-corpus.json");try{const m=await s(u),l=await o(m);i&&(console.log(JSON.stringify({corpus:m.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 p=((l.cachly.precisionAt1-l.flatfile.precisionAt1)*100).toFixed(1),x=((l.cachly.mrr-l.flatfile.mrr)*100).toFixed(1),b=((l.cachly.precisionAt1-l.baseline.precisionAt1)*100).toFixed(1),w=l.cachly.precisionAt1>=l.flatfile.precisionAt1?"\x1B[32m+":"\x1B[31m",f=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 : ${m.name??u}`),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 : ${w}${p}%\x1B[0m`),console.log(` MRR : ${f}${x}%\x1B[0m`),console.log(` vs BM25 : \x1B[32m+${b}%\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)}% (${w}${p}% 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${E("/setup-ai","bench")}\x1B[0m`),console.log("")}catch(m){console.error(`
129
- \u274C bench failed: ${m.message}
129
+ `),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"),i=process.argv.includes("--json"),c=process.argv.slice(3).find(g=>!g.startsWith("--")),a=t(e(import.meta.url)),d=c?n(process.cwd(),c):n(a,"bench","external","sample-corpus.json");try{const g=await s(d),l=await o(g);i&&(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),h=((l.cachly.mrr-l.flatfile.mrr)*100).toFixed(1),y=((l.cachly.precisionAt1-l.baseline.precisionAt1)*100).toFixed(1),x=l.cachly.precisionAt1>=l.flatfile.precisionAt1?"\x1B[32m+":"\x1B[31m",m=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 : ${x}${u}%\x1B[0m`),console.log(` MRR : ${m}${h}%\x1B[0m`),console.log(` vs BM25 : \x1B[32m+${y}%\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)}% (${x}${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${j("/setup-ai","bench")}\x1B[0m`),console.log("")}catch(g){console.error(`
130
+ \u274C bench failed: ${g.message}
130
131
  `),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(`
131
132
  \x1B[35m\u{1F9E0} cachly Brain \u2014 Live Demo\x1B[0m`),console.log(`\x1B[90mNo account needed. Reading your git history...\x1B[0m
132
133
  `),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.
133
134
  `),console.log(` Example: cd ~/my-project && npx @cachly-dev/mcp-server@latest demo
134
- `),process.exit(0));let i="";try{i=dt(o,["config","user.name"]).trim().split(" ")[0]??""}catch{}let c=s(o);try{const _=JSON.parse(t(n(o,"package.json"),"utf-8"));_.name&&(c=_.name.replace(/^@[^/]+\//,""))}catch{}let r="";try{r=dt(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.
135
- `),process.exit(0)}const u=r.trim().split(`
136
- `).filter(Boolean).map(_=>{const[k,P,ne,F]=_.split("|||");return{sha:(k??"").trim().slice(0,8),subject:(P??"").trim(),date:(ne??"").trim(),author:(F??"").trim()}});u.length===0&&(console.log(`\u26A0\uFE0F No commits found.
137
- `),process.exit(0));const m=new Map,l=[],p=[],x=[],b=new Set;let w=0;for(const _ of u){const k=us(_.subject);m.set(k,(m.get(k)??0)+1),ps(_.subject)&&w++,k==="fix"&&l.length<5&&l.push(_.subject.slice(0,72)),k==="feat"&&p.length<5&&p.push(_.subject.slice(0,72)),k==="security"&&x.length<3&&x.push(_.subject.slice(0,72)),_.author&&b.add(_.author)}const f=ms(u.map(_=>_.subject)),a=`${u[u.length-1]?.date??"?"} \u2192 ${u[0]?.date??"?"}`,g=f>=501?"Oracle":f>=201?"Architect":f>=51?"Expert":f>=11?"Explorer":"Apprentice",S=`${i?`Hey ${i} \u2014 `:""}here's what your AI would know about ${c}`;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} ${S.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(u.length).padEnd(6)}\x1B[0m Date range: \x1B[90m${a.slice(0,23).padEnd(23)}\x1B[0m \u2502`),console.log(`\u2502 Lessons extracted: \x1B[32m${String(f).padEnd(6)}\x1B[0m Contributors: \x1B[36m${String(b.size).padEnd(20)}\x1B[0m\u2502`),console.log(`\u2502 Brain Level : \x1B[35m${g.padEnd(10)}\x1B[0m Reverts: \x1B[33m${String(w).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=[...m.entries()].filter(([_])=>_!=="chore").sort((_,k)=>k[1]-_[1]),I=(_,k)=>"\u2588".repeat(Math.round(_/k*20)).padEnd(20),C=Math.max(...B.map(([,_])=>_),1);console.log("\u2502 \x1B[90mCategory breakdown:\x1B[0m \u2502");for(const[_,k]of B){const P={fix:"\u{1F527}",feat:"\u2728",perf:"\u26A1",security:"\u{1F512}",deploy:"\u{1F680}",refactor:"\u{1F504}"}[_]??"\u2022";console.log(`\u2502 ${P} \x1B[36m${_.padEnd(10)}\x1B[0m \x1B[35m${I(k,C)}\x1B[0m \x1B[33m${String(k).padStart(3)}\x1B[0m \u2502`)}if(x.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 x)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(p.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 p.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:c,commits:String(u.length),lessons:String(f),level:g,authors:String(b.size),reverts:String(w)}),R=E(`/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${R}\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=ee(),t=J();(!e||!t)&&(console.log(`
135
+ `),process.exit(0));let i="";try{i=dt(o,["config","user.name"]).trim().split(" ")[0]??""}catch{}let c=s(o);try{const $=JSON.parse(t(n(o,"package.json"),"utf-8"));$.name&&(c=$.name.replace(/^@[^/]+\//,""))}catch{}let a="";try{a=dt(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.
136
+ `),process.exit(0)}const d=a.trim().split(`
137
+ `).filter(Boolean).map($=>{const[S,P,ne,F]=$.split("|||");return{sha:(S??"").trim().slice(0,8),subject:(P??"").trim(),date:(ne??"").trim(),author:(F??"").trim()}});d.length===0&&(console.log(`\u26A0\uFE0F No commits found.
138
+ `),process.exit(0));const g=new Map,l=[],u=[],h=[],y=new Set;let x=0;for(const $ of d){const S=ms($.subject);g.set(S,(g.get(S)??0)+1),gs($.subject)&&x++,S==="fix"&&l.length<5&&l.push($.subject.slice(0,72)),S==="feat"&&u.length<5&&u.push($.subject.slice(0,72)),S==="security"&&h.length<3&&h.push($.subject.slice(0,72)),$.author&&y.add($.author)}const m=fs(d.map($=>$.subject)),r=`${d[d.length-1]?.date??"?"} \u2192 ${d[0]?.date??"?"}`,p=m>=501?"Oracle":m>=201?"Architect":m>=51?"Expert":m>=11?"Explorer":"Apprentice",w=`${i?`Hey ${i} \u2014 `:""}here's what your AI would know about ${c}`;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} ${w.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(m).padEnd(6)}\x1B[0m Contributors: \x1B[36m${String(y.size).padEnd(20)}\x1B[0m\u2502`),console.log(`\u2502 Brain Level : \x1B[35m${p.padEnd(10)}\x1B[0m Reverts: \x1B[33m${String(x).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 C=[...g.entries()].filter(([$])=>$!=="chore").sort(($,S)=>S[1]-$[1]),E=($,S)=>"\u2588".repeat(Math.round($/S*20)).padEnd(20),T=Math.max(...C.map(([,$])=>$),1);console.log("\u2502 \x1B[90mCategory breakdown:\x1B[0m \u2502");for(const[$,S]of C){const P={fix:"\u{1F527}",feat:"\u2728",perf:"\u26A1",security:"\u{1F512}",deploy:"\u{1F680}",refactor:"\u{1F504}"}[$]??"\u2022";console.log(`\u2502 ${P} \x1B[36m${$.padEnd(10)}\x1B[0m \x1B[35m${E(S,T)}\x1B[0m \x1B[33m${String(S).padStart(3)}\x1B[0m \u2502`)}if(h.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 h)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 I=new URLSearchParams({repo:c,commits:String(d.length),lessons:String(m),level:p,authors:String(y.size),reverts:String(x)}),R=j(`/preview?${I.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${R}\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=ee(),t=J();(!e||!t)&&(console.log(`
138
139
  \u26A0\uFE0F No cachly key or Brain instance found (environment or ~/.cachly/credentials.json).`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot (takes 1\u20135 minutes)
139
140
  `),process.exit(1)),process.stdout.write(`
140
141
  \u{1F9E0} Fetching your Brain stats...
141
- `);try{const n=await fetch(`${v}/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,i=s.total_recall_count??0,c=Math.round(s.iq_boost_pct??0),r=i*1200,u=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${u.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Total recalls : \x1B[36m${String(i).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(c).padEnd(3)}%\x1B[0m \u2502`),console.log(`\u2502 Tokens saved : \x1B[32m${("~"+(r/1e3).toFixed(0)+"K (est.)").padEnd(42)}\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 m=E("/","share"),l=`\u{1F9E0} My AI coding assistant now has persistent memory.
142
+ `);try{const n=await fetch(`${_}/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,i=s.total_recall_count??0,c=Math.round(s.iq_boost_pct??0),a=i*1200,d=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${d.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Total recalls : \x1B[36m${String(i).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(c).padEnd(3)}%\x1B[0m \u2502`),console.log(`\u2502 Tokens saved : \x1B[32m${("~"+(a/1e3).toFixed(0)+"K (est.)").padEnd(42)}\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 g=j("/","share"),l=`\u{1F9E0} My AI coding assistant now has persistent memory.
142
143
 
143
- ${o} lessons stored \xB7 ${i} recalls \xB7 ${u}
144
+ ${o} lessons stored \xB7 ${i} recalls \xB7 ${d}
144
145
 
145
146
  Fix a bug once \u2192 AI remembers forever. Across Claude Code, Cursor, Windsurf, Copilot.
146
147
 
147
- ${m}
148
+ ${g}
148
149
 
149
150
  #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(l.split(`
150
- `).map(p=>` ${p}`).join(`
151
+ `).map(u=>` ${u}`).join(`
151
152
  `)),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(`
152
153
  \u274C Could not fetch stats: ${n.message}
153
154
  `),process.exit(1)}process.exit(0)}if(process.argv[2]==="publish"){const e=ee(),t=J();(!e||!t)&&(console.log(`
154
155
  \u26A0\uFE0F No cachly key or Brain instance found (environment or ~/.cachly/credentials.json).`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
155
156
  `),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(`
156
157
  \u{1F9E0} Publishing Brain snapshot...
157
- `);try{const i=await fetch(`${v}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)});let c=0,r=0;if(i.ok){const x=await i.json();c=x.lesson_count??0,r=x.total_recall_count??0}const u=await fetch(`${v}/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(!u.ok)throw new Error(`HTTP ${u.status}`);const l=(await u.json()).share_id??"unavailable",p=E(`/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(c).padEnd(10)}\x1B[0m Recalls: \x1B[36m${String(r).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${p.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(` ${p}`),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(i){console.log(`
158
+ `);try{const i=await fetch(`${_}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)});let c=0,a=0;if(i.ok){const h=await i.json();c=h.lesson_count??0,a=h.total_recall_count??0}const d=await fetch(`${_}/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=j(`/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(c).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(i){console.log(`
158
159
  \u274C Could not publish Brain: ${i.message}
159
160
  `),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(`
160
161
  \u274C Unknown format "${t}". Use one of: ${n.join(", ")}
161
162
 
162
- `),process.exit(1)),process.stdout.write(e(ge,t,M)+`
163
+ `),process.exit(1)),process.stdout.write(e(de,t,M)+`
163
164
  `,()=>process.exit(0))}if(process.argv[2]==="badge"){const e=J();e||(console.log(`
164
165
  \u26A0\uFE0F No Brain instance found (environment or ~/.cachly/credentials.json).`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot (takes 1\u20135 minutes)
165
- `),process.exit(1));const t=`${v}/api/v1/badge/${e}`,n=E("/","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)}const ye=Zo(process.argv[2],process.stdin.isTTY===!0&&process.stdout.isTTY===!0);if(ye==="version"&&(process.stdout.write(`${M}
166
+ `),process.exit(1));const t=`${_}/api/v1/badge/${e}`,n=j("/","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)}const ye=Qo(process.argv[2],process.stdin.isTTY===!0&&process.stdout.isTTY===!0);if(ye==="version"&&(process.stdout.write(`${M}
166
167
  `,()=>process.exit(0)),await new Promise(()=>{})),ye==="unbekannt"&&console.error(`
167
- Unknown command: ${process.argv[2]}`),!process.argv[2]&&process.stdout.isTTY||ye==="hilfe"||ye==="unbekannt"){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("");const e=(t,n)=>console.log(` \x1B[36m ${t.padEnd(22)}\x1B[0m ${n}`);console.log(" \x1B[1mStart:\x1B[0m \x1B[1m\x1B[32mnpx @cachly-dev/mcp-server@latest autopilot\x1B[0m \u2190 \x1B[1mOne command, fully ready\x1B[0m"),console.log(" Every command below runs as: npx @cachly-dev/mcp-server@latest <command>"),console.log(""),console.log(" \x1B[1mEvery day:\x1B[0m"),e("status","Lessons, recalls and team at a glance"),e("ambient-stats","Tokens injected vs saved \u2014 the honest net, even when negative"),e("doctor","Diagnose a broken or missing install"),e("health","Check key, API, editor configs and git hook"),e("digest","What your Brain learned this week"),console.log(" \x1B[1mSet up:\x1B[0m"),e("demo","Try it first (no account)"),e("setup","Interactive setup (pick editors)"),e("init","Write the config for one editor (flags)"),e("claim","Keep a test Brain in your own account"),e("upgrade","Check for updates"),e("uninstall","Take cachly out of this project (--dry-run first)"),console.log(" \x1B[1mYour data:\x1B[0m"),e("export","Write your lessons to disk (md / jsonl)"),e("index [dir]","Index a project into the Brain (CI)"),e("learn-git [repo]","Learn lessons from recent commits (CI)"),console.log(" \x1B[1mTeam & sharing:\x1B[0m"),e("invite","Invite a teammate"),e("join <token>","Accept a Brain invite"),e("share","Share your Brain stats"),e("publish","Publish an importable Brain snapshot"),e("badge","README badge for your Brain"),console.log(" \x1B[1mMore:\x1B[0m"),e("bench","Recall quality vs flat-file memory"),e("tool-specs | openapi","Tool definitions for other agent frameworks"),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 ${ge.length} MCP tools\x1B[0m`),console.log(""),process.exit(ye==="unbekannt"?1:0)}const Es={cursor:{datei:".cursor/hooks.json",name:"Cursor",wie:"session briefing, per-prompt recall after the first tool call"},copilot:{datei:ln,name:"VS Code / Copilot",wie:"session briefing, per-prompt recall"},codex:{datei:dn,name:"Codex",wie:"session briefing, per-prompt recall; trust it once in /hooks"},gemini:{datei:un,name:"Gemini CLI",wie:"session briefing, per-prompt recall"}};function Rs(e,t,n){if(!t)return;const{datei:s,name:o,wie:i}=Es[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 c=t.hooks==="unchanged"?"\u2713 ":"\u2705 ",r=t.hooks==="written"?"Written":t.hooks==="merged"?"Merged":"Already wired";console.log(`${c}${n}${r}: ${s} (Ambient Recall for ${o} \u2014 ${i})`)}async function ze(e,t,n,s){const o=e==="codex"?"Codex":"Gemini CLI",i=await(e==="codex"?xn:_n)(t,n).catch(()=>null);if(!i||i.status==="skipped"){const u=Ts(e,n);console.log(`\u26A0\uFE0F ${s}${i?`${i.datei} ${i.grund??"could not be read"} \u2014 left untouched.`:`${o} MCP entry could not be written.`} Register cachly yourself:`),u&&console.log(` ${s}${u.befehl}`);return}const c=i.status==="unchanged"?"\u2713 ":"\u2705 ",r=i.status==="written"?"Written":i.status==="updated"?"Updated":"Already configured";console.log(`${c}${s}${r}: ${i.datei} (MCP server cachly for ${o} \u2014 it asks once to trust this folder; until then the server stays off)`)}async function be(e,t,n,s){const o={cursor:sn,copilot:rn,codex:an,gemini:cn}[e];Rs(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:i}=await import("node:path"),c=process.argv.slice(3),r=d=>Qo(c,d),u=Xo(c,["instance-id","api-key","editor","project-dir","api-url"]);u.length>0&&(console.error(`
168
- Missing value for ${u.map(d=>`--${d}`).join(", ")}. Nothing was written.
169
- `),process.exit(1));let m=r("instance-id")??process.env.CACHLY_BRAIN_INSTANCE_ID,l=r("api-key")??process.env.CACHLY_JWT;const p=(r("editor")??"claude").toLowerCase(),x=o(r("project-dir")??"."),b=r("api-url");if(b&&(v=b.replace(/\/+$/,"")),!m||!l){const d=_e(),S=$e();d&&S&&(l??=d,m??=S,l===d&&m===S&&console.log("\u2713 Reusing credentials from ~/.cachly/credentials.json (saved by a prior setup)"))}if(!m||!l)try{const{existsSync:d}=await import("node:fs"),S=process.env.HOME??process.env.USERPROFILE??"",B=S?o(S,".claude","mcp.json"):"";if(B&&d(B)){const C=JSON.parse(await s(B,"utf-8")).mcpServers?.cachly?.env??{};l??=C.CACHLY_JWT,m??=C.CACHLY_BRAIN_INSTANCE_ID,l&&m&&console.log("\u2713 Reusing credentials from ~/.claude/mcp.json (saved by a prior setup)")}}catch{}(!m||!l)&&(console.error(`
168
+ Unknown command: ${process.argv[2]}`),!process.argv[2]&&process.stdout.isTTY||ye==="hilfe"||ye==="unbekannt"){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("");const e=(t,n)=>console.log(` \x1B[36m ${t.padEnd(22)}\x1B[0m ${n}`);console.log(" \x1B[1mStart:\x1B[0m \x1B[1m\x1B[32mnpx @cachly-dev/mcp-server@latest autopilot\x1B[0m \u2190 \x1B[1mOne command, fully ready\x1B[0m"),console.log(" Every command below runs as: npx @cachly-dev/mcp-server@latest <command>"),console.log(""),console.log(" \x1B[1mEvery day:\x1B[0m"),e("status","Lessons, recalls and team at a glance"),e("ambient-stats","Tokens injected vs saved \u2014 the honest net, even when negative"),e("doctor","Diagnose a broken or missing install"),e("health","Check key, API, editor configs and git hook"),e("digest","What your Brain learned this week"),console.log(" \x1B[1mSet up:\x1B[0m"),e("demo","Try it first (no account)"),e("setup","Interactive setup (pick editors)"),e("init","Write the config for one editor (flags)"),e("claim","Keep a test Brain in your own account"),e("upgrade","Check for updates"),e("uninstall","Take cachly out of this project (--dry-run first)"),console.log(" \x1B[1mYour data:\x1B[0m"),e("export","Write your lessons to disk (md / jsonl)"),e("index [dir]","Index a project into the Brain (CI)"),e("learn-git [repo]","Learn lessons from recent commits (CI)"),console.log(" \x1B[1mTeam & sharing:\x1B[0m"),e("invite","Invite a teammate"),e("join <token>","Accept a Brain invite"),e("share","Share your Brain stats"),e("publish","Publish an importable Brain snapshot"),e("badge","README badge for your Brain"),console.log(" \x1B[1mMore:\x1B[0m"),e("bench","Recall quality vs flat-file memory"),e("tool-specs | openapi","Tool definitions for other agent frameworks"),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 ${de.length} MCP tools\x1B[0m`),console.log(""),process.exit(ye==="unbekannt"?1:0)}const js={cursor:{datei:".cursor/hooks.json",name:"Cursor",wie:"session briefing, per-prompt recall after the first tool call"},copilot:{datei:dn,name:"VS Code / Copilot",wie:"session briefing, per-prompt recall"},codex:{datei:un,name:"Codex",wie:"session briefing, per-prompt recall; trust it once in /hooks"},gemini:{datei:pn,name:"Gemini CLI",wie:"session briefing, per-prompt recall"}};function Bs(e,t,n){if(!t)return;const{datei:s,name:o,wie:i}=js[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 c=t.hooks==="unchanged"?"\u2713 ":"\u2705 ",a=t.hooks==="written"?"Written":t.hooks==="merged"?"Merged":"Already wired";console.log(`${c}${n}${a}: ${s} (Ambient Recall for ${o} \u2014 ${i})`)}async function ze(e,t,n,s){const o=e==="codex"?"Codex":"Gemini CLI",i=await(e==="codex"?_n:$n)(t,n).catch(()=>null);if(!i||i.status==="skipped"){const d=Es(e,n);console.log(`\u26A0\uFE0F ${s}${i?`${i.datei} ${i.grund??"could not be read"} \u2014 left untouched.`:`${o} MCP entry could not be written.`} Register cachly yourself:`),d&&console.log(` ${s}${d.befehl}`);return}const c=i.status==="unchanged"?"\u2713 ":"\u2705 ",a=i.status==="written"?"Written":i.status==="updated"?"Updated":"Already configured";console.log(`${c}${s}${a}: ${i.datei} (MCP server cachly for ${o} \u2014 it asks once to trust this folder; until then the server stays off)`)}async function be(e,t,n,s){const o={cursor:rn,copilot:an,codex:cn,gemini:ln}[e];Bs(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:i,relative:c}=await import("node:path"),a=process.argv.slice(3),d=w=>Xo(a,w),g=en(a,["instance-id","api-key","editor","project-dir","api-url"]);g.length>0&&(console.error(`
169
+ Missing value for ${g.map(w=>`--${w}`).join(", ")}. Nothing was written.
170
+ `),process.exit(1));let l=d("instance-id")??process.env.CACHLY_BRAIN_INSTANCE_ID,u=d("api-key")??process.env.CACHLY_JWT;const h=(d("editor")??"claude").toLowerCase(),y=o(d("project-dir")??"."),x=d("api-url");if(x&&(_=x.replace(/\/+$/,"")),!l||!u){const w=_e(),C=$e();w&&C&&(u??=w,l??=C,u===w&&l===C&&console.log("\u2713 Reusing credentials from ~/.cachly/credentials.json (saved by a prior setup)"))}if(!l||!u)try{const{existsSync:w}=await import("node:fs"),C=process.env.HOME??process.env.USERPROFILE??"",E=C?o(C,".claude","mcp.json"):"";if(E&&w(E)){const I=JSON.parse(await s(E,"utf-8")).mcpServers?.cachly?.env??{};u??=I.CACHLY_JWT,l??=I.CACHLY_BRAIN_INSTANCE_ID,u&&l&&console.log("\u2713 Reusing credentials from ~/.claude/mcp.json (saved by a prior setup)")}}catch{}(!l||!u)&&(console.error(`
170
171
  Usage: npx @cachly-dev/mcp-server@latest init --instance-id <uuid> --api-key <cky_live_...> [--editor claude|cursor|windsurf|copilot|continue|cline|zed|codex|gemini] [--project-dir /path] [--api-url https://your-self-hosted-backend]
171
172
  `),console.error(`First time? Run the zero-config wizard (signs you in, auto-provisions): npx @cachly-dev/mcp-server@latest autopilot
172
- `),console.error(`Get your credentials from: ${E("/setup-ai","init")}
173
- `),process.exit(1));const w=en({instanceId:m,apiKey:l,editor:p},[...Object.keys(le),"codex","gemini"]);if(w.length>0){console.error(`
174
- Nothing was written:`);for(const d of w)console.error(` - ${d}`);console.error(""),process.exit(1)}try{const d=await fetch(`${v}/api/v1/instances/${m}/memory`,{headers:{Authorization:`Bearer ${l}`},signal:AbortSignal.timeout(8e3)});(d.status===401||d.status===403||d.status===404)&&(console.error(`
175
- The server does not accept this key and instance (HTTP ${d.status}). Nothing was written.`),console.error(`Get your credentials from: ${E("/setup-ai","init")}
176
- `),process.exit(1))}catch{console.log("\u26A0\uFE0F Could not reach the server to check the key \u2014 writing the config anyway.")}const f=()=>{oe(l),$e()||xe(m,{apiKey:l})};if(p==="codex"||p==="gemini")f(),console.log(""),await ze(p,x,Q(l,m),"");else{const d=le[p]??".mcp.json",S=o(x,d);await n(i(S),{recursive:!0});const{existsSync:B}=await import("node:fs"),I=B(S),C=I?await s(S,"utf-8").catch(()=>""):"";f();const T=await Ht(S,l,m,p,{readFile:s,existsSync:B});T!==C?(await t(S,T,"utf-8"),console.log(`
177
- \u2705 ${I?"Updated":"Written"}: ${d}`)):console.log(`
178
- \u2713 Already configured: ${d} (no change)`)}const a=await Mt(x,m);for(const[d,S]of Object.entries(a))console.log(Dt(d.split(/[\\/]/).pop()??d,S));try{const d=await at(x,m);d==="written"?console.log("\u2705 Written: .git/hooks/post-commit (CLS hook)"):d==="upgraded"?console.log(`\u2705 Upgraded: .git/hooks/post-commit (CLS hook \u2192 ${ct})`):d==="appended"?console.log("\u2705 Appended: .git/hooks/post-commit (CLS hook)"):d==="unchanged"&&console.log("\u2713 CLS hook already current in .git/hooks/post-commit")}catch{}if(p==="claude")try{const d=await ut(x,m);if(d.settings==="skipped")console.log(`\u26A0\uFE0F .claude/settings.json ${d.grund??"is not valid JSON"} \u2014 left untouched, Ambient Recall hooks not wired`);else{const S=d.scripts==="written"?"\u2705 Written":d.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${pt})`:"\u2713 Unchanged";console.log(`${S}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),d.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):d.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{}(p==="cursor"||p==="copilot"||p==="codex"||p==="gemini")&&await be(p,x,m,"");const g=((Date.now()-e)/1e3).toFixed(1);console.log(`
179
- \u{1F9E0} Cachly AI Brain configured for ${p==="claude"?"Claude Code":p}! (${g}s)`),console.log(p==="codex"||p==="gemini"?` Start ${p} in this folder and trust it when asked \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(`
173
+ `),console.error(`Get your credentials from: ${j("/setup-ai","init")}
174
+ `),process.exit(1));const m=tn({instanceId:l,apiKey:u,editor:h},[...Object.keys(le),"codex","gemini"]);if(m.length>0){console.error(`
175
+ Nothing was written:`);for(const w of m)console.error(` - ${w}`);console.error(""),process.exit(1)}try{const w=await fetch(`${_}/api/v1/instances/${l}/memory`,{headers:{Authorization:`Bearer ${u}`},signal:AbortSignal.timeout(8e3)});(w.status===401||w.status===403||w.status===404)&&(console.error(`
176
+ The server does not accept this key and instance (HTTP ${w.status}). Nothing was written.`),console.error(`Get your credentials from: ${j("/setup-ai","init")}
177
+ `),process.exit(1))}catch{console.log("\u26A0\uFE0F Could not reach the server to check the key \u2014 writing the config anyway.")}const r=()=>{oe(u),$e()||xe(l,{apiKey:u})};if(h==="codex"||h==="gemini")r(),console.log(""),await ze(h,y,Q(u,l),"");else{const w=le[h]??".mcp.json",C=o(y,w);await n(i(C),{recursive:!0});const{existsSync:E}=await import("node:fs"),T=E(C),I=T?await s(C,"utf-8").catch(()=>""):"";r();const R=await Ht(C,u,l,h,{readFile:s,existsSync:E});R!==I?(await t(C,R,"utf-8"),console.log(`
178
+ \u2705 ${T?"Updated":"Written"}: ${w}`)):console.log(`
179
+ \u2713 Already configured: ${w} (no change)`)}const p=await Mt(y,l);for(const[w,C]of Object.entries(p))console.log(Dt(w.split(/[\\/]/).pop()??w,C));try{const w=await at(y,l),C=c(y,o(Yo(y),"post-commit")).replace(/\\/g,"/");w==="written"?console.log(`\u2705 Written: ${C} (CLS hook)`):w==="upgraded"?console.log(`\u2705 Upgraded: ${C} (CLS hook \u2192 ${ct})`):w==="appended"?console.log(`\u2705 Appended: ${C} (CLS hook)`):w==="unchanged"&&console.log(`\u2713 CLS hook already current in ${C}`)}catch{}if(h==="claude")try{const w=await ut(y,l);if(w.settings==="skipped")console.log(`\u26A0\uFE0F .claude/settings.json ${w.grund??"is not valid JSON"} \u2014 left untouched, Ambient Recall hooks not wired`);else{const C=w.scripts==="written"?"\u2705 Written":w.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${pt})`:"\u2713 Unchanged";console.log(`${C}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),w.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):w.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{}(h==="cursor"||h==="copilot"||h==="codex"||h==="gemini")&&await be(h,y,l,"");const v=((Date.now()-e)/1e3).toFixed(1);console.log(`
180
+ \u{1F9E0} Cachly AI Brain configured for ${h==="claude"?"Claude Code":h}! (${v}s)`),console.log(h==="codex"||h==="gemini"?` Start ${h} in this folder and trust it when asked \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(`
180
181
  \u{1F4DB} Add a live badge to your README:`),console.log(` npx @cachly-dev/mcp-server@latest badge
181
182
  `),process.exit(0)}if(process.argv[2]==="status"){const e=ee(),t=J();(!e||!t)&&(console.log(`
182
183
  \u26A0\uFE0F No cachly key or Brain instance found (environment or ~/.cachly/credentials.json).`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
183
- `),process.exit(1));try{const[n,s]=await Promise.all([fetch(`${v}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)}),fetch(`${v}/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(),i=s.ok?await s.json():null,c=o.lesson_count??0,r=o.total_recall_count??0,u=Math.round(o.iq_boost_pct??0),m=o.team_authors??[],l=i?.referral_count??0,p=i?.url??"",x=c===0?"Intern \u{1F331}":c<10?"Junior Dev \u{1F527}":c<30?"Mid Dev \u26A1":c<60?"Senior Dev \u{1F9E0}":c<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}",b=c>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 ${b} \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(c).padEnd(8)}\x1B[0m Level : \x1B[32m${x.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Recalls : \x1B[36m${String(r).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(u).padEnd(3)}%\x1B[0m \u2502`),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");const w=m.slice(0,4).join(", ");console.log(`\u2502 \x1B[36m\u{1F465} Team Brain\x1B[0m \xB7 ${String(m.length).padEnd(2)} developer${m.length===1?" ":"s"} sharing lessons${" ".repeat(Math.max(0,19-w.length))} \u2502`),console.log(`\u2502 ${w.slice(0,56).padEnd(56)} \u2502`)}if(p){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 w=`${p.slice(0,44)}${p.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${w.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(""),c===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(`
184
+ `),process.exit(1));try{const[n,s]=await Promise.all([fetch(`${_}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)}),fetch(`${_}/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(),i=s.ok?await s.json():null,c=o.lesson_count??0,a=o.total_recall_count??0,d=Math.round(o.iq_boost_pct??0),g=o.team_authors??[],l=i?.referral_count??0,u=i?.url??"",h=c===0?"Intern \u{1F331}":c<10?"Junior Dev \u{1F527}":c<30?"Mid Dev \u26A1":c<60?"Senior Dev \u{1F9E0}":c<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}",y=c>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 ${y} \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(c).padEnd(8)}\x1B[0m Level : \x1B[32m${h.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 x=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-x.length))} \u2502`),console.log(`\u2502 ${x.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 x=`${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${x.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(""),c===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(`
184
185
  \u274C Could not fetch status: ${n.message}
185
- `),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,i=0;const c=f=>{console.log(` \u2705 ${f}`),o++},r=f=>{console.log(` \u26A0\uFE0F ${f}`)},u=f=>{console.log(` \u274C ${f}`),i++};console.log(`
186
+ `),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,i=0;const c=m=>{console.log(` \u2705 ${m}`),o++},a=m=>{console.log(` \u26A0\uFE0F ${m}`)},d=m=>{console.log(` \u274C ${m}`),i++};console.log(`
186
187
  \u{1F9E0} cachly health check
187
- `),console.log("\u{1F511} Auth token");const m=ee();if(!m)u("No cachly key found (environment or ~/.cachly/credentials.json) \u2014 run: npx @cachly-dev/mcp-server@latest autopilot");else if(m.startsWith("cky_"))c("Long-lived API key set (cky_\u2026) \u2014 no client-side expiry");else try{const f=m.split(".");if(f.length!==3)throw new Error("not a JWT");const a=JSON.parse(Buffer.from(f[1],"base64url").toString("utf-8")),g=a.exp?a.exp*1e3:null,d=g?Math.floor((g-Date.now())/6e4):null;g&&g<Date.now()?u(`JWT expired ${Math.abs(d)} minute(s) ago \u2014 get a new one: ${E("/setup-ai","health")}`):d!==null&&d<30?r(`JWT expires in ${d} minute(s) \u2014 refresh soon at ${E("/setup-ai","health")}`):c(`JWT valid${d!==null?` (expires in ${Math.floor(d/60)}h ${d%60}m)`:""}`)}catch{u("CACHLY_JWT format invalid (expected a cky_ API key or a 3-part JWT)")}console.log(`
188
- \u{1F310} Brain API`);const l=process.env.CACHLY_API_URL??"https://api.cachly.dev";try{const f=await fetch(`${l}/health`,{signal:AbortSignal.timeout(5e3)});if(f.ok){const a=await f.json();c(`${l} reachable (status: ${a.status??"ok"})`)}else f.status===401||f.status===403?c(`${l} reachable (auth required \u2014 expected)`):u(`${l}/health returned HTTP ${f.status}`)}catch(f){u(`${l} unreachable \u2014 ${f.message}`)}console.log(`
189
- \u{1F9E0} Brain instance`);const p=J();if(!p)r("No Brain instance found (environment or ~/.cachly/credentials.json) \u2014 will auto-resolve on first tool call");else if(m)try{const f=await fetch(`${l}/api/v1/instances/${p}`,{headers:{Authorization:`Bearer ${m}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(f.ok){const a=await f.json();if(a.status==="running")if(c(`Instance "${a.name}" (${p.slice(0,8)}\u2026) is running`),console.log(`
190
- \u{1F50C} Redis connectivity`),a.host&&a.port)try{let g,d;try{const C=await fetch(`${l}/api/v1/instances/${p}/connection`,{headers:{Authorization:`Bearer ${m}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(C.ok){const T=await C.json();g=T.password,d=T}}catch{}const S=vt({host:a.host,port:a.port,tls_enabled:a.tls_enabled},d),B=new Xe({host:S.host,port:S.port,password:g,...S.tls?{tls:S.tls}:{},lazyConnect:!0,connectTimeout:5e3,retryStrategy:()=>null});await B.connect();const I=await B.ping();B.disconnect(),I==="PONG"?c(`Redis PING \u2192 PONG (${S.host}:${S.port}, ${S.art==="klartext"?"unencrypted":"TLS"})`):r(`Redis responded but not PONG: ${I}`)}catch(g){u(`Redis unreachable \u2014 ${g.message}`)}else r("Instance has no host/port yet");else r(`Instance "${a.name}" status: ${a.status}`)}else u(`Instance ${p.slice(0,8)}\u2026 not found (HTTP ${f.status})`)}catch(f){u(`Could not check instance \u2014 ${f.message}`)}console.log(`
191
- \u{1F6E0} Editor configs (project dir)`);const x=[{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"},{editor:"Codex",path:".codex/config.toml"},{editor:"Gemini CLI",path:".gemini/settings.json"}];let b=0;for(const{editor:f,path:a}of x){const g=n(s,a);if(e(g))try{const d=await t(g,"utf-8");d.includes("@cachly-dev/mcp-server")||d.includes("cachly")?(c(`${f}: ${a}`),b++):r(`${f}: ${a} exists but cachly not found inside`)}catch{r(`${f}: ${a} exists but could not read`)}}b===0&&u("No editor MCP configs found in this folder \u2014 run: npx @cachly-dev/mcp-server@latest init (add --editor cursor|copilot|codex|gemini if needed)"),console.log(`
192
- \u{1FA9D} Git hook (ambient learning)`);const w=n(s,".git","hooks","post-commit");if(!e(n(s,".git")))r("Not in a git repository \u2014 skip");else if(e(w))try{(await t(w,"utf-8")).includes("cachly")?c(".git/hooks/post-commit (cachly CLS hook present)"):r(".git/hooks/post-commit exists but cachly hook not found \u2014 run setup to add it")}catch{r(".git/hooks/post-commit exists but could not read")}else r(".git/hooks/post-commit not found \u2014 run: npx @cachly-dev/mcp-server@latest autopilot");console.log(`
193
- \u{1F9EC} Embedding provider (semantic search)`);{const f=[["OPENAI_API_KEY","openai"],["GEMINI_API_KEY","gemini"],["MISTRAL_API_KEY","mistral"],["COHERE_API_KEY","cohere"],["OLLAMA_BASE_URL","ollama"]],a=(process.env.CACHLY_EMBED_PROVIDER??"").toLowerCase();if(a&&a!=="cachly"){const g=f.find(([,d])=>d===a)?.[0];g&&process.env[g]?c(`BYOK: ${a} (key present in ${g})`):r(`CACHLY_EMBED_PROVIDER=${a} but its key env var is not set \u2014 semantic search will fail`)}else{it==="ollama"?c("Local Ollama (OLLAMA_BASE_URL) \u2014 text stays on your machine"):it==="cachly"?c("Server-side embeddings (cachly, EU) \u2014 no key needed, uses your JWT"):r("No embedding provider active \u2014 sign in (CACHLY_JWT) for EU-hosted embeddings; search runs on words until then");for(const[g,d]of f)d!=="ollama"&&process.env[g]&&c(`${g} is set but not used \u2014 ${d} runs only if you name it with CACHLY_EMBED_PROVIDER=${d}`)}}console.log(`
188
+ `),console.log("\u{1F511} Auth token");const g=ee();if(!g)d("No cachly key found (environment or ~/.cachly/credentials.json) \u2014 run: npx @cachly-dev/mcp-server@latest autopilot");else if(g.startsWith("cky_"))c("Long-lived API key set (cky_\u2026) \u2014 no client-side expiry");else try{const m=g.split(".");if(m.length!==3)throw new Error("not a JWT");const r=JSON.parse(Buffer.from(m[1],"base64url").toString("utf-8")),p=r.exp?r.exp*1e3:null,v=p?Math.floor((p-Date.now())/6e4):null;p&&p<Date.now()?d(`JWT expired ${Math.abs(v)} minute(s) ago \u2014 get a new one: ${j("/setup-ai","health")}`):v!==null&&v<30?a(`JWT expires in ${v} minute(s) \u2014 refresh soon at ${j("/setup-ai","health")}`):c(`JWT valid${v!==null?` (expires in ${Math.floor(v/60)}h ${v%60}m)`:""}`)}catch{d("CACHLY_JWT format invalid (expected a cky_ API key or a 3-part JWT)")}console.log(`
189
+ \u{1F310} Brain API`);const l=process.env.CACHLY_API_URL??"https://api.cachly.dev";try{const m=await fetch(`${l}/health`,{signal:AbortSignal.timeout(5e3)});if(m.ok){const r=await m.json();c(`${l} reachable (status: ${r.status??"ok"})`)}else m.status===401||m.status===403?c(`${l} reachable (auth required \u2014 expected)`):d(`${l}/health returned HTTP ${m.status}`)}catch(m){d(`${l} unreachable \u2014 ${m.message}`)}console.log(`
190
+ \u{1F9E0} Brain instance`);const u=J();if(!u)a("No Brain instance found (environment or ~/.cachly/credentials.json) \u2014 will auto-resolve on first tool call");else if(g)try{const m=await fetch(`${l}/api/v1/instances/${u}`,{headers:{Authorization:`Bearer ${g}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(m.ok){const r=await m.json();if(r.status==="running")if(c(`Instance "${r.name}" (${u.slice(0,8)}\u2026) is running`),console.log(`
191
+ \u{1F50C} Redis connectivity`),r.host&&r.port)try{let p,v;try{const T=await fetch(`${l}/api/v1/instances/${u}/connection`,{headers:{Authorization:`Bearer ${g}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(T.ok){const I=await T.json();p=I.password,v=I}}catch{}const w=vt({host:r.host,port:r.port,tls_enabled:r.tls_enabled},v),C=new Xe({host:w.host,port:w.port,password:p,...w.tls?{tls:w.tls}:{},lazyConnect:!0,connectTimeout:5e3,retryStrategy:()=>null});await C.connect();const E=await C.ping();C.disconnect(),E==="PONG"?c(`Redis PING \u2192 PONG (${w.host}:${w.port}, ${w.art==="klartext"?"unencrypted":"TLS"})`):a(`Redis responded but not PONG: ${E}`)}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 ${u.slice(0,8)}\u2026 not found (HTTP ${m.status})`)}catch(m){d(`Could not check instance \u2014 ${m.message}`)}console.log(`
192
+ \u{1F6E0} Editor configs (project dir)`);const h=[{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"},{editor:"Codex",path:".codex/config.toml"},{editor:"Gemini CLI",path:".gemini/settings.json"}];let y=0;for(const{editor:m,path:r}of h){const p=n(s,r);if(e(p))try{const v=await t(p,"utf-8");v.includes("@cachly-dev/mcp-server")||v.includes("cachly")?(c(`${m}: ${r}`),y++):a(`${m}: ${r} exists but cachly not found inside`)}catch{a(`${m}: ${r} exists but could not read`)}}y===0&&d("No editor MCP configs found in this folder \u2014 run: npx @cachly-dev/mcp-server@latest init (add --editor cursor|copilot|codex|gemini if needed)"),console.log(`
193
+ \u{1FA9D} Git hook (ambient learning)`);const x=n(s,".git","hooks","post-commit");if(!e(n(s,".git")))a("Not in a git repository \u2014 skip");else if(e(x))try{(await t(x,"utf-8")).includes("cachly")?c(".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(`
194
+ \u{1F9EC} Embedding provider (semantic search)`);{const m=[["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=m.find(([,v])=>v===r)?.[0];p&&process.env[p]?c(`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{it==="ollama"?c("Local Ollama (OLLAMA_BASE_URL) \u2014 text stays on your machine"):it==="cachly"?c("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,v]of m)v!=="ollama"&&process.env[p]&&c(`${p} is set but not used \u2014 ${v} runs only if you name it with CACHLY_EMBED_PROVIDER=${v}`)}}console.log(`
194
195
  ${"\u2500".repeat(40)}`),i===0?console.log(`\u2705 All checks passed (${o} ok)
195
196
  `):(console.log(`\u274C ${i} check(s) failed, ${o} passed
196
197
  `),console.log(`\u{1F4A1} Fix issues with: npx @cachly-dev/mcp-server@latest autopilot
197
- `),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"),i=a=>{const g=process.argv.indexOf(`--${a}`);return g!==-1?process.argv[g+1]:void 0};v=(i("api-url")??"https://api.cachly.dev").replace(/\/+$/,"");const c=(i("auth-url")??gt).replace(/\/+$/,"");console.log(`
198
+ `),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"),i=r=>{const p=process.argv.indexOf(`--${r}`);return p!==-1?process.argv[p+1]:void 0};_=(i("api-url")??"https://api.cachly.dev").replace(/\/+$/,"");const c=(i("auth-url")??gt).replace(/\/+$/,"");console.log(`
198
199
  \u{1F9E0} cachly \u2014 keep your test Brain in your own account
199
- `),(v!=="https://api.cachly.dev"||c!==gt)&&console.log(`\u26A0\uFE0F Not the cachly servers: API ${v}, sign-in ${c}
200
- `);const r=kn({argument:i("key"),credentials:_e()});r||(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
201
- `),process.exit(1));const u=r.schluessel,m={argument:"--key",credentials:"~/.cachly/credentials.json"}[r.quelle];console.log(`Test key: ${u.slice(0,14)}\u2026 (from ${m})
200
+ `),(_!=="https://api.cachly.dev"||c!==gt)&&console.log(`\u26A0\uFE0F Not the cachly servers: API ${_}, sign-in ${c}
201
+ `);const a=Sn({argument:i("key"),credentials:_e()});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
202
+ `),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})
202
203
  `);let l="";try{console.log(`Step 1: Sign in to your cachly account
203
- `);const a=await Sn(fetch,c);console.log(` Code: \x1B[1;33m${a.userCode}\x1B[0m`),console.log(" Open this URL and confirm the code:"),console.log(`${a.adresse}
204
- `),ae(a.adresse,(g,d)=>{g||console.log(`
205
- \u2139\uFE0F No browser could be opened here (${d??"unknown"}) \u2014 please open the URL yourself.`)}),process.stdout.write(" Waiting for sign-in"),l=await An(fetch,a,{basis:c,puls:()=>process.stdout.write(".")}),console.log(` \x1B[32m\u2713\x1B[0m
206
- `)}catch(a){console.error(`
204
+ `);const r=await An(fetch,c);console.log(` Code: \x1B[1;33m${r.userCode}\x1B[0m`),console.log(" Open this URL and confirm the code:"),console.log(`${r.adresse}
205
+ `),ae(r.adresse,(p,v)=>{p||console.log(`
206
+ \u2139\uFE0F No browser could be opened here (${v??"unknown"}) \u2014 please open the URL yourself.`)}),process.stdout.write(" Waiting for sign-in"),l=await Cn(fetch,r,{basis:c,puls:()=>process.stdout.write(".")}),console.log(` \x1B[32m\u2713\x1B[0m
207
+ `)}catch(r){console.error(`
207
208
 
208
- ${a.message}. Nothing was changed.
209
- `),process.exit(1)}process.stdout.write("Step 2: Moving the test Brain into your account (it restarts once, up to a minute)\u2026");let p;try{p=await Cn(fetch,v,l,u,"mcp",`cachly-mcp/${M}`),console.log(` \x1B[32m\u2713\x1B[0m
210
- `)}catch(a){console.error(`
209
+ ${r.message}. Nothing was changed.
210
+ `),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 Tn(fetch,_,l,d,"mcp",`cachly-mcp/${M}`),console.log(` \x1B[32m\u2713\x1B[0m
211
+ `)}catch(r){console.error(`
211
212
 
212
- ${En(a)}
213
- `),process.exit(1)}y=p.apiKey,oe(p.apiKey),xe(p.instanceId,{apiKey:p.apiKey}),await pe(p.apiKey),await me(p.instanceId);const x=o(),b=new Set([...Object.values(le).map(a=>s(process.cwd(),a)),s(x,".claude.json"),s(x,".claude","mcp.json"),s(x,".cursor","mcp.json"),s(x,".codeium","windsurf","mcp_config.json")]);let w=0;for(const a of b)if(n(a))try{const g=Rn(await e(a,"utf-8"),u,p.apiKey);g.ersetzt&&(await t(a,g.text,"utf-8"),w++)}catch{}const f=await Tn(fetch,v,p.apiKey,p.instanceId);console.log(In(p,f)),console.log(`
214
- New key stored in ~/.cachly/credentials.json${w?` and in ${w} 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.
215
- `),process.exit(0)}const Ae=process.argv[2]==="autopilot";if(process.argv[2]==="autosetup"||process.argv[2]==="setup"||Ae){const{writeFile:e,mkdir:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o,dirname:i}=await import("node:path"),{createInterface:c}=await import("node:readline"),r=Date.now(),u=Ae?"autopilot":"setup";Fo();const m=process.argv.indexOf("--api-url");m!==-1&&process.argv[m+1]&&(v=process.argv[m+1].replace(/\/+$/,""),console.log(`\u2139\uFE0F Using self-hosted backend: ${v}
216
- `)),$("setup_started");const l=process.stdin.isTTY===!0,p=Ae||process.argv.includes("--yes")||process.argv.includes("-y")||!l;Ae?console.log(`\u{1F916} Autopilot \u2014 one-command setup (auth \u2192 instance \u2192 configs \u2192 Brain), zero prompts.
213
+ ${Rn(r)}
214
+ `),process.exit(1)}b=u.apiKey,oe(u.apiKey),xe(u.instanceId,{apiKey:u.apiKey}),await me(u.apiKey),await ge(u.instanceId);const h=o(),y=new Set([...Object.values(le).map(r=>s(process.cwd(),r)),s(h,".claude.json"),s(h,".claude","mcp.json"),s(h,".cursor","mcp.json"),s(h,".codeium","windsurf","mcp_config.json")]);let x=0;for(const r of y)if(n(r))try{const p=jn(await e(r,"utf-8"),d,u.apiKey);p.ersetzt&&(await t(r,p.text,"utf-8"),x++)}catch{}const m=await In(fetch,_,u.apiKey,u.instanceId);console.log(En(u,m)),console.log(`
215
+ New key stored in ~/.cachly/credentials.json${x?` and in ${x} 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.
216
+ `),process.exit(0)}const Ae=process.argv[2]==="autopilot";if(process.argv[2]==="autosetup"||process.argv[2]==="setup"||Ae){const{writeFile:e,mkdir:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o,dirname:i}=await import("node:path"),{createInterface:c}=await import("node:readline"),a=Date.now(),d=Ae?"autopilot":"setup";Fo();const g=process.argv.indexOf("--api-url");g!==-1&&process.argv[g+1]&&(_=process.argv[g+1].replace(/\/+$/,""),console.log(`\u2139\uFE0F Using self-hosted backend: ${_}
217
+ `)),k("setup_started");const l=process.stdin.isTTY===!0,u=Ae||process.argv.includes("--yes")||process.argv.includes("-y")||!l;Ae?console.log(`\u{1F916} Autopilot \u2014 one-command setup (auth \u2192 instance \u2192 configs \u2192 Brain), zero prompts.
217
218
  `):!l&&!process.argv.includes("--yes")&&!process.argv.includes("-y")&&console.log(`\u2139\uFE0F Non-interactive terminal detected \u2014 running in automatic mode (no prompts).
218
- `);const x=c({input:process.stdin,output:process.stdout}),b=(h,A="")=>p?(console.log(`${h}${A}`),Promise.resolve(A)):new Promise(j=>x.question(h,z=>j(z.trim()||A)));console.log(`
219
+ `);const h=c({input:process.stdin,output:process.stdout}),y=(f,A="")=>u?(console.log(`${f}${A}`),Promise.resolve(A)):new Promise(B=>h.question(f,z=>B(z.trim()||A)));console.log(`
219
220
  \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
220
- `);let w=process.env.CACHLY_JWT??"";if(w)console.log(`\u2713 Using token from CACHLY_JWT env var
221
+ `);let x=process.env.CACHLY_JWT??"";if(x)console.log(`\u2713 Using token from CACHLY_JWT env var
221
222
  `);else{console.log(`Step 1: Sign in to cachly (free, no credit card)
222
- `),$("setup_auth_started");let h="",A="",j="",z=5e3,U=!1,de="cachly";try{const G=await fetch(`${v}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({}),signal:AbortSignal.timeout(8e3)});if(G.ok){const N=await G.json();h=N.device_code,A=N.user_code;const D=N.verification_uri||E("/device",u);j=`${D}${D.includes("?")?"&":"?"}code=${encodeURIComponent(A)}`,z=(N.interval??5)*1e3,U=!!h}}catch{}if(!U)try{const N=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(N.ok){const D=await N.json();h=D.device_code,A=D.user_code,j=D.verification_uri_complete,z=(D.interval??5)*1e3,U=!0,de="keycloak"}}catch{}if(U&&h){console.log(` Code: \x1B[1;33m${A}\x1B[0m`),console.log(" Open this URL and confirm the code:"),console.log(`${j}
223
- `),ae(j,(N,D)=>{if(N){$("device_browser_opened",{stelle:"setup"});return}$("device_browser_failed",{reason:D??"unknown",stelle:"setup"}),console.log(` \u2139\uFE0F No browser could be opened here (${D??"unknown"}) \u2014 please open the URL yourself.
224
- `)}),process.stdout.write(" Waiting for authorization");const G=Date.now()+600*1e3;for(;Date.now()<G;){await new Promise(N=>setTimeout(N,z)),process.stdout.write(".");try{let N=null;if(de==="cachly")try{const D=await fetch(`${v}/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:h}),signal:AbortSignal.timeout(8e3)});D.status<500&&(N=await D.json())}catch{}else{const D="https://auth.cachly.dev/realms/cachly/protocol/openid-connect";try{N=await(await fetch(`${D}/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=${h}`,signal:AbortSignal.timeout(8e3)})).json()}catch{}}if(N?.access_token){w=N.access_token,console.log(` \x1B[32m\u2713 Authorized!\x1B[0m
225
- `),$("setup_auth_completed"),$("device_flow_completed");break}N?.error==="slow_down"?z=Math.min(z+2e3,15e3):N?.error&&N.error!=="authorization_pending"&&($("device_flow_failed",{reason:N.error}),console.error(`
223
+ `),k("setup_auth_started");let f="",A="",B="",z=5e3,U=!1,ue="cachly";try{const G=await fetch(`${_}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({}),signal:AbortSignal.timeout(8e3)});if(G.ok){const N=await G.json();f=N.device_code,A=N.user_code;const D=N.verification_uri||j("/device",d);B=`${D}${D.includes("?")?"&":"?"}code=${encodeURIComponent(A)}`,z=(N.interval??5)*1e3,U=!!f}}catch{}if(!U)try{const N=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(N.ok){const D=await N.json();f=D.device_code,A=D.user_code,B=D.verification_uri_complete,z=(D.interval??5)*1e3,U=!0,ue="keycloak"}}catch{}if(U&&f){console.log(` Code: \x1B[1;33m${A}\x1B[0m`),console.log(" Open this URL and confirm the code:"),console.log(`${B}
224
+ `),ae(B,(N,D)=>{if(N){k("device_browser_opened",{stelle:"setup"});return}k("device_browser_failed",{reason:D??"unknown",stelle:"setup"}),console.log(` \u2139\uFE0F No browser could be opened here (${D??"unknown"}) \u2014 please open the URL yourself.
225
+ `)}),process.stdout.write(" Waiting for authorization");const G=Date.now()+600*1e3;for(;Date.now()<G;){await new Promise(N=>setTimeout(N,z)),process.stdout.write(".");try{let N=null;if(ue==="cachly")try{const D=await fetch(`${_}/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:f}),signal:AbortSignal.timeout(8e3)});D.status<500&&(N=await D.json())}catch{}else{const D="https://auth.cachly.dev/realms/cachly/protocol/openid-connect";try{N=await(await fetch(`${D}/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(N?.access_token){x=N.access_token,console.log(` \x1B[32m\u2713 Authorized!\x1B[0m
226
+ `),k("setup_auth_completed"),k("device_flow_completed");break}N?.error==="slow_down"?z=Math.min(z+2e3,15e3):N?.error&&N.error!=="authorization_pending"&&(k("device_flow_failed",{reason:N.error}),console.error(`
226
227
  Auth error: ${N.error}. Aborting.
227
- `),x.close(),process.exit(1))}catch{}}w||($("device_flow_failed",{reason:"timeout"}),console.error(`
228
+ `),h.close(),process.exit(1))}catch{}}x||(k("device_flow_failed",{reason:"timeout"}),console.error(`
228
229
  Timed out waiting for authorization. Aborting.
229
- `),x.close(),process.exit(1)),console.log("")}else{$("device_flow_failed",{reason:"device_flow_unavailable"});const G=E("/setup-ai",u);console.log(` \u26A0\uFE0F Could not start automatic sign-in. Opening browser for web sign-in...
230
+ `),h.close(),process.exit(1)),console.log("")}else{k("device_flow_failed",{reason:"device_flow_unavailable"});const G=j("/setup-ai",d);console.log(` \u26A0\uFE0F Could not start automatic sign-in. Opening browser for web sign-in...
230
231
  `),console.log(` URL: \x1B[36m${G}\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_...)
231
- `),ae(G),p?($("device_flow_failed",{reason:"non_interactive_no_key"}),console.error(`
232
+ `),ae(G),u?(k("device_flow_failed",{reason:"non_interactive_no_key"}),console.error(`
232
233
  \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:
233
234
  `),console.error(` \x1B[1mCACHLY_JWT=cky_live_xxx npx @cachly-dev/mcp-server@latest autopilot\x1B[0m
234
235
  `),console.error(` Or add it to your editor's MCP config under env.CACHLY_JWT.
235
- `),x.close(),process.exit(1)):(w=await b(" Paste API key (cky_live_...): "),w||(console.error(`
236
+ `),h.close(),process.exit(1)):(x=await y(" Paste API key (cky_live_...): "),x||(console.error(`
236
237
  API key is required. Aborting.
237
- `),x.close(),process.exit(1)),$("setup_auth_completed"),console.log(""))}}if(w.startsWith("eyJ")){process.stdout.write("\u23F3 Generating your API key...");try{const h=await fetch(`${v}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`},body:JSON.stringify({name:"cachly-mcp-setup",scope:"read_write"})});if(!h.ok)throw new Error(`HTTP ${h.status}`);const A=await h.json();if(!A.key)throw new Error("no key in response");w=A.key,console.log(` \u2713
238
+ `),h.close(),process.exit(1)),k("setup_auth_completed"),console.log(""))}}if(x.startsWith("eyJ")){process.stdout.write("\u23F3 Generating your API key...");try{const f=await fetch(`${_}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${x}`},body:JSON.stringify({name:"cachly-mcp-setup",scope:"read_write"})});if(!f.ok)throw new Error(`HTTP ${f.status}`);const A=await f.json();if(!A.key)throw new Error("no key in response");x=A.key,console.log(` \u2713
238
239
  `)}catch{console.log(` (skipped)
239
- `)}}process.stdout.write("\u23F3 Fetching your instances...");let f=[];try{const h=await fetch(`${v}/api/v1/instances`,{headers:{Authorization:`Bearer ${w}`}});if(!h.ok)throw new Error(`HTTP ${h.status}`);f=((await h.json()).data??[]).filter(j=>j.status==="running")}catch(h){const A=h.message;console.error(`
240
-
241
- Failed to fetch instances: ${A}`),A.includes("401")&&(console.error(`Token rejected. Get a valid token at ${E("/setup-ai",u)}
242
- `),ae(E("/setup-ai",u))),x.close(),process.exit(1)}if(console.log(` found ${f.length}
243
- `),f.length===0){process.stdout.write("\u23F3 Creating your free Brain instance...");try{const h=await fetch(`${v}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${w}`,"Content-Type":"application/json"}});if(!h.ok)throw new Error(`HTTP ${h.status}`);const A=await h.json();if(A.instance)f=[A.instance];else if(A.instance_id){const j=A.instance_id;console.log(` \u2713 created (${j.slice(0,8)}\u2026)
244
- `),process.stdout.write("\u23F3 Waiting for instance to start");for(let z=0;z<45;z++){await new Promise(U=>setTimeout(U,3e3)),process.stdout.write(".");try{const U=await fetch(`${v}/api/v1/instances/${j}`,{headers:{Authorization:`Bearer ${w}`}});if(U.ok){const de=await U.json();if(de.status==="running"){f=[de];break}}}catch{}}console.log("")}}catch(h){console.log(` failed: ${h.message}
245
- `)}f.length===0&&(console.error(`
246
- Could not create an instance automatically. Opening ${E("/instances",u)} \u2026
247
- `),ae(E("/instances",u)),x.close(),process.exit(1))}const a=f[0];f.length>1&&(console.log(`\u2139\uFE0F Multiple instances found \u2014 using most recent: ${a.name}`),console.log(` (Run with --instance-id <id> to use a different one)
248
- `)),console.log(`\u2713 Instance: ${a.name} (${a.id.slice(0,8)}\u2026)
249
- `),$("setup_instance_ready",{instance_id:a.id});const g=process.cwd(),d=[],{homedir:S}=await import("node:os"),B=S();d.push("claude"),s(o(g,".cursor"))&&d.push("cursor"),s(o(g,".windsurf"))&&d.push("windsurf"),s(o(g,".vscode"))&&d.push("copilot"),s(o(g,".continue"))&&d.push("continue");const I=process.platform==="darwin"?o(B,"Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev"):o(B,".vscode/extensions");(s(I)&&!d.includes("copilot")||s(I))&&d.push("cline");const C=process.platform==="darwin"?o(B,"Library/Application Support/Zed"):o(B,".config/zed");s(C)&&d.push("zed");const T=h=>({claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",copilot:"GitHub Copilot",continue:"Continue.dev",cline:"Cline (VSCode)",zed:"Zed"})[h]??h,R=d;console.log(`\u{1F527} Configuring for: ${R.map(T).join(", ")}
250
- `);const{existsSync:_}=await import("node:fs"),k=[];let P=0;oe(w),xe(a.id,{apiKey:w});for(const h of R){const A=le[h]??".mcp.json",j=o(g,A);try{await t(i(j),{recursive:!0});const z=_(j),U=await Ht(j,w,a.id,h,{readFile:n,existsSync:_});await e(j,U,"utf-8"),console.log(`\u2705 ${z?"Updated":"Written"}: ${A}`),P++}catch(z){const U=z.message;console.log(`\u26A0\uFE0F Could not write ${A}: ${U}`),console.log(" Fix permissions or run with sudo, then re-run setup."),k.push({file:A,reason:U})}}const ne=await Mt(g,a.id);for(const[h,A]of Object.entries(ne)){const{relative:j}=await import("node:path");console.log(Dt(j(g,h)||h,A))}y=w;let F=0;if(s(o(g,".git"))){process.stdout.write("\u23F3 Bootstrapping Brain from git history (~10s)...");try{const h=await W("brain_from_git",{instance_id:a.id,repo_path:g,limit:100});if(h.startsWith("\u274C"))console.log(` (skipped: ${rt(h.replace(/^❌\s*/,"")).split(`
251
- `)[0].slice(0,160)})`);else{const A=h.match(/Ingested: \*\*(\d+)\*\*/);F=A?parseInt(A[1],10):0,console.log(` \u2713 ${F} lesson${F===1?"":"s"} extracted from git history`);const j=Uo(h);j&&(console.log(""),console.log(rt(j)))}}catch(h){console.log(` (skipped: ${h.message.slice(0,80)})`)}}if(F===0){process.stdout.write("\u{1F331} Seeding 16 universal engineering lessons (first recall works instantly)...");try{await W("brain_seed_starter",{instance_id:a.id}),console.log(" \u2713");try{const h=await W("smart_recall",{instance_id:a.id,query:"docker build slow"}),A=Jo(h);A&&(console.log(""),console.log(Wo(A.topic,A.what)))}catch{}}catch(h){console.log(` (skipped: ${h.message.slice(0,60)})`)}}try{const h=await fetch(`${v}/api/v1/instances/${a.id}/memory`,{headers:{Authorization:`Bearer ${w}`},signal:AbortSignal.timeout(6e3)});if(h.ok){const j=(await h.json()).lesson_count??0;console.log(j===0?`
240
+ `)}}process.stdout.write("\u23F3 Fetching your instances...");let m=[];try{const f=await fetch(`${_}/api/v1/instances`,{headers:{Authorization:`Bearer ${x}`}});if(!f.ok)throw new Error(`HTTP ${f.status}`);m=((await f.json()).data??[]).filter(B=>B.status==="running")}catch(f){const A=f.message;console.error(`
241
+
242
+ Failed to fetch instances: ${A}`),A.includes("401")&&(console.error(`Token rejected. Get a valid token at ${j("/setup-ai",d)}
243
+ `),ae(j("/setup-ai",d))),h.close(),process.exit(1)}if(console.log(` found ${m.length}
244
+ `),m.length===0){process.stdout.write("\u23F3 Creating your free Brain instance...");try{const f=await fetch(`${_}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${x}`,"Content-Type":"application/json"}});if(!f.ok)throw new Error(`HTTP ${f.status}`);const A=await f.json();if(A.instance)m=[A.instance];else if(A.instance_id){const B=A.instance_id;console.log(` \u2713 created (${B.slice(0,8)}\u2026)
245
+ `),process.stdout.write("\u23F3 Waiting for instance to start");for(let z=0;z<45;z++){await new Promise(U=>setTimeout(U,3e3)),process.stdout.write(".");try{const U=await fetch(`${_}/api/v1/instances/${B}`,{headers:{Authorization:`Bearer ${x}`}});if(U.ok){const ue=await U.json();if(ue.status==="running"){m=[ue];break}}}catch{}}console.log("")}}catch(f){console.log(` failed: ${f.message}
246
+ `)}m.length===0&&(console.error(`
247
+ Could not create an instance automatically. Opening ${j("/instances",d)} \u2026
248
+ `),ae(j("/instances",d)),h.close(),process.exit(1))}const r=m[0];m.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)
249
+ `)),console.log(`\u2713 Instance: ${r.name} (${r.id.slice(0,8)}\u2026)
250
+ `),k("setup_instance_ready",{instance_id:r.id});const p=process.cwd(),v=[],{homedir:w}=await import("node:os"),C=w();v.push("claude"),s(o(p,".cursor"))&&v.push("cursor"),s(o(p,".windsurf"))&&v.push("windsurf"),s(o(p,".vscode"))&&v.push("copilot"),s(o(p,".continue"))&&v.push("continue");const E=process.platform==="darwin"?o(C,"Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev"):o(C,".vscode/extensions");(s(E)&&!v.includes("copilot")||s(E))&&v.push("cline");const T=process.platform==="darwin"?o(C,"Library/Application Support/Zed"):o(C,".config/zed");s(T)&&v.push("zed");const I=f=>({claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",copilot:"GitHub Copilot",continue:"Continue.dev",cline:"Cline (VSCode)",zed:"Zed"})[f]??f,R=v;console.log(`\u{1F527} Configuring for: ${R.map(I).join(", ")}
251
+ `);const{existsSync:$}=await import("node:fs"),S=[];let P=0;oe(x),xe(r.id,{apiKey:x});for(const f of R){const A=le[f]??".mcp.json",B=o(p,A);try{await t(i(B),{recursive:!0});const z=$(B),U=await Ht(B,x,r.id,f,{readFile:n,existsSync:$});await e(B,U,"utf-8"),console.log(`\u2705 ${z?"Updated":"Written"}: ${A}`),P++}catch(z){const U=z.message;console.log(`\u26A0\uFE0F Could not write ${A}: ${U}`),console.log(" Fix permissions or run with sudo, then re-run setup."),S.push({file:A,reason:U})}}const ne=await Mt(p,r.id);for(const[f,A]of Object.entries(ne)){const{relative:B}=await import("node:path");console.log(Dt(B(p,f)||f,A))}b=x;let F=0;if(s(o(p,".git"))){process.stdout.write("\u23F3 Bootstrapping Brain from git history (~10s)...");try{const f=await W("brain_from_git",{instance_id:r.id,repo_path:p,limit:100});if(f.startsWith("\u274C"))console.log(` (skipped: ${rt(f.replace(/^❌\s*/,"")).split(`
252
+ `)[0].slice(0,160)})`);else{const A=f.match(/Ingested: \*\*(\d+)\*\*/);F=A?parseInt(A[1],10):0,console.log(` \u2713 ${F} lesson${F===1?"":"s"} extracted from git history`);const B=Uo(f);B&&(console.log(""),console.log(rt(B)))}}catch(f){console.log(` (skipped: ${f.message.slice(0,80)})`)}}if(F===0){process.stdout.write("\u{1F331} Seeding 16 universal engineering lessons (first recall works instantly)...");try{await W("brain_seed_starter",{instance_id:r.id}),console.log(" \u2713");try{const f=await W("smart_recall",{instance_id:r.id,query:"docker build slow"}),A=Jo(f);A&&(console.log(""),console.log(Wo(A.topic,A.what)))}catch{}}catch(f){console.log(` (skipped: ${f.message.slice(0,60)})`)}}try{const f=await fetch(`${_}/api/v1/instances/${r.id}/memory`,{headers:{Authorization:`Bearer ${x}`},signal:AbortSignal.timeout(6e3)});if(f.ok){const B=(await f.json()).lesson_count??0;console.log(B===0?`
252
253
  \u{1F9E0} Your Brain is empty. It learns from your fixes and commits from now on.`:`
253
- \u{1F9E0} Your Brain now holds ${j} lesson${j===1?"":"s"}.`)}}catch{}if(!p)try{if(console.log(`
254
- \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 b(" Set yourself as the first admin? (y/N): ","N")).toLowerCase()==="y"){const A=await b(' Your handle (e.g. "alice"): ');A.trim()&&await W("team_assign_role",{instance_id:a.id,handle:A.trim(),role:"admin"}).catch(()=>"")&&(console.log(` \u2705 ${A.trim()} is now admin. Invite teammates:
255
- `),console.log(` team_assign_role(instance_id="${a.id}", handle="<teammate>", role="contributor", assigned_by="${A.trim()}")
254
+ \u{1F9E0} Your Brain now holds ${B} lesson${B===1?"":"s"}.`)}}catch{}if(!u)try{if(console.log(`
255
+ \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 y(" Set yourself as the first admin? (y/N): ","N")).toLowerCase()==="y"){const A=await y(' Your handle (e.g. "alice"): ');A.trim()&&await W("team_assign_role",{instance_id:r.id,handle:A.trim(),role:"admin"}).catch(()=>"")&&(console.log(` \u2705 ${A.trim()} is now admin. Invite teammates:
256
+ `),console.log(` team_assign_role(instance_id="${r.id}", handle="<teammate>", role="contributor", assigned_by="${A.trim()}")
256
257
  `))}else console.log(` Skipped \u2014 run team_assign_role at any time.
257
- `)}catch{}if(!p){const h=await b(" \u{1F4EC} Stay in the loop? Email for release notes [Enter to skip]: ");if(h&&h.includes("@"))try{await fetch(`${v}/api/newsletter/subscribe`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:h.trim().toLowerCase(),source:"mcp-setup"}),signal:AbortSignal.timeout(5e3)}),console.log(` \u2705 Subscribed \u2014 you'll only hear from us when it matters.
258
- `)}catch{}}try{const h=await at(process.cwd(),a.id);h==="written"?console.log(`
259
- \u2705 CLS git hook installed \u2014 your brain will learn from every commit.`):h==="upgraded"?console.log(`
260
- \u2705 CLS git hook upgraded to ${ct}.`):h==="appended"&&console.log(`
261
- \u2705 CLS git hook appended to existing post-commit.`)}catch{}if(R.includes("claude"))try{const h=await ut(process.cwd(),a.id);if(h.settings==="skipped")console.log(`\u26A0\uFE0F .claude/settings.json ${h.grund??"is not valid JSON"} \u2014 left untouched, Ambient Recall hooks not wired`);else{const A=h.scripts==="written"?"\u2705 Written":h.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${pt})`:"\u2713 Unchanged";console.log(`${A}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),h.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):h.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{}R.includes("cursor")&&await be("cursor",process.cwd(),a.id," "),R.includes("copilot")&&await be("copilot",process.cwd(),a.id," "),(s(o(B,".codex"))||s(o(g,".codex")))&&(await be("codex",process.cwd(),a.id," "),await ze("codex",process.cwd(),Q("",a.id)," ")),(s(o(B,".gemini"))||s(o(g,".gemini")))&&(await be("gemini",process.cwd(),a.id," "),await ze("gemini",process.cwd(),Q("",a.id)," ")),y=w;const Ue=Math.round((Date.now()-r)/1e3);if(k.length>0&&$("setup_config_write_failed",{instance_id:a.id,failed:k.length,succeeded:P}),$("setup_completed",{instance_id:a.id,elapsed_s:Ue,config_failures:k.length}),k.length>0&&P===0){console.log(`
258
+ `)}catch{}if(!u){const f=await y(" \u{1F4EC} Stay in the loop? Email for release notes [Enter to skip]: ");if(f&&f.includes("@"))try{await fetch(`${_}/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.
259
+ `)}catch{}}try{const f=await at(process.cwd(),r.id);f==="written"?console.log(`
260
+ \u2705 CLS git hook installed \u2014 your brain will learn from every commit.`):f==="upgraded"?console.log(`
261
+ \u2705 CLS git hook upgraded to ${ct}.`):f==="appended"&&console.log(`
262
+ \u2705 CLS git hook appended to existing post-commit.`)}catch{}if(R.includes("claude"))try{const f=await ut(process.cwd(),r.id);if(f.settings==="skipped")console.log(`\u26A0\uFE0F .claude/settings.json ${f.grund??"is not valid JSON"} \u2014 left untouched, Ambient Recall hooks not wired`);else{const A=f.scripts==="written"?"\u2705 Written":f.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${pt})`:"\u2713 Unchanged";console.log(`${A}: .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{}R.includes("cursor")&&await be("cursor",process.cwd(),r.id," "),R.includes("copilot")&&await be("copilot",process.cwd(),r.id," "),(s(o(C,".codex"))||s(o(p,".codex")))&&(await be("codex",process.cwd(),r.id," "),await ze("codex",process.cwd(),Q("",r.id)," ")),(s(o(C,".gemini"))||s(o(p,".gemini")))&&(await be("gemini",process.cwd(),r.id," "),await ze("gemini",process.cwd(),Q("",r.id)," ")),b=x;const Ue=Math.round((Date.now()-a)/1e3);if(S.length>0&&k("setup_config_write_failed",{instance_id:r.id,failed:S.length,succeeded:P}),k("setup_completed",{instance_id:r.id,elapsed_s:Ue,config_failures:S.length}),S.length>0&&P===0){console.log(`
262
263
  \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(`
263
- Your Brain instance exists, but no editor knows about it yet.`),console.log(" Failed writes:");for(const h of k)console.log(` \u2022 ${h.file} \u2014 ${h.reason}`);console.log(`
264
- Fix the permissions above and re-run, or configure manually:`),console.log(` CACHLY_JWT=${w.slice(0,12)}\u2026 CACHLY_BRAIN_INSTANCE_ID=${a.id}`),console.log(` Docs: ${E("/docs/mcp",u)}
265
- `),x.close(),await new Promise(h=>setTimeout(h,300)),process.exit(1)}if(console.log(`
266
- \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 \u{1F680} Brain is ready. \u2551"),console.log(`\u2551 \u23F1\uFE0F Setup completed in ${(Ue+"s").padEnd(5)} \u2014 restart your editor \u2551`),console.log("\u2551 and your AI arrives pre-briefed every session. \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"),k.length>0){console.log(`
267
- \u26A0\uFE0F Some editor configs could not be written (others succeeded):`);for(const h of k)console.log(` \u2022 ${h.file} \u2014 ${h.reason}`);console.log(" Fix the permissions above and re-run setup to configure them too.")}console.log(`
264
+ Your Brain instance exists, but no editor knows about it yet.`),console.log(" Failed writes:");for(const f of S)console.log(` \u2022 ${f.file} \u2014 ${f.reason}`);console.log(`
265
+ Fix the permissions above and re-run, or configure manually:`),console.log(` CACHLY_JWT=${x.slice(0,12)}\u2026 CACHLY_BRAIN_INSTANCE_ID=${r.id}`),console.log(` Docs: ${j("/docs/mcp",d)}
266
+ `),h.close(),await new Promise(f=>setTimeout(f,300)),process.exit(1)}if(console.log(`
267
+ \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 \u{1F680} Brain is ready. \u2551"),console.log(`\u2551 \u23F1\uFE0F Setup completed in ${(Ue+"s").padEnd(5)} \u2014 restart your editor \u2551`),console.log("\u2551 and your AI arrives pre-briefed every session. \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"),S.length>0){console.log(`
268
+ \u26A0\uFE0F Some editor configs could not be written (others succeeded):`);for(const f of S)console.log(` \u2022 ${f.file} \u2014 ${f.reason}`);console.log(" Fix the permissions above and re-run setup to configure them too.")}console.log(`
268
269
  \u{1F449} Next: restart your editor, start a new chat and ask:`),console.log(" What does my cachly Brain know about this project?"),console.log(` Your AI should call the cachly tool smart_recall and answer from your Brain.
269
- `),console.log(` Dashboard: ${E(`/instances/${a.id}`,u)}`),console.log(` Step-by-step guide: ${E("/docs/setup",u)}
270
- `),x.close(),await new Promise(h=>setTimeout(h,300)),process.exit(0)}if(process.argv[2]==="index"){const{resolve:e}=await import("node:path"),t=process.argv.slice(3),n=r=>{const u=t.indexOf(`--${r}`);return u!==-1?t[u+1]:void 0},s=e(n("dir")??t.find(r=>!r.startsWith("--"))??"."),o=n("instance-id")||J(),i=parseInt(n("max-files")??"500",10),c=n("namespace")??"cachly:sem:code";(!o||!y)&&(console.error(`
270
+ `),console.log(` Dashboard: ${j(`/instances/${r.id}`,d)}`),console.log(` Step-by-step guide: ${j("/docs/setup",d)}
271
+ `),h.close(),await new Promise(f=>setTimeout(f,300)),process.exit(0)}if(process.argv[2]==="index"){const{resolve:e}=await import("node:path"),t=process.argv.slice(3),n=a=>{const d=t.indexOf(`--${a}`);return d!==-1?t[d+1]:void 0},s=e(n("dir")??t.find(a=>!a.startsWith("--"))??"."),o=n("instance-id")||J(),i=parseInt(n("max-files")??"500",10),c=n("namespace")??"cachly:sem:code";(!o||!b)&&(console.error(`
271
272
  \u274C No Brain instance or key found (flag, environment or ~/.cachly/credentials.json)
272
273
  `),console.error(" export CACHLY_BRAIN_INSTANCE_ID=<uuid>"),console.error(" export CACHLY_JWT=<cky_live_...>"),console.error(` npx @cachly-dev/mcp-server@latest index ./my-project
273
274
  `),process.exit(1)),console.log(`
274
275
  \u{1F4C2} Indexing: ${s}`),console.log(` Instance: ${o.slice(0,8)}\u2026 Max files: ${i}
275
- `);try{const r=await W("index_project",{instance_id:o,dir:s,max_files:i,ttl:604800,namespace:c});console.log(r),console.log(`
276
+ `);try{const a=await W("index_project",{instance_id:o,dir:s,max_files:i,ttl:604800,namespace:c});console.log(a),console.log(`
276
277
  \u2705 Indexing complete.
277
- `)}catch(r){console.error(`
278
- \u274C Indexing failed: ${r.message}
279
- `),process.exit(1)}process.exit(0)}if(process.argv[2]==="learn-git"){const{resolve:e}=await import("node:path"),t=process.argv.slice(3),n=c=>{const r=t.indexOf(`--${c}`);return r!==-1?t[r+1]:void 0},s=e(n("dir")??t.find(c=>!c.startsWith("--"))??"."),o=n("instance-id")||J(),i=parseInt(n("max-commits")??"50",10);(!o||!y)&&(console.error(`
278
+ `)}catch(a){console.error(`
279
+ \u274C Indexing failed: ${a.message}
280
+ `),process.exit(1)}process.exit(0)}if(process.argv[2]==="learn-git"){const{resolve:e}=await import("node:path"),t=process.argv.slice(3),n=c=>{const a=t.indexOf(`--${c}`);return a!==-1?t[a+1]:void 0},s=e(n("dir")??t.find(c=>!c.startsWith("--"))??"."),o=n("instance-id")||J(),i=parseInt(n("max-commits")??"50",10);(!o||!b)&&(console.error(`
280
281
  \u274C No Brain instance or key found (flag, environment or ~/.cachly/credentials.json)
281
282
  `),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 .
282
283
  `),process.exit(1)),console.log(`
283
284
  \u{1F9E0} Learning from git history: ${s}`),console.log(` Instance: ${o.slice(0,8)}\u2026 Max commits: ${i}
284
- `);try{const c=await W("brain_from_git",{instance_id:o,repo_path:s,limit:i});console.log(c),$("brain_from_git",{api_key:y,instance_id:o}),console.log(`
285
+ `);try{const c=await W("brain_from_git",{instance_id:o,repo_path:s,limit:i});console.log(c),k("brain_from_git",{api_key:b,instance_id:o}),console.log(`
285
286
  \u2705 Brain learned from your commits.
286
- `),await new Promise(r=>setTimeout(r,300))}catch(c){console.error(`
287
+ `),await new Promise(a=>setTimeout(a,300))}catch(c){console.error(`
287
288
  \u274C learn-git failed: ${c.message}
288
- `),process.exit(1)}process.exit(0)}if(process.argv[2]==="ambient-recall"&&await pn(process.argv.slice(3),process.argv[1]),process.argv[2]==="ambient-auffrischen"&&await mn(),process.argv[2]===fn&&await gn(process.argv[3]??""),process.argv[2]==="ambient-credit"){try{const e=Math.round(Number(process.argv[3]));if(Number.isFinite(e)&&e>0){const t=Math.min(e,2e4),n=process.argv.slice(4).join(" ").slice(0,200)||void 0,s={ts:new Date().toISOString(),event:"credit",injected:0,prevented:t,note:n,instanz:J()||void 0};await yn(s),await fs(process.env.CACHLY_BRAIN_INSTANCE_ID??L,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=J(),t=vn(await mt(),e||void 0),n=t.eigene,s=ls(n),o=n.slice(-5);if(console.log(`
289
+ `),process.exit(1)}process.exit(0)}if(process.argv[2]==="ambient-recall"&&await mn(process.argv.slice(3),process.argv[1]),process.argv[2]==="ambient-auffrischen"&&await gn(),process.argv[2]===hn&&await fn(process.argv[3]??""),process.argv[2]==="ambient-credit"){try{const e=Math.round(Number(process.argv[3]));if(Number.isFinite(e)&&e>0){const t=Math.min(e,2e4),n=process.argv.slice(4).join(" ").slice(0,200)||void 0,s={ts:new Date().toISOString(),event:"credit",injected:0,prevented:t,note:n,instanz:J()||void 0};await bn(s),await ys(process.env.CACHLY_BRAIN_INSTANCE_ID??L,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=J(),t=xn(await mt(),e||void 0),n=t.eigene,s=us(n),o=n.slice(-5);if(console.log(`
289
290
  \u{1F9E0} Ambient Recall \u2014 net-token ledger
290
291
  `),console.log(` Instance: ${e?`${e.slice(0,8)}\u2026`:"(none set \u2014 showing every entry on this computer)"}`),console.log(` Turns recorded: ${n.length}`),console.log(` Injected tokens: ${s.injected}`),console.log(` Prevented tokens: ${s.prevented} (agent-reported via ambient-credit)`),console.log(` NET: ${s.net>=0?"+":""}${s.net} tokens`),o.length>0){console.log(`
291
292
  Last entries:`);for(const i of o){const c=i.prevented>0?`+${i.prevented} prevented`:`-${i.injected} injected`;console.log(` \u2022 ${i.ts.slice(0,19)} ${i.event}: ${c}${i.note?` (${i.note})`:""}`)}}(t.ohneInstanz>0||t.andereInstanzen>0)&&(console.log(`
292
- Not counted above:`),t.ohneInstanz>0&&console.log(` \u2022 ${t.ohneInstanz} older entries without an instance (before 0.10.207)`),t.andereInstanzen>0&&console.log(` \u2022 entries of ${t.andereInstanzen} other instance${t.andereInstanzen===1?"":"s"} on this computer`)),console.log(""),process.exit(0)}if(process.argv[2]==="uninstall"){const{homedir:e,tmpdir:t}=await import("node:os"),{resolve:n}=await import("node:path"),{createInterface:s}=await import("node:readline/promises"),o=process.argv.slice(3),c={projekt:n((r=>{const u=o.indexOf(`--${r}`);return u!==-1?o[u+1]:void 0})("project-dir")??"."),heim:process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??e(),tmp:t(),schluessel:ee(),instanz:J(),apiUrl:v,istTty:process.stdin.isTTY===!0&&process.stdout.isTTY===!0,ausgabe:r=>console.log(r),frage:async r=>{const u=s({input:process.stdin,output:process.stdout});try{return/^(y|yes|j|ja)$/i.test((await u.question(r)).trim())}finally{u.close()}}};process.exit(await tn(o,c))}if(process.argv[2]==="doctor"){const{checkNodeVersion:e,checkCredential:t,checkApiReachable:n,checkAuthAccepted:s,checkInstance:o,checkVectorCoverage:i,inspectAmbientHooks:c,checkHooks:r,checkLedger:u,renderDoctorReport:m,doctorExitCode:l}=await import("./doctor.js"),p=[e(),t(y),await n(v),await s(v,y),o(J()||L),await i(v,y,J()||L),r(c(process.cwd())),u(await mt(),bn())];console.log(m(p)),process.exit(l(p))}if(process.argv[2]==="cls-ingest"){try{const e=process.argv[3];(!e||!y)&&process.exit(0);let t;try{t=JSON.parse(e)}catch{process.exit(0)}const n=t.instance_id??L;(!n||!t.source)&&process.exit(0),await W("cls_ingest",{instance_id:n,source:t.source,payload:t.payload??{}})}catch{}process.exit(0)}if(!y){const e=Ft();if(e)try{const t=await fetch(Kt(e),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:Yt(e),signal:AbortSignal.timeout(8e3)});if(t.ok){const n=await t.json();n.access_token&&(y=n.access_token,ce(n.access_token),$("m2m_auth_completed",{grant:"client_credentials",client_id:e.clientId}),process.stderr.write(`\u{1F916} cachly: authenticated via client_credentials (M2M, headless).
293
+ Not counted above:`),t.ohneInstanz>0&&console.log(` \u2022 ${t.ohneInstanz} older entries without an instance (before 0.10.207)`),t.andereInstanzen>0&&console.log(` \u2022 entries of ${t.andereInstanzen} other instance${t.andereInstanzen===1?"":"s"} on this computer`)),console.log(""),process.exit(0)}if(process.argv[2]==="uninstall"){const{homedir:e,tmpdir:t}=await import("node:os"),{resolve:n}=await import("node:path"),{createInterface:s}=await import("node:readline/promises"),o=process.argv.slice(3),c={projekt:n((a=>{const d=o.indexOf(`--${a}`);return d!==-1?o[d+1]:void 0})("project-dir")??"."),heim:process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??e(),tmp:t(),schluessel:ee(),instanz:J(),apiUrl:_,istTty:process.stdin.isTTY===!0&&process.stdout.isTTY===!0,ausgabe:a=>console.log(a),frage:async a=>{const d=s({input:process.stdin,output:process.stdout});try{return/^(y|yes|j|ja)$/i.test((await d.question(a)).trim())}finally{d.close()}}};process.exit(await on(o,c))}if(process.argv[2]==="doctor"){const{checkNodeVersion:e,checkCredential:t,checkApiReachable:n,checkAuthAccepted:s,checkInstance:o,checkVectorCoverage:i,inspectAmbientHooks:c,checkHooks:a,checkLedger:d,renderDoctorReport:g,doctorExitCode:l}=await import("./doctor.js"),u=[e(),t(b),await n(_),await s(_,b),o(J()||L),await i(_,b,J()||L),a(c(process.cwd())),d(await mt(),wn())];console.log(g(u)),process.exit(l(u))}if(process.argv[2]==="cls-ingest"){try{const e=process.argv[3];(!e||!b)&&process.exit(0);let t;try{t=JSON.parse(e)}catch{process.exit(0)}const n=t.instance_id??L;(!n||!t.source)&&process.exit(0),await W("cls_ingest",{instance_id:n,source:t.source,payload:t.payload??{}})}catch{}process.exit(0)}if(!b){const e=Ft();if(e)try{const t=await fetch(Kt(e),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:Yt(e),signal:AbortSignal.timeout(8e3)});if(t.ok){const n=await t.json();n.access_token&&(b=n.access_token,ce(n.access_token),k("m2m_auth_completed",{grant:"client_credentials",client_id:e.clientId}),process.stderr.write(`\u{1F916} cachly: authenticated via client_credentials (M2M, headless).
293
294
  `))}else process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth failed (${t.status}). Check CACHLY_CLIENT_ID / CACHLY_CLIENT_SECRET.
294
- `),$("m2m_auth_failed",{status:t.status})}catch(t){process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth error: ${t.message}
295
- `),$("m2m_auth_failed",{reason:"network"})}}const js=["demo","share","publish","health","autosetup","setup","autopilot","init","digest","invite","badge","join","upgrade","bench","tool-specs","openapi","ambient-credit","ambient-stats","doctor","uninstall"];if(!y&&!js.includes(process.argv[2]??""))if(!process.argv[2]&&process.stdout.isTTY===!0&&eo){const s=`
295
+ `),k("m2m_auth_failed",{status:t.status})}catch(t){process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth error: ${t.message}
296
+ `),k("m2m_auth_failed",{reason:"network"})}}const Ls=["demo","share","publish","health","autosetup","setup","autopilot","init","digest","invite","badge","join","upgrade","bench","tool-specs","openapi","ambient-credit","ambient-stats","doctor","uninstall"];if(!b&&!Ls.includes(process.argv[2]??""))if(!process.argv[2]&&process.stdout.isTTY===!0&&eo){const s=`
296
297
  \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
297
298
  \u2551 \u{1F9E0} cachly AI Brain \u2014 Setup required \u2551
298
299
  \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
299
300
  \u2551 \u2551
300
301
  \u2551 CACHLY_JWT is not set. Get your free credentials at: \u2551
301
302
  \u2551 \u2551
302
- `+(`\u2551 \u{1F449} ${E("/setup-ai","first-run")}`.padEnd(66)+`\u2551
303
+ `+(`\u2551 \u{1F449} ${j("/setup-ai","first-run")}`.padEnd(66)+`\u2551
303
304
  `)+`\u2551 \u2551
304
305
  \u2551 Then run the one-command setup wizard: \u2551
305
306
  \u2551 \u2551
@@ -312,15 +313,15 @@ Could not create an instance automatically. Opening ${E("/instances",u)} \u2026
312
313
  \u{1F9E0} cachly: no API key yet \u2014 the first cachly tool call creates a test Brain on EU servers, no sign-up.
313
314
  (Own account: npx @cachly-dev/mcp-server@latest autopilot)
314
315
 
315
- `);else{const e=Ut(y);if(e!==null){const t=Math.floor((e-Date.now())/6e4);t<=0?process.stderr.write(`
316
+ `);else{const e=Ut(b);if(e!==null){const t=Math.floor((e-Date.now())/6e4);t<=0?process.stderr.write(`
316
317
  \u26A0\uFE0F cachly: CACHLY_JWT expired ${Math.abs(t)} minute(s) ago.
317
- All tool calls will fail. Get a fresh token at ${E("/setup-ai","jwt-expiry")}
318
+ All tool calls will fail. Get a fresh token at ${j("/setup-ai","jwt-expiry")}
318
319
 
319
320
  `):t<60&&process.stderr.write(`
320
321
  \u26A0\uFE0F cachly: CACHLY_JWT expires in ${t} minute(s).
321
- Refresh it soon at ${E("/setup-ai","jwt-expiry")} to avoid interruptions.
322
+ Refresh it soon at ${j("/setup-ai","jwt-expiry")} to avoid interruptions.
322
323
 
323
- `)}}process.env.PORT||Gn({aktuelle:qn(M)});const Ce=process.env.PORT?parseInt(process.env.PORT,10):void 0;if(Ce){const{createServer:e}=await import("node:http");e((n,s)=>{const o=new URL(n.url??"/",`http://localhost:${Ce}`);if(o.pathname==="/health"){s.writeHead(200,{"Content-Type":"application/json"}),s.end(JSON.stringify({status:"ok",version:M,zeroResults:{total:Eo,last10:Io.slice(-10).map(i=>({query:i.query,ts:new Date(i.ts).toISOString()}))}}));return}if(o.pathname==="/mcp"||o.pathname==="/"){(async()=>{const i=As(),c=new oo({sessionIdGenerator:void 0});s.on("close",()=>{c.close().catch(()=>{}),i.close().catch(()=>{})});try{await i.connect(c),await c.handleRequest(n,s)}catch(r){process.stderr.write(`cachly-mcp HTTP: ${r.message}
324
- `),s.headersSent||(s.writeHead(500,{"Content-Type":"application/json"}),s.end(JSON.stringify({error:r.message})))}})();return}s.writeHead(404),s.end("not found")}).listen(Ce,()=>{process.stderr.write(`cachly-mcp HTTP server listening on :${Ce}
325
- `)})}else{const e=new to;Y("start: Module geladen, stdio verbinden"),await q.connect(e),typeof process.argv[2]=="string"&&!process.argv[2].startsWith("-")||(et=!0,Dn(()=>Kn(tt)),co(),Xn(),Zn(process.stdin,n=>{process.stderr.write(`[cachly-mcp] ${n} \u2014 session over, server exits too
326
- `),(async()=>{await De().catch(()=>{});for(const[,s]of te)await s.quit().catch(()=>{});process.exit(0)})()}))}Fe("cachly","startup",{version:M,mode:process.env.MCP_HTTP_PORT?"http":"stdio"}).catch(()=>{});export{Ko as CLAUDE_MD_MARKER_END,Yo as CLAUDE_MD_MARKER_START,To as CROSS_LINGUAL_MAP,le as EDITOR_FILES,ko as STOPWORDS,Dt as anweisungsZeile,Ao as arabicLightStem,lt as buildClaudeMdBlock,Is as buildMcpConfig,Q as buildServerEnv,Co as expandCrossLingual,$o as extractTimestamp,So as katakanaToRomaji,xo as levenshtein,Ts as mcpAddBefehl,Ht as mergeMcpConfig,_o as recencyBoost,Ro as reconnectOnce,vo as splitMultiQuery,fo as startBackgroundDevicePoll,wo as tokenize,Mt as writeInstructions};
324
+ `)}}process.env.PORT||Vn({aktuelle:Gn(M)});const Ce=process.env.PORT?parseInt(process.env.PORT,10):void 0;if(Ce){const{createServer:e}=await import("node:http");e((n,s)=>{const o=new URL(n.url??"/",`http://localhost:${Ce}`);if(o.pathname==="/health"){s.writeHead(200,{"Content-Type":"application/json"}),s.end(JSON.stringify({status:"ok",version:M,zeroResults:{total:Eo,last10:Io.slice(-10).map(i=>({query:i.query,ts:new Date(i.ts).toISOString()}))}}));return}if(o.pathname==="/mcp"||o.pathname==="/"){(async()=>{const i=Ts(),c=new oo({sessionIdGenerator:void 0});s.on("close",()=>{c.close().catch(()=>{}),i.close().catch(()=>{})});try{await i.connect(c),await c.handleRequest(n,s)}catch(a){process.stderr.write(`cachly-mcp HTTP: ${a.message}
325
+ `),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(Ce,()=>{process.stderr.write(`cachly-mcp HTTP server listening on :${Ce}
326
+ `)})}else{const e=new to;Y("start: Module geladen, stdio verbinden"),await q.connect(e),typeof process.argv[2]=="string"&&!process.argv[2].startsWith("-")||(et=!0,zn(()=>qn(tt)),co(),es(),Qn(process.stdin,n=>{process.stderr.write(`[cachly-mcp] ${n} \u2014 session over, server exits too
327
+ `),(async()=>{await De().catch(()=>{});for(const[,s]of te)await s.quit().catch(()=>{});process.exit(0)})()}))}Fe("cachly","startup",{version:M,mode:process.env.MCP_HTTP_PORT?"http":"stdio"}).catch(()=>{});export{qo as CLAUDE_MD_MARKER_END,Ko as CLAUDE_MD_MARKER_START,To as CROSS_LINGUAL_MAP,le as EDITOR_FILES,ko as STOPWORDS,Dt as anweisungsZeile,Ao as arabicLightStem,lt as buildClaudeMdBlock,Rs as buildMcpConfig,Q as buildServerEnv,Co as expandCrossLingual,$o as extractTimestamp,So as katakanaToRomaji,xo as levenshtein,Es as mcpAddBefehl,Ht as mergeMcpConfig,_o as recencyBoost,Ro as reconnectOnce,vo as splitMultiQuery,fo as startBackgroundDevicePoll,wo as tokenize,Mt as writeInstructions};