@cachly-dev/mcp-server 0.10.172 → 0.10.174

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import{setzeClientKennung as yt}from"./herkunft.js";import{jwtExpiryMs as bt,checkJwt as vt,handleApiError as xt,diagnoseAuth as ge,planAuthHeal as Ae,readClientCredentialsFromEnv as wt,buildClientCredentialsBody as _t,clientCredentialsTokenUrl as $t}from"./auth.js";import{cachlyUrl as N}from"./cachly-url.js";import{nutzungsSchluessel as Ct}from"./werkzeug-nutzung.js";import{istLieferung as At,lieferSchluessel as St,tokenDerAntwort as kt,hatTreffer as Tt,trefferSchluessel as Se}from"./geliefert.js";import{notify as ke}from"./notifier.js";import{fileURLToPath as It}from"node:url";import{createRequire as Et}from"node:module";import{execFile as fe}from"node:child_process";const Rt=process.argv[1]!=null&&(process.argv[1]===It(import.meta.url)||process.argv[1].endsWith("/dist/index.js")||process.argv[1].endsWith("/src/index.ts"));import{Server as Te}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Nt}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as Lt}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{CallToolRequestSchema as Ie,ErrorCode as te,ListPromptsRequestSchema as Ee,ListResourceTemplatesRequestSchema as Re,ListResourcesRequestSchema as Ne,ListToolsRequestSchema as Le,McpError as Z}from"@modelcontextprotocol/sdk/types.js";import{Redis as Be}from"ioredis";let w=process.env.CACHLY_API_URL??"https://api.cachly.dev",x=we()??"";const dn=process.env.CACHLY_EMBED_MODEL??"",M=(()=>{try{const e=Et(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"})(),Bt=Number(process.env.CACHLY_PROVISION_TIMEOUT_MS??9e4);let B=process.env.CACHLY_BRAIN_INSTANCE_ID??"",Q=0,se=null;async function jt(){if(!x)return"";try{const e=await fetch(`${w}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${x}`,"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(`${w}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${x}`},body:JSON.stringify({event:"auto_provision_failed",status:e.status,version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}catch{fetch(`${w}/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 je(){if(B)return B;if(!x){const t=await vo({apiUrl:w,version:M});return t?(x=t.apiKey,B=t.instanzId,Q=0,ye(t.instanzId),B):""}if(se)return se;const e=Date.now();if(Q>0&&e-Q<3e4)return"";Q=e,se=(async()=>{try{const t=await fetch(`${w}/api/v1/instances`,{headers:{Authorization:`Bearer ${x}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(t.ok){const s=(await t.json())?.data??[],o=s.find(r=>r.status==="running")??s.find(r=>r.status==="provisioning");if(o)return B=o.id,Q=0,B;const a=await jt();if(a)return B=a,Q=0,ye(a),B}}catch{}return""})();try{return await se}finally{se=null}}let he=0;const Pt=6e4;let oe="";async function Pe(e){try{const{writeFile:t,mkdir:n,readFile:s}=await import("node:fs/promises"),{existsSync:o}=await import("node:fs"),{resolve:a,dirname:r}=await import("node:path"),i=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!i)return;const p=a(i,".claude","mcp.json");let l={};if(o(p))try{l=JSON.parse(await s(p,"utf-8"))}catch{}l.mcpServers??={};const d=l.mcpServers.cachly;if(d)d.env??={},d.env.CACHLY_JWT=e;else{const h={};h.CACHLY_JWT=e,l.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:h}}await n(r(p),{recursive:!0}),await t(p,JSON.stringify(l,null,2),"utf-8");const f=[a(i,".cursor","mcp.json"),a(i,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(f.map(async h=>{if(o(h))try{const v=await s(h,"utf-8"),y=JSON.parse(v),u=y?.mcpServers?.cachly;u?.env&&(u.env.CACHLY_JWT=e,await t(h,JSON.stringify(y,null,2),"utf-8"))}catch{}}))}catch{}}async function ye(e){if(e)try{const{writeFile:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),a=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!a)return;const r=[o(a,".claude","mcp.json"),o(a,".cursor","mcp.json"),o(a,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(r.map(async i=>{if(s(i))try{const p=JSON.parse(await n(i,"utf-8")),l=p?.mcpServers?.cachly;l?.env&&(l.env.CACHLY_BRAIN_INSTANCE_ID=e,await t(i,JSON.stringify(p,null,2),"utf-8"))}catch{}}))}catch{}}async function Ht(){try{const e=await fetch(`${w}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${x}`},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?(x=t.key,ve(t.key),Pe(t.key),C("auth_self_healed",{reason:"near_expiry_refresh"}),!0):!1}catch{return!1}}async function be(){const e=ge(x),t=Ae(e);if(t==="none")return oe="",!0;if(t==="refresh"){const n=Date.now();return n-he>=Pt&&(he=n,await Ht())?(oe="",!0):(oe=e.message,e.usable)}return oe=e.message,!1}function ie(e,t){const n=(o,a)=>{try{t?.(o,a)}catch{}},s=o=>{o?n(!1,o.code??o.message):n(!0)};try{process.platform==="win32"?fe("cmd",["/c","start","",e],{windowsHide:!0},s):process.platform==="darwin"?fe("open",[e],s):fe("xdg-open",[e],s)}catch(o){n(!1,o instanceof Error?o.message:"unknown")}}let G=null;async function Ot(){try{const e=await fetch(`${w}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({}),signal:AbortSignal.timeout(8e3)});if(e.ok){const t=await e.json(),n=t.verification_uri||N("/device","ambient-signin"),s=`${n}${n.includes("?")?"&":"?"}code=${encodeURIComponent(t.user_code)}`;return{deviceCode:t.device_code,userCode:t.user_code,verifyUrl:s,pollInterval:(t.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}}catch{}try{const t=await fetch("https://auth.cachly.dev/realms/cachly/protocol/openid-connect/auth/device",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"client_id=cachly-cli&scope=openid",signal:AbortSignal.timeout(8e3)});if(!t.ok)return null;const n=await t.json();return{deviceCode:n.device_code,userCode:n.user_code,verifyUrl:n.verification_uri_complete,pollInterval:(n.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}catch{return null}}async function Dt(e){if(Date.now()>e.deadline)return"expired";const t=async()=>{const s=await fetch(`${w}/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 a=await fetch(`${w}/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(a.ok){const r=await a.json();r.key&&(o=r.key)}}catch{}if(x=o,ve(o),G=null,C("device_flow_completed"),Pe(o),ne(o),Q=0,await je(),B)try{const a=await fetch(`${w}/api/v1/instances/${B}`,{headers:{Authorization:`Bearer ${x}`,Accept:"application/json"},signal:AbortSignal.timeout(4e3)});if(a.ok){const r=await a.json();if(r.status==="provisioning"){const i=Date.now()+2e4;for(;r.status==="provisioning"&&Date.now()<i;){await new Promise(l=>setTimeout(l,3e3));const p=await fetch(`${w}/api/v1/instances/${B}`,{headers:{Authorization:`Bearer ${x}`,Accept:"application/json"},signal:AbortSignal.timeout(4e3)}).catch(()=>null);if(p?.ok){const l=await p.json();r.status=l.status}else break}}}}catch{}return B&&ye(B),"done"}return s.error==="slow_down"&&(e.pollInterval=Math.min(e.pollInterval+2e3,15e3)),"pending"}catch{return"pending"}}async function He(e){if(e.polling)return"pending";e.polling=!0;try{return await Dt(e)}finally{e.polling=!1}}function Mt(e,t=He,n=o=>G===o,s=Yt){const o=async()=>{if(!n(e))return;let a="pending";try{a=await t(e)}catch{}if(a!=="done"){if(a==="expired"){n(e)&&(G=null);return}n(e)&&s(o,e.pollInterval)}};s(o,e.pollInterval)}function Yt(e,t){const n=setTimeout(e,t);typeof n.unref=="function"&&n.unref()}import{setEmbedJwt as ve}from"./embeddings.js";import{tokenize as Jt,splitMultiQuery as Ut,levenshtein as Wt,recencyBoost as Ft,extractTimestamp as zt,STOPWORDS as qt,katakanaToRomaji as Gt,arabicLightStem as Kt,expandCrossLingual as Vt,CROSS_LINGUAL_MAP as Zt,ZERO_RESULTS_LOG as Qt,zeroResultsTotal as Xt}from"./search.js";const K=new Map;function eo(e){return e<=1?200:null}async function U(e){if(!e)throw new Z(te.InvalidRequest,`\u23F3 Your Brain instance is still being set up.
2
+ import{setzeClientKennung as ht}from"./herkunft.js";import{jwtExpiryMs as yt,checkJwt as bt,handleApiError as vt,diagnoseAuth as fe,planAuthHeal as Ce,readClientCredentialsFromEnv as xt,buildClientCredentialsBody as wt,clientCredentialsTokenUrl as _t}from"./auth.js";import{cachlyUrl as N}from"./cachly-url.js";import{nutzungsSchluessel as $t}from"./werkzeug-nutzung.js";import{istLieferung as Ct,lieferSchluessel as At,tokenDerAntwort as St,hatTreffer as kt,trefferSchluessel as Ae}from"./geliefert.js";import{notify as Se}from"./notifier.js";import{fileURLToPath as Tt}from"node:url";import{createRequire as It}from"node:module";import{execFile as he}from"node:child_process";const Et=process.argv[1]!=null&&(process.argv[1]===Tt(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 Rt}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as Nt}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{CallToolRequestSchema as Te,ErrorCode as te,ListPromptsRequestSchema as Ie,ListResourceTemplatesRequestSchema as Ee,ListResourcesRequestSchema as Re,ListToolsRequestSchema as Ne,McpError as Z}from"@modelcontextprotocol/sdk/types.js";import{Redis as Le}from"ioredis";let w=process.env.CACHLY_API_URL??"https://api.cachly.dev",v=pe()??"";const cn=process.env.CACHLY_EMBED_MODEL??"",M=(()=>{try{const e=It(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"})(),Lt=Number(process.env.CACHLY_PROVISION_TIMEOUT_MS??9e4);let B=process.env.CACHLY_BRAIN_INSTANCE_ID??"",Q=0,se=null;async function Bt(){if(!v)return"";try{const e=await fetch(`${w}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${v}`,"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(`${w}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${v}`},body:JSON.stringify({event:"auto_provision_failed",status:e.status,version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}catch{fetch(`${w}/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 Be(){if(B)return B;if(!v){const t=await yo({apiUrl:w,version:M});return t?(v=t.apiKey,B=t.instanzId,Q=0,be(t.instanzId),B):""}if(se)return se;const e=Date.now();if(Q>0&&e-Q<3e4)return"";Q=e,se=(async()=>{try{const t=await fetch(`${w}/api/v1/instances`,{headers:{Authorization:`Bearer ${v}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(t.ok){const s=(await t.json())?.data??[],o=s.find(r=>r.status==="running")??s.find(r=>r.status==="provisioning");if(o)return B=o.id,Q=0,B;const a=await Bt();if(a)return B=a,Q=0,be(a),B}}catch{}return""})();try{return await se}finally{se=null}}let ye=0;const jt=6e4;let oe="";async function je(e){try{const{writeFile:t,mkdir:n,readFile:s}=await import("node:fs/promises"),{existsSync:o}=await import("node:fs"),{resolve:a,dirname:r}=await import("node:path"),i=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!i)return;const p=a(i,".claude","mcp.json");let l={};if(o(p))try{l=JSON.parse(await s(p,"utf-8"))}catch{}l.mcpServers??={};const d=l.mcpServers.cachly;if(d)d.env??={},d.env.CACHLY_JWT=e;else{const h={};h.CACHLY_JWT=e,l.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:h}}await n(r(p),{recursive:!0}),await t(p,JSON.stringify(l,null,2),"utf-8");const f=[a(i,".cursor","mcp.json"),a(i,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(f.map(async h=>{if(o(h))try{const x=await s(h,"utf-8"),y=JSON.parse(x),u=y?.mcpServers?.cachly;u?.env&&(u.env.CACHLY_JWT=e,await t(h,JSON.stringify(y,null,2),"utf-8"))}catch{}}))}catch{}}async function be(e){if(e)try{const{writeFile:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),a=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!a)return;const r=[o(a,".claude","mcp.json"),o(a,".cursor","mcp.json"),o(a,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(r.map(async i=>{if(s(i))try{const p=JSON.parse(await n(i,"utf-8")),l=p?.mcpServers?.cachly;l?.env&&(l.env.CACHLY_BRAIN_INSTANCE_ID=e,await t(i,JSON.stringify(p,null,2),"utf-8"))}catch{}}))}catch{}}async function Pt(){try{const e=await fetch(`${w}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${v}`},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?(v=t.key,xe(t.key),je(t.key),C("auth_self_healed",{reason:"near_expiry_refresh"}),!0):!1}catch{return!1}}async function ve(){const e=fe(v),t=Ce(e);if(t==="none")return oe="",!0;if(t==="refresh"){const n=Date.now();return n-ye>=jt&&(ye=n,await Pt())?(oe="",!0):(oe=e.message,e.usable)}return oe=e.message,!1}function ie(e,t){const n=(o,a)=>{try{t?.(o,a)}catch{}},s=o=>{o?n(!1,o.code??o.message):n(!0)};try{process.platform==="win32"?he("cmd",["/c","start","",e],{windowsHide:!0},s):process.platform==="darwin"?he("open",[e],s):he("xdg-open",[e],s)}catch(o){n(!1,o instanceof Error?o.message:"unknown")}}let G=null;async function Ht(){try{const e=await fetch(`${w}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({}),signal:AbortSignal.timeout(8e3)});if(e.ok){const t=await e.json(),n=t.verification_uri||N("/device","ambient-signin"),s=`${n}${n.includes("?")?"&":"?"}code=${encodeURIComponent(t.user_code)}`;return{deviceCode:t.device_code,userCode:t.user_code,verifyUrl:s,pollInterval:(t.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}}catch{}try{const t=await fetch("https://auth.cachly.dev/realms/cachly/protocol/openid-connect/auth/device",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"client_id=cachly-cli&scope=openid",signal:AbortSignal.timeout(8e3)});if(!t.ok)return null;const n=await t.json();return{deviceCode:n.device_code,userCode:n.user_code,verifyUrl:n.verification_uri_complete,pollInterval:(n.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}catch{return null}}async function Ot(e){if(Date.now()>e.deadline)return"expired";const t=async()=>{const s=await fetch(`${w}/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 a=await fetch(`${w}/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(a.ok){const r=await a.json();r.key&&(o=r.key)}}catch{}if(v=o,xe(o),G=null,C("device_flow_completed"),je(o),ne(o),Q=0,await Be(),B)try{const a=await fetch(`${w}/api/v1/instances/${B}`,{headers:{Authorization:`Bearer ${v}`,Accept:"application/json"},signal:AbortSignal.timeout(4e3)});if(a.ok){const r=await a.json();if(r.status==="provisioning"){const i=Date.now()+2e4;for(;r.status==="provisioning"&&Date.now()<i;){await new Promise(l=>setTimeout(l,3e3));const p=await fetch(`${w}/api/v1/instances/${B}`,{headers:{Authorization:`Bearer ${v}`,Accept:"application/json"},signal:AbortSignal.timeout(4e3)}).catch(()=>null);if(p?.ok){const l=await p.json();r.status=l.status}else break}}}}catch{}return B&&be(B),"done"}return s.error==="slow_down"&&(e.pollInterval=Math.min(e.pollInterval+2e3,15e3)),"pending"}catch{return"pending"}}async function Pe(e){if(e.polling)return"pending";e.polling=!0;try{return await Ot(e)}finally{e.polling=!1}}function Dt(e,t=Pe,n=o=>G===o,s=Mt){const o=async()=>{if(!n(e))return;let a="pending";try{a=await t(e)}catch{}if(a!=="done"){if(a==="expired"){n(e)&&(G=null);return}n(e)&&s(o,e.pollInterval)}};s(o,e.pollInterval)}function Mt(e,t){const n=setTimeout(e,t);typeof n.unref=="function"&&n.unref()}import{setEmbedJwt as xe}from"./embeddings.js";import{tokenize as Yt,splitMultiQuery as Jt,levenshtein as Ut,recencyBoost as Wt,extractTimestamp as Ft,STOPWORDS as zt,katakanaToRomaji as qt,arabicLightStem as Gt,expandCrossLingual as Kt,CROSS_LINGUAL_MAP as Vt,ZERO_RESULTS_LOG as Zt,zeroResultsTotal as Qt}from"./search.js";const K=new Map;function Xt(e){return e<=1?200:null}async function U(e){if(!e)throw new Z(te.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.`);if(K.has(e))return K.get(e);let t=await O(`/api/v1/instances/${e}`);if(t.status==="provisioning"){const r=Date.now()+Bt;for(;t.status==="provisioning"&&Date.now()<r;)await new Promise(i=>setTimeout(i,3e3)),t=await O(`/api/v1/instances/${e}`)}if(t.status!=="running"){fetch(`${w}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...x?{Authorization:`Bearer ${x}`}:{}},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.`);if(K.has(e))return K.get(e);let t=await O(`/api/v1/instances/${e}`);if(t.status==="provisioning"){const r=Date.now()+Lt;for(;t.status==="provisioning"&&Date.now()<r;)await new Promise(i=>setTimeout(i,3e3)),t=await O(`/api/v1/instances/${e}`)}if(t.status!=="running"){fetch(`${w}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...v?{Authorization:`Bearer ${v}`}:{}},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.
10
10
 
11
11
  First-time provisioning typically takes 1\u20133 minutes. Please retry in a moment \u2014 the instance will be ready soon.`:t.status==="failed"?r=`\u274C Brain instance "${t.name}" failed to start.
12
12
 
@@ -18,20 +18,20 @@ Update your payment method at: ${N("/billing","upgrade")}`:t.status==="pending_p
18
18
  Complete your checkout at: ${N("/instances","upgrade")}`:r=`Brain instance "${t.name}" is not reachable (status: ${t.status}).
19
19
 
20
20
  \u2022 View your instance at: ${N("/instances","instance-error")}
21
- \u2022 Run \`get_api_status\` for a full diagnostic.`,new Z(te.InvalidRequest,r)}if(!t.host||!t.port)throw new Z(te.InternalError,`Instance "${t.name}" is running but has no host/port \u2014 contact support@cachly.dev.`);let n,s=t.tls_enabled!==!1;try{const r=await O(`/api/v1/instances/${e}/connection`);n=r.password??void 0,s=r.tls_enabled!==!1}catch(r){const i=r instanceof Error?r.message:String(r);if(i.includes("401")||i.includes("403")||i.includes("Unauthorized"))throw new Z(te.InvalidRequest,"API key rejected \u2014 run `cachly setup` to refresh your credentials.")}const o=new Be({host:t.host,port:t.port,password:n||void 0,commandTimeout:8e3,...s?{tls:{}}:{},lazyConnect:!0,enableReadyCheck:!0,connectTimeout:8e3,retryStrategy:eo,maxRetriesPerRequest:1,keepAlive:15e3}),a=()=>{K.delete(e),o.disconnect()};o.on("error",a),o.on("end",a);try{await o.connect()}catch(r){o.disconnect();const i=r instanceof Error?r.message:String(r);throw fetch(`${w}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...x?{Authorization:`Bearer ${x}`}:{}},body:JSON.stringify({event:"redis_connect_failed",instance_id:e,host:t.host,port:t.port,error:i,version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{}),new Z(te.InternalError,`Could not reach Brain instance "${t.name}" (${t.host}:${t.port}).
21
+ \u2022 Run \`get_api_status\` for a full diagnostic.`,new Z(te.InvalidRequest,r)}if(!t.host||!t.port)throw new Z(te.InternalError,`Instance "${t.name}" is running but has no host/port \u2014 contact support@cachly.dev.`);let n,s=t.tls_enabled!==!1;try{const r=await O(`/api/v1/instances/${e}/connection`);n=r.password??void 0,s=r.tls_enabled!==!1}catch(r){const i=r instanceof Error?r.message:String(r);if(i.includes("401")||i.includes("403")||i.includes("Unauthorized"))throw new Z(te.InvalidRequest,"API key rejected \u2014 run `cachly setup` to refresh your credentials.")}const o=new Le({host:t.host,port:t.port,password:n||void 0,commandTimeout:8e3,...s?{tls:{}}:{},lazyConnect:!0,enableReadyCheck:!0,connectTimeout:8e3,retryStrategy:Xt,maxRetriesPerRequest:1,keepAlive:15e3}),a=()=>{K.delete(e),o.disconnect()};o.on("error",a),o.on("end",a);try{await o.connect()}catch(r){o.disconnect();const i=r instanceof Error?r.message:String(r);throw fetch(`${w}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...v?{Authorization:`Bearer ${v}`}:{}},body:JSON.stringify({event:"redis_connect_failed",instance_id:e,host:t.host,port:t.port,error:i,version:M}),signal:AbortSignal.timeout(3e3)}).catch(()=>{}),new Z(te.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: ${i}`)}return K.set(e,o),o}async function O(e,t={},n=!1){n||Ae(ge(x))!=="none"&&await be(),vt(x);const s=Number(process.env.CACHLY_API_TIMEOUT_MS??15e3),o=await fetch(`${w}${e}`,{...t,signal:AbortSignal.timeout(s),headers:{"Content-Type":"application/json",Authorization:`Bearer ${x}`,...t.headers}});if(!o.ok){if(o.status===401&&!n&&(he=0,await be()))return O(e,t,!0);const r=(await o.json().catch(()=>({error:o.statusText}))).error??o.statusText;xt(o.status,r)}if(o.status!==204)return o.json()}import{handleBrainTool as to}from"./handlers/brain.js";import{handleContextTool as oo}from"./handlers/context.js";import{handleInstanceTool as no}from"./handlers/instances.js";import{handleCacheTool as so}from"./handlers/cache.js";import{handleTeamTool as io}from"./handlers/team.js";import{handleRoadmapTool as ro}from"./handlers/roadmap.js";import{handleAdvancedTool as ao}from"./handlers/advanced.js";import{handleSyndicateTool as co}from"./handlers/syndicate.js";import{handleFedbrainTool as Oe,_lastBrainFromGitCounts as de}from"./handlers/fedbrain.js";import{extractFirstRecallProof as lo,renderFirstRecallProof as po}from"./first-recall-proof.js";import{installClsPostCommitHook as De,CLS_HOOK_VERSION as Me}from"./cls-hook.js";import{installAmbientHooks as Ye,AMBIENT_HOOK_VERSION as Je}from"./ambient-hooks.js";import{runAmbient as uo,parseHookPayload as Ue,stopObservation as mo}from"./ambient-cli.js";import{stopAntwort as go}from"./schreibbeleg.js";import{appendLedgerEntry as We,readLedger as xe,defaultLedgerPath as fo}from"./ambient-ledger.js";import{loadAmbientMemory as ho,saveAmbientMemory as yo}from"./ambient-memory.js";import{buildAmbientDeps as bo}from"./ambient-deps.js";import{resolveApiKey as we,saveApiKey as ne}from"./credentials.js";import{holeSofortTest as vo}from"./sofort-test.js";import{beiStdinEnde as xo}from"./stdin-ende.js";import{merkeWerkzeugAufruf as wo,starteBrandWachhund as _o}from"./brand-wachhund.js";import{sichtbareWerkzeuge as $o,VERTEILER as Fe}from"./werkzeug-auswahl.js";import{buildLessonsMarkdown as Co,buildLessonsJsonl as Ao,vonRohLektion as So}from"./brain-export.js";import{detectEditor as ko}from"./editor.js";import{milestoneSent as ze,markMilestoneSent as qe}from"./funnel-milestones.js";import{kostprobeUebrig as To,kostprobeVerbrauchen as Io,kostprobeHinweis as Eo,schrankeNachKostproben as Ro}from"./kostprobe.js";import{netBalance as No,shouldBackoff as Ge}from"./ambient-recall.js";import{handleShareTool as Ke}from"./handlers/share.js";import{handleVizTool as Lo}from"./handlers/viz.js";import{TOOLS as re}from"./tools.js";let Ve=!1,pe=!1;function Ze(){return ko()}function Bo(e){if(!e)return null;const t=e.match(/\*\*💡\s+([^*]+)\*\*/),n=e.match(/^>\s+(.+)$/m);if(!t||!n)return null;const s=t[1].trim(),o=n[1].trim();return!s||!o?null:{topic:s,what:o}}function jo(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 C(e,t,n){if(process.env.CACHLY_NO_TELEMETRY==="1")return;const s=x?jo(x):void 0;fetch(`${w}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:e,version:M,editor:Ze(),...x?{jwt:x}:{},...s?{user_fingerprint:s}:{},...n?{metrics:n}:{},...t}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}function Qe(e,t){return!e||!x||process.env.CACHLY_NO_TELEMETRY==="1"?Promise.resolve():fetch(`${w}/api/v1/instances/${e}/ambient-events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${x}`},body:JSON.stringify({events:[t]}),signal:AbortSignal.timeout(3e3)}).then(()=>{},()=>{})}async function Po(e){if(!Ve&&process.env.CACHLY_NO_TELEMETRY!=="1"){Ve=!0;try{await fetch(`${w}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"first_call_no_jwt",version:M,editor:Ze(),tool:e}),signal:AbortSignal.timeout(3e3)})}catch{}}}const Ho=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"]),Oo={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."},Xe=N("/billing","upgrade"),et=new Map;async function Do(e){const t=et.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 et.set(e,{info:o,expiresAt:Date.now()+6e4}),o}catch{return{tier:"unknown",isFree:!1}}}async function Mo(e,t){if(!Ho.has(e)||!t)return null;const{isFree:n}=await Do(t);if(!n)return null;const s=Oo[e]??"A Premium intelligence feature.";if(To(e)){const o=Io(e);return{kostprobe:Eo(e,o,Xe)}}return{sperre:Ro(e,s,Xe)}}async function Yo(e,t){try{await(await U(e)).hincrby(Ct(e),t,1)}catch{}}async function Jo(e,t,n){if(At(t))try{const s=await U(e),o=Tt(n);await s.incrby(St(e),o?kt(n):0),await s.hincrby(Se(e),"abrufe",1),o&&await s.hincrby(Se(e),"treffer",1)}catch{}}async function F(e,t){if(!x){if(Po(e),G){const b=await He(G);return b==="done"?F(e,t):b==="expired"?(C("device_flow_failed",{reason:"timeout"}),G=null,"\u231B **Authentication timed out.** Please call any tool again to restart the sign-in flow."):["\u23F3 **Signing you in\u2026**","",`Finish in your browser: **${G.verifyUrl}**`,`Code: **${G.userCode}**`,"","This completes automatically once you sign in \u2014 no need to come back here."].join(`
26
- `)}const c=await Ot();return c?(G=c,C("device_flow_started",{tool:e}),ie(c.verifyUrl,(b,g)=>{if(b){C("device_browser_opened",{stelle:"tool"});return}C("device_browser_failed",{reason:g??"unknown",stelle:"tool"}),process.stderr.write(`
25
+ \u2022 Technical detail: ${i}`)}return K.set(e,o),o}async function O(e,t={},n=!1){n||Ce(fe(v))!=="none"&&await ve(),bt(v);const s=Number(process.env.CACHLY_API_TIMEOUT_MS??15e3),o=await fetch(`${w}${e}`,{...t,signal:AbortSignal.timeout(s),headers:{"Content-Type":"application/json",Authorization:`Bearer ${v}`,...t.headers}});if(!o.ok){if(o.status===401&&!n&&(ye=0,await ve()))return O(e,t,!0);const r=(await o.json().catch(()=>({error:o.statusText}))).error??o.statusText;vt(o.status,r)}if(o.status!==204)return o.json()}import{handleBrainTool as eo}from"./handlers/brain.js";import{handleContextTool as to}from"./handlers/context.js";import{handleInstanceTool as oo}from"./handlers/instances.js";import{handleCacheTool as no}from"./handlers/cache.js";import{handleTeamTool as so}from"./handlers/team.js";import{handleRoadmapTool as io}from"./handlers/roadmap.js";import{handleAdvancedTool as ro}from"./handlers/advanced.js";import{handleSyndicateTool as ao}from"./handlers/syndicate.js";import{handleFedbrainTool as He,_lastBrainFromGitCounts as de}from"./handlers/fedbrain.js";import{extractFirstRecallProof as co,renderFirstRecallProof as lo}from"./first-recall-proof.js";import{installClsPostCommitHook as Oe,CLS_HOOK_VERSION as De}from"./cls-hook.js";import{installAmbientHooks as Me,AMBIENT_HOOK_VERSION as Ye}from"./ambient-hooks.js";import{runEinblendung as po,parseHookPayload as Je,stopObservation as uo}from"./ambient-cli.js";import{holeBestand as mo}from"./einblendung.js";import{stopAntwort as go}from"./schreibbeleg.js";import{rahmeAntwort as fo}from"./antwort-rahmen.js";import{appendLedgerEntry as Ue,readLedger as We,defaultLedgerPath as ho}from"./ambient-ledger.js";import{resolveApiKey as pe,saveApiKey as ne}from"./credentials.js";import{holeSofortTest as yo}from"./sofort-test.js";import{beiStdinEnde as bo}from"./stdin-ende.js";import{merkeWerkzeugAufruf as vo,starteBrandWachhund as xo}from"./brand-wachhund.js";import{sichtbareWerkzeuge as wo,VERTEILER as Fe}from"./werkzeug-auswahl.js";import{buildLessonsMarkdown as _o,buildLessonsJsonl as $o,vonRohLektion as Co}from"./brain-export.js";import{detectEditor as Ao}from"./editor.js";import{milestoneSent as ze,markMilestoneSent as qe}from"./funnel-milestones.js";import{kostprobeUebrig as So,kostprobeVerbrauchen as ko,kostprobeHinweis as To,schrankeNachKostproben as Io}from"./kostprobe.js";import{netBalance as Eo}from"./ambient-recall.js";import{handleShareTool as Ge}from"./handlers/share.js";import{handleVizTool as Ro}from"./handlers/viz.js";import{TOOLS as re}from"./tools.js";let Ke=!1,ue=!1;function Ve(){return Ao()}function No(e){if(!e)return null;const t=e.match(/\*\*💡\s+([^*]+)\*\*/),n=e.match(/^>\s+(.+)$/m);if(!t||!n)return null;const s=t[1].trim(),o=n[1].trim();return!s||!o?null:{topic:s,what:o}}function Lo(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 C(e,t,n){if(process.env.CACHLY_NO_TELEMETRY==="1")return;const s=v?Lo(v):void 0;fetch(`${w}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:e,version:M,editor:Ve(),...v?{jwt:v}:{},...s?{user_fingerprint:s}:{},...n?{metrics:n}:{},...t}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}function Ze(e,t){return!e||!v||process.env.CACHLY_NO_TELEMETRY==="1"?Promise.resolve():fetch(`${w}/api/v1/instances/${e}/ambient-events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${v}`},body:JSON.stringify({events:[t]}),signal:AbortSignal.timeout(3e3)}).then(()=>{},()=>{})}async function Bo(e){if(!Ke&&process.env.CACHLY_NO_TELEMETRY!=="1"){Ke=!0;try{await fetch(`${w}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"first_call_no_jwt",version:M,editor:Ve(),tool:e}),signal:AbortSignal.timeout(3e3)})}catch{}}}const jo=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"]),Po={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."},Qe=N("/billing","upgrade"),Xe=new Map;async function Ho(e){const t=Xe.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 Xe.set(e,{info:o,expiresAt:Date.now()+6e4}),o}catch{return{tier:"unknown",isFree:!1}}}async function Oo(e,t){if(!jo.has(e)||!t)return null;const{isFree:n}=await Ho(t);if(!n)return null;const s=Po[e]??"A Premium intelligence feature.";if(So(e)){const o=ko(e);return{kostprobe:To(e,o,Qe)}}return{sperre:Io(e,s,Qe)}}async function Do(e,t){try{await(await U(e)).hincrby($t(e),t,1)}catch{}}async function Mo(e,t,n){if(Ct(t))try{const s=await U(e),o=kt(n);await s.incrby(At(e),o?St(n):0),await s.hincrby(Ae(e),"abrufe",1),o&&await s.hincrby(Ae(e),"treffer",1)}catch{}}async function F(e,t){if(!v){if(Bo(e),G){const b=await Pe(G);return b==="done"?F(e,t):b==="expired"?(C("device_flow_failed",{reason:"timeout"}),G=null,"\u231B **Authentication timed out.** Please call any tool again to restart the sign-in flow."):["\u23F3 **Signing you in\u2026**","",`Finish in your browser: **${G.verifyUrl}**`,`Code: **${G.userCode}**`,"","This completes automatically once you sign in \u2014 no need to come back here."].join(`
26
+ `)}const c=await Ht();return c?(G=c,C("device_flow_started",{tool:e}),ie(c.verifyUrl,(b,g)=>{if(b){C("device_browser_opened",{stelle:"tool"});return}C("device_browser_failed",{reason:g??"unknown",stelle:"tool"}),process.stderr.write(`
27
27
  cachly: could not open a browser (${g??"unknown"}).
28
28
  cachly: open this yourself to finish signing in:
29
29
  cachly: ${c.verifyUrl}
30
30
  cachly: code ${c.userCode}
31
31
 
32
- `)}),Mt(c),["\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} **${c.verifyUrl}**`,"",`Code: **${c.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 Free forever \xB7 No credit card \xB7 ${re.length} MCP tools \xB7 GDPR \xB7 EU servers`].join(`
32
+ `)}),Dt(c),["\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} **${c.verifyUrl}**`,"",`Code: **${c.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 Free forever \xB7 No credit card \xB7 ${re.length} MCP tools \xB7 GDPR \xB7 EU servers`].join(`
33
33
  `)):["\u{1F9E0} **cachly AI Brain \u2014 Setup required**","","Run the setup wizard once in your terminal:"," ```"," npx @cachly-dev/mcp-server@latest autopilot"," ```","",`Or get your API key at: ${N("/setup-ai","ambient-signin")}`,"","\u2728 Free tier includes: 1 Brain instance, persistent memory, semantic search."].join(`
34
- `)}if(!t.instance_id){const c=await je();c&&(t={...t,instance_id:c})}const n=await Mo(e,t.instance_id);let s="";if(n!==null){if("sperre"in n)return C("premium_gate_hit",{tool:e,instance_id:t.instance_id??""}),n.sperre;s=n.kostprobe,C("premium_taste_used",{tool:e,instance_id:t.instance_id??""})}typeof t.instance_id=="string"&&t.instance_id&&Yo(t.instance_id,e);const o=await to(e,t,U,O);if(o!==null){typeof t.instance_id=="string"&&t.instance_id&&Jo(t.instance_id,e,String(o??"")),!pe&&x&&(pe=!0,ze("first_call_success")||(qe("first_call_success"),C("first_call_success",{tool:e,instance_id:t.instance_id??B??""})));const c=t.instance_id??B??"",b=x?{api_key:x,instance_id:c}:{instance_id:c};if(e==="recall_best_solution")C("recall_best_solution",b);else if(e==="learn_from_attempts")C("learn_from_attempts",b);else if(e==="session_start"){C("session_start",b,{born_at:void 0,recalls_total:void 0,starter_seeded:!1});const g=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),E=g.includes("Welcome! Your AI Brain is live.");if(!E&&g.length>100)C("recall_best_solution",b);else if(E&&t.workspace_path)try{const j=await Oe("brain_from_git",{instance_id:c,repo_path:t.workspace_path,limit:50},U,O);if(j!==null){C("brain_from_git",{...b,...de??{}}),C("recall_best_solution",b);let $="";if((de?.total??0)===0)try{const T=await Ke("brain_seed_starter",{instance_id:c},U,O);T&&(C("brain_seed_starter",{...b,auto:!0},{seeded_count:16,auto:!0}),$=`
34
+ `)}if(!t.instance_id){const c=await Be();c&&(t={...t,instance_id:c})}const n=await Oo(e,t.instance_id);let s="";if(n!==null){if("sperre"in n)return C("premium_gate_hit",{tool:e,instance_id:t.instance_id??""}),n.sperre;s=n.kostprobe,C("premium_taste_used",{tool:e,instance_id:t.instance_id??""})}typeof t.instance_id=="string"&&t.instance_id&&Do(t.instance_id,e);const o=await eo(e,t,U,O);if(o!==null){typeof t.instance_id=="string"&&t.instance_id&&Mo(t.instance_id,e,String(o??"")),!ue&&v&&(ue=!0,ze("first_call_success")||(qe("first_call_success"),C("first_call_success",{tool:e,instance_id:t.instance_id??B??""})));const c=t.instance_id??B??"",b=v?{api_key:v,instance_id:c}:{instance_id:c};if(e==="recall_best_solution")C("recall_best_solution",b);else if(e==="learn_from_attempts")C("learn_from_attempts",b);else if(e==="session_start"){C("session_start",b,{born_at:void 0,recalls_total:void 0,starter_seeded:!1});const g=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),E=g.includes("Welcome! Your AI Brain is live.");if(!E&&g.length>100)C("recall_best_solution",b);else if(E&&t.workspace_path)try{const j=await He("brain_from_git",{instance_id:c,repo_path:t.workspace_path,limit:50},U,O);if(j!==null){C("brain_from_git",{...b,...de??{}}),C("recall_best_solution",b);let $="";if((de?.total??0)===0)try{const T=await Ge("brain_seed_starter",{instance_id:c},U,O);T&&(C("brain_seed_starter",{...b,auto:!0},{seeded_count:16,auto:!0}),$=`
35
35
  ---
36
36
  `+String(T))}catch{}const k=String(j),I=de?.total??0,H=I>0?`
37
37
  \u2705 **Brain bootstrapped from git \u2014 ${I} lesson${I===1?"":"s"} loaded.** Your AI already knows your history.`:"";if(k||$||H)return String(o)+H+`
@@ -42,8 +42,8 @@ cachly: code ${c.userCode}
42
42
  > Run \`brain_from_git(instance_id="`+c+'", 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")C("session_end",b);else if(e==="smart_recall"){const g=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),E=g.length>50&&!g.includes("No lessons found")&&!g.includes("no lessons")&&!g.includes("No matches found");if(C("smart_recall",b,{hit:E,topic:String(t.query??"").slice(0,80)}),E&&C("recall_best_solution",b),oe&&typeof o=="string")return`> \u26A0\uFE0F **Brain auth degraded** \u2014 ${oe.split(`
43
43
  `)[0]}
44
44
 
45
- ${o}`}return o}const a=await oo(e,t,U,O);if(a!==null)return!pe&&x&&(pe=!0,ze("first_call_success")||(qe("first_call_success"),C("first_call_success",{tool:e,instance_id:t.instance_id??B??""}))),a;const r=await no(e,t,U,O);if(r!==null)return r;const i=await so(e,t,U,O);if(i!==null)return i;const p=c=>s?c+s:c,l=await io(e,t,U,O);if(l!==null)return p(l);const d=await ro(e,t,U,O);if(d!==null)return d;const f=await ao(e,t,U,O);if(f!==null)return p(f);const h=await co(e,t,U,O);if(h!==null){if(e==="brain_predict"){const c=t.instance_id??B??"";C("brain_predict",x?{api_key:x,instance_id:c}:{instance_id:c})}return p(h)}const v=await Ke(e,t,U,O);if(v!==null)return v;const y=await Lo(e,t,U,O);if(y!==null)return y;const u=await Oe(e,t,U,O);if(u!==null){const c=t.instance_id??B??"",b=x?{api_key:x,instance_id:c}:{instance_id:c};if(e==="brain_from_git"){const g=de;C("brain_from_git",{...b,...g??{}},g?{fixes:g.fixes,features:g.features,refactors:g.refactors,total:g.total}:void 0)}else e==="brain_predict_failures"&&C("brain_predict_failures",b);return u}switch(e){case"get_api_status":{let c="unknown";try{const A=await fetch(`${w}/health`,{signal:AbortSignal.timeout(8e3)});if(A.ok){const $=await A.json();c=`${$.status??"ok"} (db: ${$.db??"?"})`}else c=`HTTP ${A.status}`}catch(A){c=`unreachable: ${A.message}`}if(!x)return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${w}`,` \u{1F493} Health: ${c}`," \u{1F511} Auth: \u274C CACHLY_JWT not set","",`\u{1F4A1} Get your API token at ${N("/instances","api-status")} \u2192 Settings \u2192 API Token`].join(`
46
- `);let b="\u274C invalid JWT format";try{const A=x.split(".");if(A.length===3){const $=JSON.parse(Buffer.from(A[1],"base64url").toString("utf-8")),k=$.sub??"(unknown)",I=$.iss??"(unknown)",H=I.includes("keycloak")?"Keycloak":"OIDC",T=$.exp?new Date($.exp*1e3):null,D=T?T<new Date:!1;b=["\u2705 JWT decoded",` Sub (user ID): ${k}`,` Provider: ${H}`,` Issuer: ${I}`,` Expires: ${T?T.toISOString():"never"} ${D?"\u26A0\uFE0F EXPIRED \u2013 get a new token!":"\u2705"}`].join(`
45
+ ${o}`}return o}const a=await to(e,t,U,O);if(a!==null)return!ue&&v&&(ue=!0,ze("first_call_success")||(qe("first_call_success"),C("first_call_success",{tool:e,instance_id:t.instance_id??B??""}))),a;const r=await oo(e,t,U,O);if(r!==null)return r;const i=await no(e,t,U,O);if(i!==null)return i;const p=c=>s?c+s:c,l=await so(e,t,U,O);if(l!==null)return p(l);const d=await io(e,t,U,O);if(d!==null)return d;const f=await ro(e,t,U,O);if(f!==null)return p(f);const h=await ao(e,t,U,O);if(h!==null){if(e==="brain_predict"){const c=t.instance_id??B??"";C("brain_predict",v?{api_key:v,instance_id:c}:{instance_id:c})}return p(h)}const x=await Ge(e,t,U,O);if(x!==null)return x;const y=await Ro(e,t,U,O);if(y!==null)return y;const u=await He(e,t,U,O);if(u!==null){const c=t.instance_id??B??"",b=v?{api_key:v,instance_id:c}:{instance_id:c};if(e==="brain_from_git"){const g=de;C("brain_from_git",{...b,...g??{}},g?{fixes:g.fixes,features:g.features,refactors:g.refactors,total:g.total}:void 0)}else e==="brain_predict_failures"&&C("brain_predict_failures",b);return u}switch(e){case"get_api_status":{let c="unknown";try{const A=await fetch(`${w}/health`,{signal:AbortSignal.timeout(8e3)});if(A.ok){const $=await A.json();c=`${$.status??"ok"} (db: ${$.db??"?"})`}else c=`HTTP ${A.status}`}catch(A){c=`unreachable: ${A.message}`}if(!v)return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${w}`,` \u{1F493} Health: ${c}`," \u{1F511} Auth: \u274C CACHLY_JWT not set","",`\u{1F4A1} Get your API token at ${N("/instances","api-status")} \u2192 Settings \u2192 API Token`].join(`
46
+ `);let b="\u274C invalid JWT format";try{const A=v.split(".");if(A.length===3){const $=JSON.parse(Buffer.from(A[1],"base64url").toString("utf-8")),k=$.sub??"(unknown)",I=$.iss??"(unknown)",H=I.includes("keycloak")?"Keycloak":"OIDC",T=$.exp?new Date($.exp*1e3):null,D=T?T<new Date:!1;b=["\u2705 JWT decoded",` Sub (user ID): ${k}`,` Provider: ${H}`,` Issuer: ${I}`,` Expires: ${T?T.toISOString():"never"} ${D?"\u26A0\uFE0F EXPIRED \u2013 get a new token!":"\u2705"}`].join(`
47
47
  `)}}catch{b="\u274C JWT decode failed \u2013 check CACHLY_JWT format"}let g="";try{const $=(await O("/api/v1/instances")).data??[];if($.length===0)g=`
48
48
 
49
49
  \u{1F9E0} **Brain Instances:** none \u2014 create one at ${N("/instances","api-status")}`;else{const k=[`
@@ -51,19 +51,19 @@ ${o}`}return o}const a=await oo(e,t,U,O);if(a!==null)return!pe&&x&&(pe=!0,ze("fi
51
51
  \u{1F9E0} **Brain Instances:**`];for(const I of $){const H=I.status==="running"?"\u{1F7E2}":I.status==="provisioning"?"\u{1F7E1}":"\u{1F534}",T=I.id===B?" \u2190 active":"";if(k.push(` ${H} **${I.name}** (\`${I.id}\`) \xB7 ${I.status}${T}`),I.status==="running"&&I.host){const D=K.get(I.id);if(D)try{await D.ping(),k.push(" \u{1F493} Redis: connected")}catch{k.push(" \u26A0\uFE0F Redis: pooled but ping failed \u2014 will reconnect on next use")}else k.push(" \u{1F4A4} Redis: not connected yet (connects on first tool use)")}else I.status==="provisioning"?k.push(" \u23F3 Still provisioning \u2014 check back in ~30 s"):I.status!=="running"&&k.push(` \u274C Not reachable (status: ${I.status})`)}g=k.join(`
52
52
  `)}}catch(A){g=`
53
53
 
54
- \u{1F9E0} **Brain Instances:** could not fetch \u2014 ${A.message}`}await be();const E=ge(x),j=E.state==="long_lived"?"\u{1F6E1}\uFE0F Self-healing: \u2705 long-lived API key (won't expire silently)":E.state==="healthy"?`\u{1F6E1}\uFE0F Self-healing: \u2705 token valid${E.expiresInMs?` (${Math.round(E.expiresInMs/36e5)}h left)`:""}`:E.state==="near_expiry"?"\u{1F6E1}\uFE0F Self-healing: \u267B\uFE0F token near expiry \u2014 auto-refresh attempted":`\u{1F6E1}\uFE0F Self-healing: \u26A0\uFE0F ${E.message.split(`
54
+ \u{1F9E0} **Brain Instances:** could not fetch \u2014 ${A.message}`}await ve();const E=fe(v),j=E.state==="long_lived"?"\u{1F6E1}\uFE0F Self-healing: \u2705 long-lived API key (won't expire silently)":E.state==="healthy"?`\u{1F6E1}\uFE0F Self-healing: \u2705 token valid${E.expiresInMs?` (${Math.round(E.expiresInMs/36e5)}h left)`:""}`:E.state==="near_expiry"?"\u{1F6E1}\uFE0F Self-healing: \u267B\uFE0F token near expiry \u2014 auto-refresh attempted":`\u{1F6E1}\uFE0F Self-healing: \u26A0\uFE0F ${E.message.split(`
55
55
  `)[0]}`;return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${w}`,` \u{1F493} Health: ${c}`,` ${j}`,"","\u{1F511} **Auth:**",b,g].join(`
56
- `)}default:throw new tt(`Unknown tool: ${e}`)}}class tt extends Error{}const ot=`This project has a Cachly AI Brain \u2014 persistent, cross-session memory of past fixes, decisions, and gotchas for THIS codebase. Use it proactively; it makes you faster and stops you repeating known mistakes.
56
+ `)}default:throw new et(`Unknown tool: ${e}`)}}class et extends Error{}const tt=`This project has a Cachly AI Brain \u2014 persistent, cross-session memory of past fixes, decisions, and gotchas for THIS codebase. Use it proactively; it makes you faster and stops you repeating known mistakes.
57
57
 
58
58
  - BEFORE a non-trivial task: call smart_recall with a short description of what you're about to do. If it returns lessons, apply them before researching from scratch.
59
59
  - WHEN debugging an error: call causal_trace with the exact error first \u2014 a known fix may already exist.
60
60
  - AFTER a fix, deploy, or discovery: call learn_from_attempts so the knowledge persists.
61
61
  - BEFORE a risky op (deploy, migration, dependency bump): call brain_predict.
62
62
 
63
- The Brain instance id comes from the CACHLY_BRAIN_INSTANCE_ID environment variable.`,nt={tools:{},resources:{},prompts:{}},st=async()=>{const{katalog:e,unbekannteKernnamen:t}=$o(re);return t.length>0&&console.error(`cachly: ${t.length} Kernwerkzeug(e) gibt es gar nicht: ${t.join(", ")}`),{tools:e}};async function it(){return{resources:[]}}async function rt(){return{resourceTemplates:[]}}async function at(){return{prompts:[]}}function Uo(e){e.setRequestHandler(Le,st),e.setRequestHandler(Ie,dt),e.setRequestHandler(Ne,it),e.setRequestHandler(Re,rt),e.setRequestHandler(Ee,at)}function Wo(){const e=new Te({name:"cachly-mcp",version:M},{capabilities:nt,instructions:ot});return Uo(e),ct(e),e}function ct(e){const t=e.oninitialized;e.oninitialized=()=>{try{const n=e.getClientVersion();yt(n?.name,n?.version)}catch{}t?.()}}const X=new Te({name:"cachly-mcp",version:M},{capabilities:nt,instructions:ot});ct(X),X.setRequestHandler(Le,st),X.setRequestHandler(Ne,it),X.setRequestHandler(Re,rt),X.setRequestHandler(Ee,at);let _e=null,ae=!1,V=null,lt=0;async function Fo(e){if(!ae){if(V){await V;return}if(V=(async()=>{ae=!0,_e=e;try{await F("session_start",{instance_id:e,focus:"auto (MCP session)",workspace_path:process.cwd()})}catch{}finally{V=null}})(),await V,process.env.CACHLY_AUTO_INDEX!=="false")try{const t=await U(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),F("index_project",{instance_id:e,dir:process.cwd(),max_files:150,ttl:86400*7,namespace:"cachly:sem:code"}).catch(()=>{}))}catch{}}}async function $e(){if(!(!ae||!_e)){ae=!1;try{await F("session_end",{instance_id:_e,summary:`Auto-ended after ${lt} tool call(s). Session was started automatically.`,files_changed:[],lessons_learned:0})}catch{}}}const dt=async e=>{let{name:t,arguments:n}=e.params;if(t===Fe){const o=n??{},a=typeof o.tool=="string"?o.tool:"";if(!a)return{content:[{type:"text",text:'cachly_tool braucht das Feld "tool" \u2014 den Namen des Werkzeugs.'}],isError:!0};const r=re.find(i=>i.name===a);if(!r)return{content:[{type:"text",text:`Kein Werkzeug namens "${a}". Die Liste steht in der Beschreibung von ${Fe}.`}],isError:!0};if(o.describe===!0)return{content:[{type:"text",text:JSON.stringify({name:r.name,description:r.description,inputSchema:r.inputSchema},null,2)}]};t=a,n=o.arguments??{}}const s=new Set(["session_start","session_start_summary","session_end","auto_learn_session"]);if(!s.has(t)&&!ae&&!V){const o=n?.instance_id||B||process.env.CACHLY_BRAIN_INSTANCE_ID;o&&await Fo(o).catch(()=>{})}else V&&await V.catch(()=>{});s.has(t)||lt++;try{return wo(),{content:[{type:"text",text:await F(t,n??{})}]}}catch(o){if(o instanceof tt)return{content:[{type:"text",text:o.message}],isError:!0};if(o instanceof Z)throw o;const a=o.message??String(o);throw ke("cachly","tool_error",{tool:t,error:a}).catch(()=>{}),new Z(te.InternalError,a)}};X.setRequestHandler(Ie,dt),process.on("SIGTERM",async()=>{await $e().catch(()=>{});for(const[,e]of K)await e.quit().catch(()=>{});process.exit(0)}),process.on("SIGINT",async()=>{await $e().catch(()=>{});for(const[,e]of K)await e.quit().catch(()=>{});process.exit(0)}),process.on("unhandledRejection",e=>{const t=e instanceof Error?e.message:String(e);process.stderr.write(`[cachly-mcp] unhandledRejection: ${t}
63
+ The Brain instance id comes from the CACHLY_BRAIN_INSTANCE_ID environment variable.`,ot={tools:{},resources:{},prompts:{}},nt=async()=>{const{katalog:e,unbekannteKernnamen:t}=wo(re);return t.length>0&&console.error(`cachly: ${t.length} Kernwerkzeug(e) gibt es gar nicht: ${t.join(", ")}`),{tools:e}};async function st(){return{resources:[]}}async function it(){return{resourceTemplates:[]}}async function rt(){return{prompts:[]}}function Yo(e){e.setRequestHandler(Ne,nt),e.setRequestHandler(Te,lt),e.setRequestHandler(Re,st),e.setRequestHandler(Ee,it),e.setRequestHandler(Ie,rt)}function Jo(){const e=new ke({name:"cachly-mcp",version:M},{capabilities:ot,instructions:tt});return Yo(e),at(e),e}function at(e){const t=e.oninitialized;e.oninitialized=()=>{try{const n=e.getClientVersion();ht(n?.name,n?.version)}catch{}t?.()}}const X=new ke({name:"cachly-mcp",version:M},{capabilities:ot,instructions:tt});at(X),X.setRequestHandler(Ne,nt),X.setRequestHandler(Re,st),X.setRequestHandler(Ee,it),X.setRequestHandler(Ie,rt);let we=null,ae=!1,V=null,ct=0;async function Uo(e){if(!ae){if(V){await V;return}if(V=(async()=>{ae=!0,we=e;try{await F("session_start",{instance_id:e,focus:"auto (MCP session)",workspace_path:process.cwd()})}catch{}finally{V=null}})(),await V,process.env.CACHLY_AUTO_INDEX!=="false")try{const t=await U(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),F("index_project",{instance_id:e,dir:process.cwd(),max_files:150,ttl:86400*7,namespace:"cachly:sem:code"}).catch(()=>{}))}catch{}}}async function _e(){if(!(!ae||!we)){ae=!1;try{await F("session_end",{instance_id:we,summary:`Auto-ended after ${ct} tool call(s). Session was started automatically.`,files_changed:[],lessons_learned:0})}catch{}}}const lt=async e=>{let{name:t,arguments:n}=e.params;if(t===Fe){const o=n??{},a=typeof o.tool=="string"?o.tool:"";if(!a)return{content:[{type:"text",text:'cachly_tool braucht das Feld "tool" \u2014 den Namen des Werkzeugs.'}],isError:!0};const r=re.find(i=>i.name===a);if(!r)return{content:[{type:"text",text:`Kein Werkzeug namens "${a}". Die Liste steht in der Beschreibung von ${Fe}.`}],isError:!0};if(o.describe===!0)return{content:[{type:"text",text:JSON.stringify({name:r.name,description:r.description,inputSchema:r.inputSchema},null,2)}]};t=a,n=o.arguments??{}}const s=new Set(["session_start","session_start_summary","session_end","auto_learn_session"]);if(!s.has(t)&&!ae&&!V){const o=n?.instance_id||B||process.env.CACHLY_BRAIN_INSTANCE_ID;o&&await Uo(o).catch(()=>{})}else V&&await V.catch(()=>{});s.has(t)||ct++;try{vo();const o=await F(t,n??{});return{content:[{type:"text",text:fo(t,o)}]}}catch(o){if(o instanceof et)return{content:[{type:"text",text:o.message}],isError:!0};if(o instanceof Z)throw o;const a=o.message??String(o);throw Se("cachly","tool_error",{tool:t,error:a}).catch(()=>{}),new Z(te.InternalError,a)}};X.setRequestHandler(Te,lt),process.on("SIGTERM",async()=>{await _e().catch(()=>{});for(const[,e]of K)await e.quit().catch(()=>{});process.exit(0)}),process.on("SIGINT",async()=>{await _e().catch(()=>{});for(const[,e]of K)await e.quit().catch(()=>{});process.exit(0)}),process.on("unhandledRejection",e=>{const t=e instanceof Error?e.message:String(e);process.stderr.write(`[cachly-mcp] unhandledRejection: ${t}
64
64
  `)}),process.on("uncaughtException",e=>{process.stderr.write(`[cachly-mcp] uncaughtException: ${e?.stack??String(e)}
65
- `)}),process.stdout.on("error",()=>{}),process.stdin.on("error",()=>{});const pt={claude:".mcp.json",cursor:".cursor/mcp.json",windsurf:".windsurf/mcp.json",copilot:".vscode/mcp.json",continue:".continue/config.json",cline:".vscode/mcp.json",zed:".zed/settings.json"},Ce="<!-- cachly-brain-start -->",ut="<!-- cachly-brain-end -->",mt="https://api.cachly.dev";function ce(e,t,n={}){const s={CACHLY_BRAIN_INSTANCE_ID:t};return n.includeApiKey&&(s.CACHLY_JWT=e),w&&w!==mt&&(s.CACHLY_API_URL=w),s}function zo(e,t,n){return JSON.stringify(n==="continue"?{experimental:{modelContextProtocolServers:[{transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:ce(e,t)}]}}:n==="zed"?{context_servers:{cachly:{command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:ce(e,t)},settings:{}}}}:{mcpServers:{cachly:{command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:ce(e,t)}}},null,2)}async function gt(e,t,n,s,o,a={}){const r={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:ce(t,n)};if(!o.existsSync(e))return zo(t,n,s);let i={};try{i=JSON.parse(await o.readFile(e,"utf-8"))}catch{try{const{rename:f}=await import("node:fs/promises");await f(e,e+".bak"),process.stderr.write(`\u26A0\uFE0F ${e} was not valid JSON \u2014 backed up to ${e}.bak
66
- `)}catch{}}if(s==="continue"){const f=i.experimental??{},h=f.modelContextProtocolServers??[];let v;for(const u of h){const c=u.env??{};if(c.CACHLY_JWT){v=c.CACHLY_JWT;break}}v&&ne(v,a);const y=h.filter(u=>{const c=u.env??{};return!c.CACHLY_JWT&&!c.CACHLY_BRAIN_INSTANCE_ID});return y.push({transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:r.env}),i.experimental={...f,modelContextProtocolServers:y},JSON.stringify(i,null,2)}if(s==="zed"){const f=i.context_servers??{},v=f.cachly?.command?.env?.CACHLY_JWT;return v&&ne(v,a),f.cachly={command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:r.env},settings:{}},i.context_servers=f,JSON.stringify(i,null,2)}const p=i.mcpServers??{},d=p.cachly?.env?.CACHLY_JWT;return d&&ne(d,a),p.cachly=r,i.mcpServers=p,JSON.stringify(i,null,2)}function ft(e){return`${Ce}
65
+ `)}),process.stdout.on("error",()=>{}),process.stdin.on("error",()=>{});const dt={claude:".mcp.json",cursor:".cursor/mcp.json",windsurf:".windsurf/mcp.json",copilot:".vscode/mcp.json",continue:".continue/config.json",cline:".vscode/mcp.json",zed:".zed/settings.json"},$e="<!-- cachly-brain-start -->",pt="<!-- cachly-brain-end -->",ut="https://api.cachly.dev";function ce(e,t,n={}){const s={CACHLY_BRAIN_INSTANCE_ID:t};return n.includeApiKey&&(s.CACHLY_JWT=e),w&&w!==ut&&(s.CACHLY_API_URL=w),s}function Wo(e,t,n){return JSON.stringify(n==="continue"?{experimental:{modelContextProtocolServers:[{transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:ce(e,t)}]}}:n==="zed"?{context_servers:{cachly:{command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:ce(e,t)},settings:{}}}}:{mcpServers:{cachly:{command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:ce(e,t)}}},null,2)}async function mt(e,t,n,s,o,a={}){const r={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:ce(t,n)};if(!o.existsSync(e))return Wo(t,n,s);let i={};try{i=JSON.parse(await o.readFile(e,"utf-8"))}catch{try{const{rename:f}=await import("node:fs/promises");await f(e,e+".bak"),process.stderr.write(`\u26A0\uFE0F ${e} was not valid JSON \u2014 backed up to ${e}.bak
66
+ `)}catch{}}if(s==="continue"){const f=i.experimental??{},h=f.modelContextProtocolServers??[];let x;for(const u of h){const c=u.env??{};if(c.CACHLY_JWT){x=c.CACHLY_JWT;break}}x&&ne(x,a);const y=h.filter(u=>{const c=u.env??{};return!c.CACHLY_JWT&&!c.CACHLY_BRAIN_INSTANCE_ID});return y.push({transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:r.env}),i.experimental={...f,modelContextProtocolServers:y},JSON.stringify(i,null,2)}if(s==="zed"){const f=i.context_servers??{},x=f.cachly?.command?.env?.CACHLY_JWT;return x&&ne(x,a),f.cachly={command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:r.env},settings:{}},i.context_servers=f,JSON.stringify(i,null,2)}const p=i.mcpServers??{},d=p.cachly?.env?.CACHLY_JWT;return d&&ne(d,a),p.cachly=r,i.mcpServers=p,JSON.stringify(i,null,2)}function gt(e){return`${$e}
67
67
  ## Cachly AI Brain \u2014 Always Active
68
68
 
69
69
  The Brain MCP server runs automatically. Instance: \`${e}\`
@@ -118,31 +118,31 @@ Report predicted failure risks to the user before proceeding.
118
118
 
119
119
  ### Half-finished code rule:
120
120
  Never commit code that does not compile. Run \`tsc --noEmit\` / \`go build ./...\` before every commit.
121
- ${ut}`}const qo=`---
121
+ ${pt}`}const Fo=`---
122
122
  description: Cachly AI Brain \u2014 persistent memory protocol (recall before tasks, learn after fixes)
123
123
  alwaysApply: true
124
124
  ---
125
125
 
126
- `;async function ht(e,t){const{writeFile:n,appendFile:s,readFile:o,mkdir:a}=await import("node:fs/promises"),{existsSync:r}=await import("node:fs"),{resolve:i,dirname:p}=await import("node:path"),l=[{path:i(e,"CLAUDE.md")},{path:i(e,"AGENTS.md")},{path:i(e,".github","copilot-instructions.md")},{path:i(e,".cursor","rules","cachly.mdc"),prefix:qo},{path:i(e,".windsurfrules")},{path:i(e,".clinerules")}],d=`
127
- `+ft(t)+`
128
- `,f={};for(const{path:h,prefix:v}of l){if(await a(p(h),{recursive:!0}),r(h)){const y=await o(h,"utf-8");if(y.includes(Ce)){const u=y.replace(new RegExp(`${Ce}[\\s\\S]*?${ut}`),ft(t));await n(h,u,"utf-8"),f[h]="updated";continue}await s(h,d,"utf-8"),f[h]="appended";continue}await n(h,(v??"")+d.trimStart(),"utf-8"),f[h]="written"}return f}if(process.argv[2]==="digest"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
126
+ `;async function ft(e,t){const{writeFile:n,appendFile:s,readFile:o,mkdir:a}=await import("node:fs/promises"),{existsSync:r}=await import("node:fs"),{resolve:i,dirname:p}=await import("node:path"),l=[{path:i(e,"CLAUDE.md")},{path:i(e,"AGENTS.md")},{path:i(e,".github","copilot-instructions.md")},{path:i(e,".cursor","rules","cachly.mdc"),prefix:Fo},{path:i(e,".windsurfrules")},{path:i(e,".clinerules")}],d=`
127
+ `+gt(t)+`
128
+ `,f={};for(const{path:h,prefix:x}of l){if(await a(p(h),{recursive:!0}),r(h)){const y=await o(h,"utf-8");if(y.includes($e)){const u=y.replace(new RegExp(`${$e}[\\s\\S]*?${pt}`),gt(t));await n(h,u,"utf-8"),f[h]="updated";continue}await s(h,d,"utf-8"),f[h]="appended";continue}await n(h,(x??"")+d.trimStart(),"utf-8"),f[h]="written"}return f}if(process.argv[2]==="digest"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
129
129
  \u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
130
130
  `),process.exit(1)),process.stdout.write(`
131
131
  \u{1F9E0} Fetching your weekly Brain digest...
132
132
 
133
- `);try{const n=await fetch(`${w}/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,a=s.total_recall_count??0,r=Math.round(s.iq_boost_pct??0),i=(s.top_lessons??[]).slice(0,5),p=s.team_authors??[],l=a*1200,d=(l*3e-6).toFixed(2),f=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}",h=new Date,v=new Date(h);v.setDate(h.getDate()-7);const y=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${y(v)} \u2013 ${y(h)}\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${f.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Total recalls : \x1B[36m${String(a).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(r).padEnd(3)}%\x1B[0m \u2502`),console.log(`\u2502 Tokens saved : \x1B[32m${(Math.round(l/1e3)+"K").padEnd(8)}\x1B[0m Cost saved : \x1B[32m$${d.padEnd(20)}\x1B[0m\u2502`),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[36m\u{1F465} Team contributors:\x1B[0m ${p.slice(0,5).join(", ").slice(0,42).padEnd(42)} \u2502`)),i.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 i){const E=`${g.topic}: ${g.what_worked}`.slice(0,57);console.log(`\u2502 \x1B[90m\u2022 ${E.padEnd(58)}\x1B[0m\u2502`)}}console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("");const u=i[0],c=[`\u{1F9E0} My AI Brain weekly digest (${y(v)} \u2013 ${y(h)}):`,"",` \u{1F4DA} ${o} lessons learned`,` \u{1F501} ${a} recalls \xB7 ~${Math.round(l/1e3)}K tokens saved`,` \u{1F3AF} Brain Level: ${f}`,u?` \u{1F525} Top lesson: "${u.topic}: ${u.what_worked.slice(0,60)}${u.what_worked.length>60?"\u2026":""}"`:"","","Built with @cachly_dev \u2014 AI that actually remembers \u{1F680}","cachly.dev"].filter(Boolean).join(`
133
+ `);try{const n=await fetch(`${w}/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,a=s.total_recall_count??0,r=Math.round(s.iq_boost_pct??0),i=(s.top_lessons??[]).slice(0,5),p=s.team_authors??[],l=a*1200,d=(l*3e-6).toFixed(2),f=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}",h=new Date,x=new Date(h);x.setDate(h.getDate()-7);const y=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${y(x)} \u2013 ${y(h)}\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${f.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Total recalls : \x1B[36m${String(a).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(r).padEnd(3)}%\x1B[0m \u2502`),console.log(`\u2502 Tokens saved : \x1B[32m${(Math.round(l/1e3)+"K").padEnd(8)}\x1B[0m Cost saved : \x1B[32m$${d.padEnd(20)}\x1B[0m\u2502`),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[36m\u{1F465} Team contributors:\x1B[0m ${p.slice(0,5).join(", ").slice(0,42).padEnd(42)} \u2502`)),i.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 i){const E=`${g.topic}: ${g.what_worked}`.slice(0,57);console.log(`\u2502 \x1B[90m\u2022 ${E.padEnd(58)}\x1B[0m\u2502`)}}console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("");const u=i[0],c=[`\u{1F9E0} My AI Brain weekly digest (${y(x)} \u2013 ${y(h)}):`,"",` \u{1F4DA} ${o} lessons learned`,` \u{1F501} ${a} recalls \xB7 ~${Math.round(l/1e3)}K tokens saved`,` \u{1F3AF} Brain Level: ${f}`,u?` \u{1F525} Top lesson: "${u.topic}: ${u.what_worked.slice(0,60)}${u.what_worked.length>60?"\u2026":""}"`:"","","Built with @cachly_dev \u2014 AI that actually remembers \u{1F680}","cachly.dev"].filter(Boolean).join(`
134
134
  `),b="https://twitter.com/intent/tweet?text="+encodeURIComponent(c);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 c.split(`
135
135
  `))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${b.slice(0,90)}...\x1B[0m`),console.log(""),console.log(" \x1B[2m\u{1F4A1} Invite your team: npx @cachly-dev/mcp-server@latest invite\x1B[0m"),console.log(" \x1B[2m Cron: 0 9 * * 1 npx @cachly-dev/mcp-server@latest digest\x1B[0m"),console.log("")}catch(n){console.log(`
136
136
  \u274C Could not fetch digest: ${n.message}
137
137
  `),process.exit(1)}process.exit(0)}if(process.argv[2]==="export"){const{writeFile:e,mkdir:t}=await import("node:fs/promises"),{resolve:n}=await import("node:path"),s=process.argv.slice(3),o=l=>{const d=s.indexOf(`--${l}`);return d!==-1?s[d+1]:void 0},a=o("format")??"both";a!=="md"&&a!=="jsonl"&&a!=="both"&&(console.log(`
138
138
  \u274C Unknown --format "${a}" \u2014 use md, jsonl, or both.
139
- `),process.exit(1));const r=n(o("out")??"."),i=x||we()||"",p=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!i||!p)&&(console.log(`
139
+ `),process.exit(1));const r=n(o("out")??"."),i=v||pe()||"",p=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!i||!p)&&(console.log(`
140
140
  \u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
141
141
  `),process.exit(1)),process.stdout.write(`
142
142
  \u{1F4E4} Exporting your Brain...
143
143
 
144
- `);try{let l=[],d="";const f=await fetch(`${w}/api/v1/instances/${p}/export`,{headers:{Authorization:`Bearer ${i}`},signal:AbortSignal.timeout(12e4)});if(f.ok){const v=await f.json();l=(v.lessons??[]).map(So).filter(y=>y!==null),v.complete===!1&&(d=v.note??"the server reported an incomplete read")}else if(f.status===404){const v=await fetch(`${w}/api/v1/instances/${p}/memory`,{headers:{Authorization:`Bearer ${i}`},signal:AbortSignal.timeout(8e3)});if(!v.ok)throw new Error(`memory HTTP ${v.status}`);l=((await v.json()).top_lessons??[]).map(u=>({topic:u.topic,outcome:u.outcome,severity:u.severity,tags:u.tags,whatWorked:u.what_worked,ts:u.ts,author:u.author,recallCount:u.recall_count})),d="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 ${f.status}`);l.length===0&&(console.log(` No lessons in this Brain yet \u2014 nothing to export.
145
- `),process.exit(0)),await t(r,{recursive:!0});const h=[];if(a==="md"||a==="both"){const v=n(r,"lessons.md");await e(v,Co(l),"utf-8"),h.push(`${l.length} lesson${l.length===1?"":"s"} \u2192 ${v}`)}if(a==="jsonl"||a==="both"){const v=n(r,"lessons.jsonl");await e(v,Ao(l),"utf-8"),h.push(`${l.length} lesson${l.length===1?"":"s"} \u2192 ${v}`)}d?(console.log("\u26A0\uFE0F Export INCOMPLETE \u2014 this is not your whole Brain:"),console.log(` ${d}`),console.log("")):console.log("\u2705 Export complete:");for(const v of h)console.log(` ${v}`);console.log("")}catch(l){console.log(`
144
+ `);try{let l=[],d="";const f=await fetch(`${w}/api/v1/instances/${p}/export`,{headers:{Authorization:`Bearer ${i}`},signal:AbortSignal.timeout(12e4)});if(f.ok){const x=await f.json();l=(x.lessons??[]).map(Co).filter(y=>y!==null),x.complete===!1&&(d=x.note??"the server reported an incomplete read")}else if(f.status===404){const x=await fetch(`${w}/api/v1/instances/${p}/memory`,{headers:{Authorization:`Bearer ${i}`},signal:AbortSignal.timeout(8e3)});if(!x.ok)throw new Error(`memory HTTP ${x.status}`);l=((await x.json()).top_lessons??[]).map(u=>({topic:u.topic,outcome:u.outcome,severity:u.severity,tags:u.tags,whatWorked:u.what_worked,ts:u.ts,author:u.author,recallCount:u.recall_count})),d="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 ${f.status}`);l.length===0&&(console.log(` No lessons in this Brain yet \u2014 nothing to export.
145
+ `),process.exit(0)),await t(r,{recursive:!0});const h=[];if(a==="md"||a==="both"){const x=n(r,"lessons.md");await e(x,_o(l),"utf-8"),h.push(`${l.length} lesson${l.length===1?"":"s"} \u2192 ${x}`)}if(a==="jsonl"||a==="both"){const x=n(r,"lessons.jsonl");await e(x,$o(l),"utf-8"),h.push(`${l.length} lesson${l.length===1?"":"s"} \u2192 ${x}`)}d?(console.log("\u26A0\uFE0F Export INCOMPLETE \u2014 this is not your whole Brain:"),console.log(` ${d}`),console.log("")):console.log("\u2705 Export complete:");for(const x of h)console.log(` ${x}`);console.log("")}catch(l){console.log(`
146
146
  \u274C Could not export your Brain: ${l.message}
147
147
  `),process.exit(1)}process.exit(0)}if(process.argv[2]==="invite"){const e=process.env.CACHLY_JWT??"";e||(console.log(`
148
148
  \u26A0\uFE0F CACHLY_JWT must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
@@ -167,9 +167,9 @@ Try it free: ${s}
167
167
  \u274C Could not fetch invite: HTTP ${$.status}
168
168
  `),process.exit(1)),l=await $.json()}catch($){console.log(`
169
169
  \u274C Network error: ${$.message}
170
- `),process.exit(1)}const{instance_id:d,instance_name:f,tier:h,label:v}=l,y=new Date(l.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${f}\x1B[0m`),console.log(` Tier : ${h}`),v&&console.log(` Note : ${v}`),console.log(` Expires : ${y}`),console.log("");const u=i({input:process.stdin,output:process.stdout}),c=await new Promise($=>{u.question(" Join this Brain? [Y/n] ",k=>{u.close(),$(k.trim().toLowerCase()||"y")})});c!=="y"&&c!=="yes"&&(console.log(`
170
+ `),process.exit(1)}const{instance_id:d,instance_name:f,tier:h,label:x}=l,y=new Date(l.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${f}\x1B[0m`),console.log(` Tier : ${h}`),x&&console.log(` Note : ${x}`),console.log(` Expires : ${y}`),console.log("");const u=i({input:process.stdin,output:process.stdout}),c=await new Promise($=>{u.question(" Join this Brain? [Y/n] ",k=>{u.close(),$(k.trim().toLowerCase()||"y")})});c!=="y"&&c!=="yes"&&(console.log(`
171
171
  Cancelled.
172
- `),process.exit(0));let b=x;if(!b){console.log(`
172
+ `),process.exit(0));let b=v;if(!b){console.log(`
173
173
  No API key found \u2014 starting sign-in (10 seconds)...
174
174
  `);try{const $=await fetch(`${w}/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($.ok){const k=await $.json();console.log(` \u{1F449} Open: \x1B[36m${k.verification_uri}\x1B[0m`),console.log(` Code: \x1B[1m${k.user_code}\x1B[0m
175
175
  `);const I=(k.interval??5)*1e3;for(let H=0;H<24;H++){await new Promise(T=>setTimeout(T,I));try{const T=await fetch(`${w}/api/v1/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:k.device_code,client_id:"cachly-mcp-cli"}),signal:AbortSignal.timeout(8e3)});if(T.ok){const D=await T.json();if(D.access_token){b=D.access_token;break}}}catch{}}b||(console.log(`
@@ -177,7 +177,7 @@ Try it free: ${s}
177
177
  `),process.exit(1)),console.log(` \u2705 Signed in!
178
178
  `)}}catch($){console.log(`
179
179
  \u26A0\uFE0F Could not start sign-in: ${$.message}`),console.log(` Set CACHLY_JWT manually from ${N("/setup-ai","join")}
180
- `),process.exit(1)}}const g=process.cwd(),E=r(),j=[{label:".mcp.json (Claude Code project)",path:o(g,".mcp.json")},{label:".cursor/mcp.json",path:o(g,".cursor","mcp.json")},{label:".windsurf/mcp.json",path:o(g,".windsurf","mcp.json")},{label:".vscode/mcp.json (Copilot/Cline)",path:o(g,".vscode","mcp.json")},{label:"~/.claude/mcp.json (global)",path:o(E,".claude","mcp.json"),global:!0}];let A=0;for(const{label:$,path:k,global:I}of j){const H=a(k);if(!(!I&&!s(H)&&!s(k)))try{await n(H,{recursive:!0});let T={};if(s(k))try{T=JSON.parse(await t(k,"utf-8"))}catch{try{await(await import("node:fs/promises")).rename(k,k+".bak")}catch{}}const D=T.mcpServers??{},q=D.cachly??{},S=q.env??{};S.CACHLY_BRAIN_INSTANCE_ID=d,b&&!S.CACHLY_JWT&&(S.CACHLY_JWT=b),w!==mt&&(S.CACHLY_API_URL=w),D.cachly={...q,command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:S},T.mcpServers=D,await e(k,JSON.stringify(T,null,2),"utf-8"),console.log(` \u2705 ${$}`),A++}catch(T){T.code!=="ENOENT"&&console.log(` \u26A0\uFE0F ${$}: ${T.message}`)}}console.log(""),A===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${f}\x1B[0m`),console.log(` Restart your editor \u2014 your AI arrives pre-briefed from the team Brain.
180
+ `),process.exit(1)}}const g=process.cwd(),E=r(),j=[{label:".mcp.json (Claude Code project)",path:o(g,".mcp.json")},{label:".cursor/mcp.json",path:o(g,".cursor","mcp.json")},{label:".windsurf/mcp.json",path:o(g,".windsurf","mcp.json")},{label:".vscode/mcp.json (Copilot/Cline)",path:o(g,".vscode","mcp.json")},{label:"~/.claude/mcp.json (global)",path:o(E,".claude","mcp.json"),global:!0}];let A=0;for(const{label:$,path:k,global:I}of j){const H=a(k);if(!(!I&&!s(H)&&!s(k)))try{await n(H,{recursive:!0});let T={};if(s(k))try{T=JSON.parse(await t(k,"utf-8"))}catch{try{await(await import("node:fs/promises")).rename(k,k+".bak")}catch{}}const D=T.mcpServers??{},q=D.cachly??{},S=q.env??{};S.CACHLY_BRAIN_INSTANCE_ID=d,b&&!S.CACHLY_JWT&&(S.CACHLY_JWT=b),w!==ut&&(S.CACHLY_API_URL=w),D.cachly={...q,command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:S},T.mcpServers=D,await e(k,JSON.stringify(T,null,2),"utf-8"),console.log(` \u2705 ${$}`),A++}catch(T){T.code!=="ENOENT"&&console.log(` \u26A0\uFE0F ${$}: ${T.message}`)}}console.log(""),A===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${f}\x1B[0m`),console.log(` Restart your editor \u2014 your AI arrives pre-briefed from the team Brain.
181
181
  `),console.log(" \u{1F4DB} Add the badge to your README:"),console.log(` npx @cachly-dev/mcp-server@latest badge
182
182
  `)),process.exit(0)}if(process.argv[2]==="upgrade"){process.stdout.write(`
183
183
  \u23F3 Checking for updates...
@@ -185,7 +185,7 @@ Try it free: ${s}
185
185
  \u2705 Already on the latest version: \x1B[32mv${M}\x1B[0m
186
186
  `):(console.log(""),console.log("\x1B[35m \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly update available\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m"),console.log(""),console.log(` Current : \x1B[31mv${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(`
187
187
  \u274C Could not check for updates: ${e.message}
188
- `),process.exit(1)}process.exit(0)}if(process.argv[2]==="bench"){const{fileURLToPath:e}=await import("node:url"),{dirname:t,resolve:n}=await import("node:path"),{loadExternalCorpus:s,runExternalBenchmark:o}=await import("./bench/external-corpus.js"),a=process.argv.includes("--json"),r=process.argv.slice(3).find(l=>!l.startsWith("--")),i=t(e(import.meta.url)),p=r?n(process.cwd(),r):n(i,"bench","external","sample-corpus.json");try{const l=await s(p),d=await o(l);a&&(console.log(JSON.stringify({corpus:l.name,lessons:d.corpusSize,queries:d.queryCount,cachly_p1:Math.round(d.cachly.precisionAt1*1e3)/10,flatfile_p1:Math.round(d.flatfile.precisionAt1*1e3)/10,cachly_mrr:Math.round(d.cachly.mrr*1e3)/10,flatfile_mrr:Math.round(d.flatfile.mrr*1e3)/10,p1_lift_vs_flatfile_pct:Math.round((d.cachly.precisionAt1-d.flatfile.precisionAt1)*1e3)/10,mrr_lift_vs_flatfile_pct:Math.round((d.cachly.mrr-d.flatfile.mrr)*1e3)/10},null,2)),process.exit(0));const f=((d.cachly.precisionAt1-d.flatfile.precisionAt1)*100).toFixed(1),h=((d.cachly.mrr-d.flatfile.mrr)*100).toFixed(1),v=((d.cachly.precisionAt1-d.baseline.precisionAt1)*100).toFixed(1),y=d.cachly.precisionAt1>=d.flatfile.precisionAt1?"\x1B[32m+":"\x1B[31m",u=d.cachly.mrr>=d.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 : ${l.name??p}`),console.log(` Dataset: ${d.corpusSize} lessons \xB7 ${d.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${(d.flatfile.precisionAt1*100).toFixed(1)}%\x1B[0m (naive keyword overlap \u2014 no quality signal)`),console.log(` raw BM25 : \x1B[33m${(d.baseline.precisionAt1*100).toFixed(1)}%\x1B[0m (keyword ranking)`),console.log(` cachly : \x1B[1m\x1B[32m${(d.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${(d.flatfile.mrr*100).toFixed(1)}%\x1B[0m`),console.log(` raw BM25 : \x1B[33m${(d.baseline.mrr*100).toFixed(1)}%\x1B[0m`),console.log(` cachly : \x1B[1m\x1B[32m${(d.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 : ${y}${f}%\x1B[0m`),console.log(` MRR : ${u}${h}%\x1B[0m`),console.log(` vs BM25 : \x1B[32m+${v}%\x1B[0m Precision@1 (quality reranking on top of keyword search)`),console.log(""),console.log(" \x1B[2mFlat-file = lexical overlap over raw text files (how Anthropic/Claude Memory works).\x1B[0m"),console.log(" \x1B[2mAdversarial distractors included \u2014 failure lessons that share the exact query vocabulary.\x1B[0m"),console.log(" \x1B[2mcachly ignores them because they have low confidence / failed outcome.\x1B[0m"),console.log(""),console.log(" Share your results:"),console.log(` \x1B[36m"My Brain: Precision@1 ${(d.cachly.precisionAt1*100).toFixed(1)}% (${y}${f}% vs flat-file memory, ${d.queryCount} queries)"\x1B[0m`),console.log(""),console.log(" Run on a custom corpus:"),console.log(" \x1B[2m npx @cachly-dev/mcp-server@latest bench my-incidents.json\x1B[0m"),console.log(" \x1B[2m npx @cachly-dev/mcp-server@latest bench --json # machine-readable\x1B[0m"),console.log(""),console.log(" \x1B[1m\u2192 Give your AI this recall quality on your own work (free, 1\u20135 min):\x1B[0m"),console.log(" \x1B[32m$ npx @cachly-dev/mcp-server@latest autopilot\x1B[0m"),console.log(" \x1B[90m Signs in, configures every editor, bootstraps from your git history.\x1B[0m"),console.log(` \x1B[90m Or create your Brain at: \x1B[36m${N("/setup-ai","bench")}\x1B[0m`),console.log("")}catch(l){console.error(`
188
+ `),process.exit(1)}process.exit(0)}if(process.argv[2]==="bench"){const{fileURLToPath:e}=await import("node:url"),{dirname:t,resolve:n}=await import("node:path"),{loadExternalCorpus:s,runExternalBenchmark:o}=await import("./bench/external-corpus.js"),a=process.argv.includes("--json"),r=process.argv.slice(3).find(l=>!l.startsWith("--")),i=t(e(import.meta.url)),p=r?n(process.cwd(),r):n(i,"bench","external","sample-corpus.json");try{const l=await s(p),d=await o(l);a&&(console.log(JSON.stringify({corpus:l.name,lessons:d.corpusSize,queries:d.queryCount,cachly_p1:Math.round(d.cachly.precisionAt1*1e3)/10,flatfile_p1:Math.round(d.flatfile.precisionAt1*1e3)/10,cachly_mrr:Math.round(d.cachly.mrr*1e3)/10,flatfile_mrr:Math.round(d.flatfile.mrr*1e3)/10,p1_lift_vs_flatfile_pct:Math.round((d.cachly.precisionAt1-d.flatfile.precisionAt1)*1e3)/10,mrr_lift_vs_flatfile_pct:Math.round((d.cachly.mrr-d.flatfile.mrr)*1e3)/10},null,2)),process.exit(0));const f=((d.cachly.precisionAt1-d.flatfile.precisionAt1)*100).toFixed(1),h=((d.cachly.mrr-d.flatfile.mrr)*100).toFixed(1),x=((d.cachly.precisionAt1-d.baseline.precisionAt1)*100).toFixed(1),y=d.cachly.precisionAt1>=d.flatfile.precisionAt1?"\x1B[32m+":"\x1B[31m",u=d.cachly.mrr>=d.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 : ${l.name??p}`),console.log(` Dataset: ${d.corpusSize} lessons \xB7 ${d.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${(d.flatfile.precisionAt1*100).toFixed(1)}%\x1B[0m (naive keyword overlap \u2014 no quality signal)`),console.log(` raw BM25 : \x1B[33m${(d.baseline.precisionAt1*100).toFixed(1)}%\x1B[0m (keyword ranking)`),console.log(` cachly : \x1B[1m\x1B[32m${(d.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${(d.flatfile.mrr*100).toFixed(1)}%\x1B[0m`),console.log(` raw BM25 : \x1B[33m${(d.baseline.mrr*100).toFixed(1)}%\x1B[0m`),console.log(` cachly : \x1B[1m\x1B[32m${(d.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 : ${y}${f}%\x1B[0m`),console.log(` MRR : ${u}${h}%\x1B[0m`),console.log(` vs BM25 : \x1B[32m+${x}%\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 ${(d.cachly.precisionAt1*100).toFixed(1)}% (${y}${f}% vs flat-file memory, ${d.queryCount} queries)"\x1B[0m`),console.log(""),console.log(" Run on a custom corpus:"),console.log(" \x1B[2m npx @cachly-dev/mcp-server@latest bench my-incidents.json\x1B[0m"),console.log(" \x1B[2m npx @cachly-dev/mcp-server@latest bench --json # machine-readable\x1B[0m"),console.log(""),console.log(" \x1B[1m\u2192 Give your AI this recall quality on your own work (free, 1\u20135 min):\x1B[0m"),console.log(" \x1B[32m$ npx @cachly-dev/mcp-server@latest autopilot\x1B[0m"),console.log(" \x1B[90m Signs in, configures every editor, bootstraps from your git history.\x1B[0m"),console.log(` \x1B[90m Or create your Brain at: \x1B[36m${N("/setup-ai","bench")}\x1B[0m`),console.log("")}catch(l){console.error(`
189
189
  \u274C bench failed: ${l.message}
190
190
  `),process.exit(1)}process.exit(0)}if(process.argv[2]==="demo"){const{execSync:e}=await import("node:child_process"),{existsSync:t,readFileSync:n}=await import("node:fs"),{resolve:s,basename:o}=await import("node:path"),a=process.cwd();console.log(`
191
191
  \x1B[35m\u{1F9E0} cachly Brain \u2014 Live Demo\x1B[0m`),console.log(`\x1B[90mNo account needed. Reading your git history...\x1B[0m
@@ -194,7 +194,7 @@ Try it free: ${s}
194
194
  `),process.exit(0));let r="";try{r=e("git config user.name",{cwd:a,encoding:"utf-8",stdio:"pipe"}).trim().split(" ")[0]??""}catch{}let i=o(a);try{const S=JSON.parse(n(s(a,"package.json"),"utf-8"));S.name&&(i=S.name.replace(/^@[^/]+\//,""))}catch{}let p="";try{p=e('git log HEAD --pretty=format:"%H|||%s|||%ad|||%an" --date=short --no-merges -n 200',{cwd:a,encoding:"utf-8",stdio:"pipe"})}catch{console.log(`\u26A0\uFE0F Could not read git log. Make sure you have commits.
195
195
  `),process.exit(0)}const l=p.trim().split(`
196
196
  `).filter(Boolean).map(S=>{const[L,ee,m,_]=S.split("|||");return{sha:(L??"").trim().slice(0,8),subject:(ee??"").trim(),date:(m??"").trim(),author:(_??"").trim()}});l.length===0&&(console.log(`\u26A0\uFE0F No commits found.
197
- `),process.exit(0));const d=S=>{const L=S.toLowerCase();return/\b(fix|fixed|bug|hotfix|patch|revert|resolve)\b/.test(L)?"fix":/\b(feat|feature|add|implement|new|introduce)\b/.test(L)?"feat":/\b(perf|optim|speed|cache|latency)\b/.test(L)?"perf":/\b(security|cve|auth|csrf|xss|inject|sanitize)\b/.test(L)?"security":/\b(deploy|ci|cd|docker|k8s|infra)\b/.test(L)?"deploy":/\b(refactor|clean|simplify|extract)\b/.test(L)?"refactor":"chore"},f=new Map,h=[],v=[],y=[],u=new Set;for(const S of l){const L=d(S.subject);f.set(L,(f.get(L)??0)+1),L==="fix"&&h.length<5&&h.push(S.subject.slice(0,72)),L==="feat"&&v.length<5&&v.push(S.subject.slice(0,72)),L==="security"&&y.length<3&&y.push(S.subject.slice(0,72)),S.author&&u.add(S.author.split(" ")[0])}const c=l.length-(f.get("chore")??0),b=`${l[l.length-1]?.date??"?"} \u2192 ${l[0]?.date??"?"}`,g=l[l.length-1]?.date;let E=0;if(g){const S=Date.now()-new Date(g).getTime();E=Math.max(1,Math.round(S/(1e3*60*60*24)*5/7))}const j=Math.round(E*.75),A=c>=501?"Oracle":c>=201?"Architect":c>=51?"Expert":c>=11?"Explorer":"Apprentice",k=`${r?`Hey ${r} \u2014 `:""}here's what your AI would know about ${i}`;process.stdout.write("\x1B[2K\r"),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log(`\u2502 \x1B[1m\u{1F9E0} ${k.slice(0,58).padEnd(58)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Commits analysed : \x1B[33m${String(l.length).padEnd(6)}\x1B[0m Date range: \x1B[90m${b.slice(0,23).padEnd(23)}\x1B[0m \u2502`),console.log(`\u2502 Lessons extracted: \x1B[32m${String(c).padEnd(6)}\x1B[0m Contributors: \x1B[36m${String(u.size).padEnd(20)}\x1B[0m\u2502`),console.log(`\u2502 Brain Level : \x1B[35m${A.padEnd(14)}\x1B[0m Time wasted re-explaining: \x1B[31m${(j+"h").padEnd(5)}\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 I=[...f.entries()].filter(([S])=>S!=="chore").sort((S,L)=>L[1]-S[1]),H=(S,L)=>"\u2588".repeat(Math.round(S/L*20)).padEnd(20),T=Math.max(...I.map(([,S])=>S),1);console.log("\u2502 \x1B[90mCategory breakdown:\x1B[0m \u2502");for(const[S,L]of I){const ee={fix:"\u{1F527}",feat:"\u2728",perf:"\u26A1",security:"\u{1F512}",deploy:"\u{1F680}",refactor:"\u{1F504}"}[S]??"\u2022";console.log(`\u2502 ${ee} \x1B[36m${S.padEnd(10)}\x1B[0m \x1B[35m${H(L,T)}\x1B[0m \x1B[33m${String(L).padStart(3)}\x1B[0m \u2502`)}if(y.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[31m\u{1F512} Security fixes your AI would know:\x1B[0m \u2502");for(const S of y)console.log(`\u2502 \x1B[90m\u2022 ${S.slice(0,58).padEnd(58)}\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[33m\u{1F527} Bug fixes your AI would never repeat:\x1B[0m \u2502");for(const S of h.slice(0,4))console.log(`\u2502 \x1B[90m\u2022 ${S.slice(0,58).padEnd(58)}\x1B[0m \u2502`)}if(v.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 S of v.slice(0,3))console.log(`\u2502 \x1B[90m\u2022 ${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 \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 D=new URLSearchParams({repo:i,commits:String(l.length),lessons:String(c),level:A,authors:String(u.size),hours:String(j)}),q=N(`/preview?${D.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${q}\x1B[0m`),console.log(""),console.log(" Works with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 Copilot \xB7 Cline \xB7 Zed"),console.log(" Free forever \xB7 GDPR \xB7 German servers \xB7 No credit card"),console.log(""),process.exit(0)}if(process.argv[2]==="share"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
197
+ `),process.exit(0));const d=S=>{const L=S.toLowerCase();return/\b(fix|fixed|bug|hotfix|patch|revert|resolve)\b/.test(L)?"fix":/\b(feat|feature|add|implement|new|introduce)\b/.test(L)?"feat":/\b(perf|optim|speed|cache|latency)\b/.test(L)?"perf":/\b(security|cve|auth|csrf|xss|inject|sanitize)\b/.test(L)?"security":/\b(deploy|ci|cd|docker|k8s|infra)\b/.test(L)?"deploy":/\b(refactor|clean|simplify|extract)\b/.test(L)?"refactor":"chore"},f=new Map,h=[],x=[],y=[],u=new Set;for(const S of l){const L=d(S.subject);f.set(L,(f.get(L)??0)+1),L==="fix"&&h.length<5&&h.push(S.subject.slice(0,72)),L==="feat"&&x.length<5&&x.push(S.subject.slice(0,72)),L==="security"&&y.length<3&&y.push(S.subject.slice(0,72)),S.author&&u.add(S.author.split(" ")[0])}const c=l.length-(f.get("chore")??0),b=`${l[l.length-1]?.date??"?"} \u2192 ${l[0]?.date??"?"}`,g=l[l.length-1]?.date;let E=0;if(g){const S=Date.now()-new Date(g).getTime();E=Math.max(1,Math.round(S/(1e3*60*60*24)*5/7))}const j=Math.round(E*.75),A=c>=501?"Oracle":c>=201?"Architect":c>=51?"Expert":c>=11?"Explorer":"Apprentice",k=`${r?`Hey ${r} \u2014 `:""}here's what your AI would know about ${i}`;process.stdout.write("\x1B[2K\r"),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log(`\u2502 \x1B[1m\u{1F9E0} ${k.slice(0,58).padEnd(58)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Commits analysed : \x1B[33m${String(l.length).padEnd(6)}\x1B[0m Date range: \x1B[90m${b.slice(0,23).padEnd(23)}\x1B[0m \u2502`),console.log(`\u2502 Lessons extracted: \x1B[32m${String(c).padEnd(6)}\x1B[0m Contributors: \x1B[36m${String(u.size).padEnd(20)}\x1B[0m\u2502`),console.log(`\u2502 Brain Level : \x1B[35m${A.padEnd(14)}\x1B[0m Time wasted re-explaining: \x1B[31m${(j+"h").padEnd(5)}\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 I=[...f.entries()].filter(([S])=>S!=="chore").sort((S,L)=>L[1]-S[1]),H=(S,L)=>"\u2588".repeat(Math.round(S/L*20)).padEnd(20),T=Math.max(...I.map(([,S])=>S),1);console.log("\u2502 \x1B[90mCategory breakdown:\x1B[0m \u2502");for(const[S,L]of I){const ee={fix:"\u{1F527}",feat:"\u2728",perf:"\u26A1",security:"\u{1F512}",deploy:"\u{1F680}",refactor:"\u{1F504}"}[S]??"\u2022";console.log(`\u2502 ${ee} \x1B[36m${S.padEnd(10)}\x1B[0m \x1B[35m${H(L,T)}\x1B[0m \x1B[33m${String(L).padStart(3)}\x1B[0m \u2502`)}if(y.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[31m\u{1F512} Security fixes your AI would know:\x1B[0m \u2502");for(const S of y)console.log(`\u2502 \x1B[90m\u2022 ${S.slice(0,58).padEnd(58)}\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[33m\u{1F527} Bug fixes your AI would never repeat:\x1B[0m \u2502");for(const S of h.slice(0,4))console.log(`\u2502 \x1B[90m\u2022 ${S.slice(0,58).padEnd(58)}\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[32m\u2728 Features & decisions it would recall:\x1B[0m \u2502");for(const S of x.slice(0,3))console.log(`\u2502 \x1B[90m\u2022 ${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 \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 D=new URLSearchParams({repo:i,commits:String(l.length),lessons:String(c),level:A,authors:String(u.size),hours:String(j)}),q=N(`/preview?${D.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${q}\x1B[0m`),console.log(""),console.log(" Works with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 Copilot \xB7 Cline \xB7 Zed"),console.log(" Free forever \xB7 GDPR \xB7 German servers \xB7 No credit card"),console.log(""),process.exit(0)}if(process.argv[2]==="share"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
198
198
  \u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot (takes 1\u20135 minutes)
199
199
  `),process.exit(1)),process.stdout.write(`
200
200
  \u{1F9E0} Fetching your Brain stats...
@@ -226,31 +226,31 @@ ${d}
226
226
  Usage: npx @cachly-dev/mcp-server@latest init --instance-id <uuid> --api-key <cky_live_...> [--editor claude|cursor|windsurf|copilot|continue] [--project-dir /path] [--api-url https://your-self-hosted-backend]
227
227
  `),console.error(`First time? Run the zero-config wizard (signs you in, auto-provisions): npx @cachly-dev/mcp-server@latest autopilot
228
228
  `),console.error(`Get your credentials from: ${N("/setup-ai","init")}
229
- `),process.exit(1));const v=pt[d]??".mcp.json",y=o(f,v);await n(a(y),{recursive:!0});const{existsSync:u}=await import("node:fs"),c=u(y),b=c?await s(y,"utf-8").catch(()=>""):"";ne(l);const g=await gt(y,l,p,d,{readFile:s,existsSync:u});g!==b?(await t(y,g,"utf-8"),console.log(`
230
- \u2705 ${c?"Updated":"Written"}: ${v}`)):console.log(`
231
- \u2713 Already configured: ${v} (no change)`);const E=await ht(f,p);for(const[A,$]of Object.entries(E)){const k=$==="updated"?"\u2705 Updated":$==="appended"?"\u2705 Appended to":"\u2705 Written",I=A.split(/[\\/]/).pop()??A;console.log(`${k}: ${I}`)}try{const A=await De(f,p,x||void 0);A==="written"?console.log("\u2705 Written: .git/hooks/post-commit (CLS hook)"):A==="upgraded"?console.log(`\u2705 Upgraded: .git/hooks/post-commit (CLS hook \u2192 ${Me})`):A==="appended"?console.log("\u2705 Appended: .git/hooks/post-commit (CLS hook)"):A==="unchanged"&&console.log("\u2713 CLS hook already current in .git/hooks/post-commit")}catch{}if(d==="claude")try{const A=await Ye(f,p),$=A.scripts==="written"?"\u2705 Written":A.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${Je})`:"\u2713 Unchanged";console.log(`${$}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),A.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):A.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{}const j=((Date.now()-e)/1e3).toFixed(1);console.log(`
229
+ `),process.exit(1));const x=dt[d]??".mcp.json",y=o(f,x);await n(a(y),{recursive:!0});const{existsSync:u}=await import("node:fs"),c=u(y),b=c?await s(y,"utf-8").catch(()=>""):"";ne(l);const g=await mt(y,l,p,d,{readFile:s,existsSync:u});g!==b?(await t(y,g,"utf-8"),console.log(`
230
+ \u2705 ${c?"Updated":"Written"}: ${x}`)):console.log(`
231
+ \u2713 Already configured: ${x} (no change)`);const E=await ft(f,p);for(const[A,$]of Object.entries(E)){const k=$==="updated"?"\u2705 Updated":$==="appended"?"\u2705 Appended to":"\u2705 Written",I=A.split(/[\\/]/).pop()??A;console.log(`${k}: ${I}`)}try{const A=await Oe(f,p,v||void 0);A==="written"?console.log("\u2705 Written: .git/hooks/post-commit (CLS hook)"):A==="upgraded"?console.log(`\u2705 Upgraded: .git/hooks/post-commit (CLS hook \u2192 ${De})`):A==="appended"?console.log("\u2705 Appended: .git/hooks/post-commit (CLS hook)"):A==="unchanged"&&console.log("\u2713 CLS hook already current in .git/hooks/post-commit")}catch{}if(d==="claude")try{const A=await Me(f,p),$=A.scripts==="written"?"\u2705 Written":A.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${Ye})`:"\u2713 Unchanged";console.log(`${$}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),A.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):A.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{}const j=((Date.now()-e)/1e3).toFixed(1);console.log(`
232
232
  \u{1F9E0} Cachly AI Brain configured for ${d==="claude"?"Claude Code":d}! (${j}s)`),console.log(" 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(`
233
233
  \u{1F4DB} Add a live badge to your README:`),console.log(` npx @cachly-dev/mcp-server@latest badge
234
234
  `),process.exit(0)}if(process.argv[2]==="status"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
235
235
  \u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
236
- `),process.exit(1));try{const[n,s]=await Promise.all([fetch(`${w}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)}),fetch(`${w}/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(),a=s.ok?await s.json():null,r=o.lesson_count??0,i=o.total_recall_count??0,p=Math.round(o.iq_boost_pct??0),l=o.team_authors??[],d=a?.referral_count??0,f=a?.url??"",h=r===0?"Intern \u{1F331}":r<10?"Junior Dev \u{1F527}":r<30?"Mid Dev \u26A1":r<60?"Senior Dev \u{1F9E0}":r<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}",v=r>0?"\x1B[32m\u25CF\x1B[0m":"\x1B[33m\u25CF\x1B[0m";if(console.log(""),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log(`\u2502 ${v} \x1B[1mBrain status\x1B[0m \xB7 instance ${t.slice(0,8)}... \u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Lessons : \x1B[33m${String(r).padEnd(8)}\x1B[0m Level : \x1B[32m${h.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Recalls : \x1B[36m${String(i).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(p).padEnd(3)}%\x1B[0m \u2502`),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");const y=l.slice(0,4).join(", ");console.log(`\u2502 \x1B[36m\u{1F465} Team Brain\x1B[0m \xB7 ${String(l.length).padEnd(2)} developer${l.length===1?" ":"s"} sharing lessons${" ".repeat(Math.max(0,19-y.length))} \u2502`),console.log(`\u2502 ${y.slice(0,56).padEnd(56)} \u2502`)}if(f){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 y=`${f.slice(0,44)}${f.length>44?"\u2026":""}`;console.log(`\u2502 \x1B[35m\u{1F517} Invite link\x1B[0m \xB7 ${d>0?`\x1B[32m${d} joined\x1B[0m`:"share to grow your team"}${" ".repeat(Math.max(0,35-String(d).length))} \u2502`),console.log(`\u2502 \x1B[2m${y.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(""),r===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(`
236
+ `),process.exit(1));try{const[n,s]=await Promise.all([fetch(`${w}/api/v1/instances/${t}/memory`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(8e3)}),fetch(`${w}/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(),a=s.ok?await s.json():null,r=o.lesson_count??0,i=o.total_recall_count??0,p=Math.round(o.iq_boost_pct??0),l=o.team_authors??[],d=a?.referral_count??0,f=a?.url??"",h=r===0?"Intern \u{1F331}":r<10?"Junior Dev \u{1F527}":r<30?"Mid Dev \u26A1":r<60?"Senior Dev \u{1F9E0}":r<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}",x=r>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 ${x} \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(r).padEnd(8)}\x1B[0m Level : \x1B[32m${h.padEnd(18)}\x1B[0m\u2502`),console.log(`\u2502 Recalls : \x1B[36m${String(i).padEnd(8)}\x1B[0m Quality score: \x1B[32m${String(p).padEnd(3)}%\x1B[0m \u2502`),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");const y=l.slice(0,4).join(", ");console.log(`\u2502 \x1B[36m\u{1F465} Team Brain\x1B[0m \xB7 ${String(l.length).padEnd(2)} developer${l.length===1?" ":"s"} sharing lessons${" ".repeat(Math.max(0,19-y.length))} \u2502`),console.log(`\u2502 ${y.slice(0,56).padEnd(56)} \u2502`)}if(f){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 y=`${f.slice(0,44)}${f.length>44?"\u2026":""}`;console.log(`\u2502 \x1B[35m\u{1F517} Invite link\x1B[0m \xB7 ${d>0?`\x1B[32m${d} joined\x1B[0m`:"share to grow your team"}${" ".repeat(Math.max(0,35-String(d).length))} \u2502`),console.log(`\u2502 \x1B[2m${y.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(""),r===0&&(console.log(" \x1B[33m\u{1F4A1} No lessons yet.\x1B[0m Run a session with cachly connected to start learning."),console.log(""))}catch(n){console.log(`
237
237
  \u274C Could not fetch status: ${n.message}
238
238
  `),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,a=0;const r=u=>{console.log(` \u2705 ${u}`),o++},i=u=>{console.log(` \u26A0\uFE0F ${u}`)},p=u=>{console.log(` \u274C ${u}`),a++};console.log(`
239
239
  \u{1F9E0} cachly health check
240
240
  `),console.log("\u{1F511} Auth token");const l=process.env.CACHLY_JWT??"";if(!l)p("CACHLY_JWT not set \u2014 run: npx @cachly-dev/mcp-server@latest autopilot");else if(l.startsWith("cky_"))r("Long-lived API key set (cky_\u2026) \u2014 no client-side expiry");else try{const u=l.split(".");if(u.length!==3)throw new Error("not a JWT");const c=JSON.parse(Buffer.from(u[1],"base64url").toString("utf-8")),b=c.exp?c.exp*1e3:null,g=b?Math.floor((b-Date.now())/6e4):null;b&&b<Date.now()?p(`JWT expired ${Math.abs(g)} minute(s) ago \u2014 get a new one: ${N("/setup-ai","health")}`):g!==null&&g<30?i(`JWT expires in ${g} minute(s) \u2014 refresh soon at ${N("/setup-ai","health")}`):r(`JWT valid${g!==null?` (expires in ${Math.floor(g/60)}h ${g%60}m)`:""}`)}catch{p("CACHLY_JWT format invalid (expected a cky_ API key or a 3-part JWT)")}console.log(`
241
241
  \u{1F310} Brain API`);const d=process.env.CACHLY_API_URL??"https://api.cachly.dev";try{const u=await fetch(`${d}/health`,{signal:AbortSignal.timeout(5e3)});if(u.ok){const c=await u.json();r(`${d} reachable (status: ${c.status??"ok"})`)}else u.status===401||u.status===403?r(`${d} reachable (auth required \u2014 expected)`):p(`${d}/health returned HTTP ${u.status}`)}catch(u){p(`${d} unreachable \u2014 ${u.message}`)}console.log(`
242
242
  \u{1F9E0} Brain instance`);const f=process.env.CACHLY_BRAIN_INSTANCE_ID??"";if(!f)i("CACHLY_BRAIN_INSTANCE_ID not set \u2014 will auto-resolve on first tool call");else if(l)try{const u=await fetch(`${d}/api/v1/instances/${f}`,{headers:{Authorization:`Bearer ${l}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(u.ok){const c=await u.json();if(c.status==="running")if(r(`Instance "${c.name}" (${f.slice(0,8)}\u2026) is running`),console.log(`
243
- \u{1F50C} Redis connectivity`),c.host&&c.port)try{let b,g=c.tls_enabled!==!1;try{const A=await fetch(`${d}/api/v1/instances/${f}/connection`,{headers:{Authorization:`Bearer ${l}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(A.ok){const $=await A.json();b=$.password,g=$.tls_enabled!==!1}}catch{}const E=new Be({host:c.host,port:c.port,password:b,...g?{tls:{}}:{},lazyConnect:!0,connectTimeout:5e3,retryStrategy:()=>null});await E.connect();const j=await E.ping();E.disconnect(),j==="PONG"?r(`Redis PING \u2192 PONG (${c.host}:${c.port})`):i(`Redis responded but not PONG: ${j}`)}catch(b){p(`Redis unreachable \u2014 ${b.message}`)}else i("Instance has no host/port yet");else i(`Instance "${c.name}" status: ${c.status}`)}else p(`Instance ${f.slice(0,8)}\u2026 not found (HTTP ${u.status})`)}catch(u){p(`Could not check instance \u2014 ${u.message}`)}console.log(`
244
- \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"}];let v=0;for(const{editor:u,path:c}of h){const b=n(s,c);if(e(b))try{const g=await t(b,"utf-8");g.includes("@cachly-dev/mcp-server")||g.includes("cachly")?(r(`${u}: ${c}`),v++):i(`${u}: ${c} exists but cachly not found inside`)}catch{i(`${u}: ${c} exists but could not read`)}}v===0&&p("No editor MCP configs found \u2014 run: npx @cachly-dev/mcp-server@latest autopilot"),console.log(`
243
+ \u{1F50C} Redis connectivity`),c.host&&c.port)try{let b,g=c.tls_enabled!==!1;try{const A=await fetch(`${d}/api/v1/instances/${f}/connection`,{headers:{Authorization:`Bearer ${l}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(A.ok){const $=await A.json();b=$.password,g=$.tls_enabled!==!1}}catch{}const E=new Le({host:c.host,port:c.port,password:b,...g?{tls:{}}:{},lazyConnect:!0,connectTimeout:5e3,retryStrategy:()=>null});await E.connect();const j=await E.ping();E.disconnect(),j==="PONG"?r(`Redis PING \u2192 PONG (${c.host}:${c.port})`):i(`Redis responded but not PONG: ${j}`)}catch(b){p(`Redis unreachable \u2014 ${b.message}`)}else i("Instance has no host/port yet");else i(`Instance "${c.name}" status: ${c.status}`)}else p(`Instance ${f.slice(0,8)}\u2026 not found (HTTP ${u.status})`)}catch(u){p(`Could not check instance \u2014 ${u.message}`)}console.log(`
244
+ \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"}];let x=0;for(const{editor:u,path:c}of h){const b=n(s,c);if(e(b))try{const g=await t(b,"utf-8");g.includes("@cachly-dev/mcp-server")||g.includes("cachly")?(r(`${u}: ${c}`),x++):i(`${u}: ${c} exists but cachly not found inside`)}catch{i(`${u}: ${c} exists but could not read`)}}x===0&&p("No editor MCP configs found \u2014 run: npx @cachly-dev/mcp-server@latest autopilot"),console.log(`
245
245
  \u{1FA9D} Git hook (ambient learning)`);const y=n(s,".git","hooks","post-commit");if(!e(n(s,".git")))i("Not in a git repository \u2014 skip");else if(e(y))try{(await t(y,"utf-8")).includes("cachly")?r(".git/hooks/post-commit (cachly CLS hook present)"):i(".git/hooks/post-commit exists but cachly hook not found \u2014 run setup to add it")}catch{i(".git/hooks/post-commit exists but could not read")}else i(".git/hooks/post-commit not found \u2014 run: npx @cachly-dev/mcp-server@latest autopilot");console.log(`
246
246
  \u{1F9EC} Embedding provider (semantic search)`);{const u=[["OPENAI_API_KEY","openai"],["GEMINI_API_KEY","gemini"],["MISTRAL_API_KEY","mistral"],["COHERE_API_KEY","cohere"],["OLLAMA_BASE_URL","ollama"]],c=(process.env.CACHLY_EMBED_PROVIDER??"").toLowerCase(),b=u.find(([g])=>process.env[g]);if(c&&c!=="cachly"){const g=u.find(([,E])=>E===c)?.[0];g&&process.env[g]?r(`BYOK: ${c} (key present in ${g})`):i(`CACHLY_EMBED_PROVIDER=${c} but its key env var is not set \u2014 semantic search will fail`)}else r(b?`BYOK: ${b[1]} auto-detected (${b[0]} present)`:"Server-side embeddings (cachly) \u2014 no key needed, uses your JWT")}console.log(`
247
247
  ${"\u2500".repeat(40)}`),a===0?console.log(`\u2705 All checks passed (${o} ok)
248
248
  `):(console.log(`\u274C ${a} check(s) failed, ${o} passed
249
249
  `),console.log(`\u{1F4A1} Fix issues with: npx @cachly-dev/mcp-server@latest autopilot
250
- `),process.exit(1)),process.exit(0)}const ue=process.argv[2]==="autopilot";if(process.argv[2]==="autosetup"||process.argv[2]==="setup"||ue){const{writeFile:e,mkdir:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o,dirname:a}=await import("node:path"),{createInterface:r}=await import("node:readline"),i=Date.now(),p=ue?"autopilot":"setup",l=process.argv.indexOf("--api-url");l!==-1&&process.argv[l+1]&&(w=process.argv[l+1].replace(/\/+$/,""),console.log(`\u2139\uFE0F Using self-hosted backend: ${w}
251
- `)),C("setup_started");const d=process.stdin.isTTY===!0,f=ue||process.argv.includes("--yes")||process.argv.includes("-y")||!d;ue?console.log(`\u{1F916} Autopilot \u2014 one-command setup (auth \u2192 instance \u2192 configs \u2192 Brain), zero prompts.
250
+ `),process.exit(1)),process.exit(0)}const me=process.argv[2]==="autopilot";if(process.argv[2]==="autosetup"||process.argv[2]==="setup"||me){const{writeFile:e,mkdir:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o,dirname:a}=await import("node:path"),{createInterface:r}=await import("node:readline"),i=Date.now(),p=me?"autopilot":"setup",l=process.argv.indexOf("--api-url");l!==-1&&process.argv[l+1]&&(w=process.argv[l+1].replace(/\/+$/,""),console.log(`\u2139\uFE0F Using self-hosted backend: ${w}
251
+ `)),C("setup_started");const d=process.stdin.isTTY===!0,f=me||process.argv.includes("--yes")||process.argv.includes("-y")||!d;me?console.log(`\u{1F916} Autopilot \u2014 one-command setup (auth \u2192 instance \u2192 configs \u2192 Brain), zero prompts.
252
252
  `):!d&&!process.argv.includes("--yes")&&!process.argv.includes("-y")&&console.log(`\u2139\uFE0F Non-interactive terminal detected \u2014 running in automatic mode (no prompts).
253
- `);const h=r({input:process.stdin,output:process.stdout}),v=(m,_="")=>f?(console.log(`${m}${_}`),Promise.resolve(_)):new Promise(R=>h.question(m,Y=>R(Y.trim()||_)));console.log(`
253
+ `);const h=r({input:process.stdin,output:process.stdout}),x=(m,_="")=>f?(console.log(`${m}${_}`),Promise.resolve(_)):new Promise(R=>h.question(m,Y=>R(Y.trim()||_)));console.log(`
254
254
  \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
255
255
  `);let y=process.env.CACHLY_JWT??"";if(y)console.log(`\u2713 Using token from CACHLY_JWT env var
256
256
  `);else{console.log(`Step 1: Sign in to cachly (free, no credit card)
@@ -267,7 +267,7 @@ Timed out waiting for authorization. Aborting.
267
267
  \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:
268
268
  `),console.error(` \x1B[1mCACHLY_JWT=cky_live_xxx npx @cachly-dev/mcp-server@latest autopilot\x1B[0m
269
269
  `),console.error(` Or add it to your editor's MCP config under env.CACHLY_JWT.
270
- `),h.close(),process.exit(1)):(y=await v(" Paste API key (cky_live_...): "),y||(console.error(`
270
+ `),h.close(),process.exit(1)):(y=await x(" Paste API key (cky_live_...): "),y||(console.error(`
271
271
  API key is required. Aborting.
272
272
  `),h.close(),process.exit(1)),C("setup_auth_completed"),console.log(""))}}if(y.startsWith("eyJ")){process.stdout.write("\u23F3 Generating your API key...");try{const m=await fetch(`${w}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${y}`},body:JSON.stringify({name:"cachly-mcp-setup",scope:"read_write"})});if(!m.ok)throw new Error(`HTTP ${m.status}`);const _=await m.json();if(!_.key)throw new Error("no key in response");y=_.key,console.log(` \u2713
273
273
  `)}catch{console.log(` (skipped)
@@ -282,7 +282,7 @@ Could not create an instance automatically. Opening ${N("/instances",p)} \u2026
282
282
  `),ie(N("/instances",p)),h.close(),process.exit(1))}const c=u[0];u.length>1&&(console.log(`\u2139\uFE0F Multiple instances found \u2014 using most recent: ${c.name}`),console.log(` (Run with --instance-id <id> to use a different one)
283
283
  `)),console.log(`\u2713 Instance: ${c.name} (${c.id.slice(0,8)}\u2026)
284
284
  `),C("setup_instance_ready",{instance_id:c.id});const b=process.cwd(),g=[],{homedir:E}=await import("node:os"),j=E();g.push("claude"),s(o(b,".cursor"))&&g.push("cursor"),s(o(b,".windsurf"))&&g.push("windsurf"),s(o(b,".vscode"))&&g.push("copilot"),s(o(b,".continue"))&&g.push("continue");const A=process.platform==="darwin"?o(j,"Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev"):o(j,".vscode/extensions");(s(A)&&!g.includes("copilot")||s(A))&&g.push("cline");const $=process.platform==="darwin"?o(j,"Library/Application Support/Zed"):o(j,".config/zed");s($)&&g.push("zed");const k=m=>({claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",copilot:"GitHub Copilot",continue:"Continue.dev",cline:"Cline (VSCode)",zed:"Zed"})[m]??m,I=g;console.log(`Step 3: Configuring for: ${I.map(k).join(", ")}
285
- `);const{existsSync:H}=await import("node:fs"),T=[];let D=0;ne(y);for(const m of I){const _=pt[m]??".mcp.json",R=o(b,_);try{await t(a(R),{recursive:!0});const Y=H(R),J=await gt(R,y,c.id,m,{readFile:n,existsSync:H});await e(R,J,"utf-8"),console.log(`\u2705 ${Y?"Updated":"Written"}: ${_}`),D++}catch(Y){const J=Y.message;console.log(`\u26A0\uFE0F Could not write ${_}: ${J}`),console.log(" Fix permissions or run with sudo, then re-run setup."),T.push({file:_,reason:J})}}const q=o(j,".claude","mcp.json");try{await t(a(q),{recursive:!0});let m={};if(s(q))try{m=JSON.parse(await n(q,"utf-8"))}catch{}m.mcpServers??={},m.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:ce(y,c.id,{includeApiKey:!0})},await e(q,JSON.stringify(m,null,2),"utf-8"),console.log("\u2705 Written: ~/.claude/mcp.json (global \u2014 works in every project)"),D++}catch(m){const _=m.message;console.log(`\u26A0\uFE0F Could not write ~/.claude/mcp.json: ${_}`),T.push({file:"~/.claude/mcp.json",reason:_})}const S=await ht(b,c.id);for(const[m,_]of Object.entries(S))console.log(`${_==="updated"?"\u2705 Updated":_==="appended"?"\u2705 Appended to":"\u2705 Written"}: ${m}`);x=y;let L=0;if(s(o(b,".git"))){process.stdout.write("\u23F3 Bootstrapping Brain from git history (~10s)...");try{const m=await F("brain_from_git",{instance_id:c.id,repo_path:b,limit:100}),_=m.match(/Ingested: \*\*(\d+)\*\*/);L=_?parseInt(_[1],10):0,console.log(` \u2713 ${L} lesson${L===1?"":"s"} extracted from git history`);const R=lo(m);R&&(console.log(""),console.log(R))}catch(m){console.log(` (skipped: ${m.message.slice(0,80)})`)}}if(L===0){process.stdout.write("\u{1F331} Seeding 16 universal engineering lessons (first recall works instantly)...");try{await F("brain_seed_starter",{instance_id:c.id}),console.log(" \u2713");try{const m=await F("smart_recall",{instance_id:c.id,query:"docker build slow"}),_=Bo(m);_&&(console.log(""),console.log(po(_.topic,_.what)))}catch{}}catch(m){console.log(` (skipped: ${m.message.slice(0,60)})`)}}process.stdout.write(`
285
+ `);const{existsSync:H}=await import("node:fs"),T=[];let D=0;ne(y);for(const m of I){const _=dt[m]??".mcp.json",R=o(b,_);try{await t(a(R),{recursive:!0});const Y=H(R),J=await mt(R,y,c.id,m,{readFile:n,existsSync:H});await e(R,J,"utf-8"),console.log(`\u2705 ${Y?"Updated":"Written"}: ${_}`),D++}catch(Y){const J=Y.message;console.log(`\u26A0\uFE0F Could not write ${_}: ${J}`),console.log(" Fix permissions or run with sudo, then re-run setup."),T.push({file:_,reason:J})}}const q=o(j,".claude","mcp.json");try{await t(a(q),{recursive:!0});let m={};if(s(q))try{m=JSON.parse(await n(q,"utf-8"))}catch{}m.mcpServers??={},m.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:ce(y,c.id,{includeApiKey:!0})},await e(q,JSON.stringify(m,null,2),"utf-8"),console.log("\u2705 Written: ~/.claude/mcp.json (global \u2014 works in every project)"),D++}catch(m){const _=m.message;console.log(`\u26A0\uFE0F Could not write ~/.claude/mcp.json: ${_}`),T.push({file:"~/.claude/mcp.json",reason:_})}const S=await ft(b,c.id);for(const[m,_]of Object.entries(S))console.log(`${_==="updated"?"\u2705 Updated":_==="appended"?"\u2705 Appended to":"\u2705 Written"}: ${m}`);v=y;let L=0;if(s(o(b,".git"))){process.stdout.write("\u23F3 Bootstrapping Brain from git history (~10s)...");try{const m=await F("brain_from_git",{instance_id:c.id,repo_path:b,limit:100}),_=m.match(/Ingested: \*\*(\d+)\*\*/);L=_?parseInt(_[1],10):0,console.log(` \u2713 ${L} lesson${L===1?"":"s"} extracted from git history`);const R=co(m);R&&(console.log(""),console.log(R))}catch(m){console.log(` (skipped: ${m.message.slice(0,80)})`)}}if(L===0){process.stdout.write("\u{1F331} Seeding 16 universal engineering lessons (first recall works instantly)...");try{await F("brain_seed_starter",{instance_id:c.id}),console.log(" \u2713");try{const m=await F("smart_recall",{instance_id:c.id,query:"docker build slow"}),_=No(m);_&&(console.log(""),console.log(lo(_.topic,_.what)))}catch{}}catch(m){console.log(` (skipped: ${m.message.slice(0,60)})`)}}process.stdout.write(`
286
286
  \u23F3 Fetching your Brain health preview...`);try{const m=await fetch(`${w}/api/v1/instances/${c.id}/memory`,{headers:{Authorization:`Bearer ${y}`},signal:AbortSignal.timeout(6e3)});if(m.ok){const _=await m.json(),R=_.lesson_count??0,Y=_.context_count??0,J=Math.round(_.iq_boost_pct??0),z=R===0?"Intern \u{1F331}":R<10?"Junior Dev \u{1F527}":R<30?"Mid Dev \u26A1":R<60?"Senior Dev \u{1F9E0}":R<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}";if(console.log(` \u2713
287
287
  `),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 \u{1F9E0} Brain Health Report \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Lessons stored : ${String(R).padEnd(6)} \u2502 Level: ${z.padEnd(20)}\u2502`),console.log(`\u2502 Context entries : ${String(Y).padEnd(6)} \u2502 Quality score: ${String(J).padEnd(3)}% \u2502`),R===0&&(console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 Your Brain is empty and ready to learn. \u2502"),console.log("\u2502 After your first coding session it will contain: \u2502"),console.log("\u2502 \u2022 Lessons from every bug you fixed \u2502"),console.log("\u2502 \u2022 Your project's indexed files \u2502"),console.log("\u2502 \u2022 A session summary for next time \u2502")),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),R>=5){process.stdout.write(`
288
288
  \u23F3 Running predictive risk scan...`);try{const W=(await F("brain_predict",{instance_id:c.id,context:"starting a new development session"})).split(`
@@ -293,20 +293,20 @@ Could not create an instance automatically. Opening ${N("/instances",p)} \u2026
293
293
  `),console.log(` Dashboard: ${N(`/instances/${c.id}`,p)}`),console.log(`
294
294
  \u{1F4DB} Add a live badge to your README:`),console.log(` npx @cachly-dev/mcp-server@latest badge
295
295
  `),!f)try{if(console.log(`
296
- \u{1F451} Governance (optional \u2014 role model: admin \xB7 reviewer \xB7 contributor \xB7 viewer)`),console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),(await v(" Set yourself as the first admin? (y/N): ","N")).toLowerCase()==="y"){const _=await v(' Your handle (e.g. "alice"): ');_.trim()&&await F("team_assign_role",{instance_id:c.id,handle:_.trim(),role:"admin"}).catch(()=>"")&&(console.log(` \u2705 ${_.trim()} is now admin. Invite teammates:
296
+ \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 x(" Set yourself as the first admin? (y/N): ","N")).toLowerCase()==="y"){const _=await x(' Your handle (e.g. "alice"): ');_.trim()&&await F("team_assign_role",{instance_id:c.id,handle:_.trim(),role:"admin"}).catch(()=>"")&&(console.log(` \u2705 ${_.trim()} is now admin. Invite teammates:
297
297
  `),console.log(` team_assign_role(instance_id="${c.id}", handle="<teammate>", role="contributor", assigned_by="${_.trim()}")
298
298
  `))}else console.log(` Skipped \u2014 run team_assign_role at any time.
299
- `)}catch{}if(!f){const m=await v(" \u{1F4EC} Stay in the loop? Email for release notes [Enter to skip]: ");if(m&&m.includes("@"))try{await fetch(`${w}/api/newsletter/subscribe`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:m.trim().toLowerCase(),source:"mcp-setup"}),signal:AbortSignal.timeout(5e3)}),console.log(` \u2705 Subscribed \u2014 you'll only hear from us when it matters.
300
- `)}catch{}}try{const m=await De(process.cwd(),c.id,y||void 0);m==="written"?console.log(`
299
+ `)}catch{}if(!f){const m=await x(" \u{1F4EC} Stay in the loop? Email for release notes [Enter to skip]: ");if(m&&m.includes("@"))try{await fetch(`${w}/api/newsletter/subscribe`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:m.trim().toLowerCase(),source:"mcp-setup"}),signal:AbortSignal.timeout(5e3)}),console.log(` \u2705 Subscribed \u2014 you'll only hear from us when it matters.
300
+ `)}catch{}}try{const m=await Oe(process.cwd(),c.id,y||void 0);m==="written"?console.log(`
301
301
  \u2705 CLS git hook installed \u2014 your brain will learn from every commit.`):m==="upgraded"?console.log(`
302
- \u2705 CLS git hook upgraded to ${Me}.`):m==="appended"&&console.log(`
303
- \u2705 CLS git hook appended to existing post-commit.`)}catch{}if(I.includes("claude"))try{const m=await Ye(process.cwd(),c.id),_=m.scripts==="written"?"\u2705 Written":m.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${Je})`:"\u2713 Unchanged";console.log(`${_}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),m.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):m.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{}x=y;const ee=Math.round((Date.now()-i)/1e3);if(T.length>0&&C("setup_config_write_failed",{instance_id:c.id,failed:T.length,succeeded:D}),C("setup_completed",{instance_id:c.id,elapsed_s:ee,config_failures:T.length}),T.length>0&&D===0){console.log(`
302
+ \u2705 CLS git hook upgraded to ${De}.`):m==="appended"&&console.log(`
303
+ \u2705 CLS git hook appended to existing post-commit.`)}catch{}if(I.includes("claude"))try{const m=await Me(process.cwd(),c.id),_=m.scripts==="written"?"\u2705 Written":m.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${Ye})`:"\u2713 Unchanged";console.log(`${_}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),m.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):m.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{}v=y;const ee=Math.round((Date.now()-i)/1e3);if(T.length>0&&C("setup_config_write_failed",{instance_id:c.id,failed:T.length,succeeded:D}),C("setup_completed",{instance_id:c.id,elapsed_s:ee,config_failures:T.length}),T.length>0&&D===0){console.log(`
304
304
  \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(`
305
305
  Your Brain instance exists, but no editor knows about it yet.`),console.log(" Failed writes:");for(const m of T)console.log(` \u2022 ${m.file} \u2014 ${m.reason}`);console.log(`
306
306
  Fix the permissions above and re-run, or configure manually:`),console.log(` CACHLY_JWT=${y.slice(0,12)}\u2026 CACHLY_BRAIN_INSTANCE_ID=${c.id}`),console.log(` Docs: ${N("/docs/mcp",p)}
307
307
  `),h.close(),await new Promise(m=>setTimeout(m,300)),process.exit(1)}if(console.log(`
308
308
  \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 ${(ee+"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"),T.length>0){console.log(`
309
- \u26A0\uFE0F Some editor configs could not be written (others succeeded):`);for(const m of T)console.log(` \u2022 ${m.file} \u2014 ${m.reason}`);console.log(" Fix the permissions above and re-run setup to configure them too.")}console.log(""),h.close(),await new Promise(m=>setTimeout(m,300)),process.exit(0)}if(process.argv[2]==="index"){const{resolve:e}=await import("node:path"),t=process.argv.slice(3),n=i=>{const p=t.indexOf(`--${i}`);return p!==-1?t[p+1]:void 0},s=e(n("dir")??t.find(i=>!i.startsWith("--"))??"."),o=n("instance-id")??process.env.CACHLY_BRAIN_INSTANCE_ID,a=parseInt(n("max-files")??"500",10),r=n("namespace")??"cachly:sem:code";(!o||!x)&&(console.error(`
309
+ \u26A0\uFE0F Some editor configs could not be written (others succeeded):`);for(const m of T)console.log(` \u2022 ${m.file} \u2014 ${m.reason}`);console.log(" Fix the permissions above and re-run setup to configure them too.")}console.log(""),h.close(),await new Promise(m=>setTimeout(m,300)),process.exit(0)}if(process.argv[2]==="index"){const{resolve:e}=await import("node:path"),t=process.argv.slice(3),n=i=>{const p=t.indexOf(`--${i}`);return p!==-1?t[p+1]:void 0},s=e(n("dir")??t.find(i=>!i.startsWith("--"))??"."),o=n("instance-id")??process.env.CACHLY_BRAIN_INSTANCE_ID,a=parseInt(n("max-files")??"500",10),r=n("namespace")??"cachly:sem:code";(!o||!v)&&(console.error(`
310
310
  \u274C CACHLY_BRAIN_INSTANCE_ID and CACHLY_JWT must be set
311
311
  `),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
312
312
  `),process.exit(1)),console.log(`
@@ -315,23 +315,23 @@ Could not create an instance automatically. Opening ${N("/instances",p)} \u2026
315
315
  \u2705 Indexing complete.
316
316
  `)}catch(i){console.error(`
317
317
  \u274C Indexing failed: ${i.message}
318
- `),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=r=>{const i=t.indexOf(`--${r}`);return i!==-1?t[i+1]:void 0},s=e(n("dir")??t.find(r=>!r.startsWith("--"))??"."),o=n("instance-id")??process.env.CACHLY_BRAIN_INSTANCE_ID,a=parseInt(n("max-commits")??"50",10);(!o||!x)&&(console.error(`
318
+ `),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=r=>{const i=t.indexOf(`--${r}`);return i!==-1?t[i+1]:void 0},s=e(n("dir")??t.find(r=>!r.startsWith("--"))??"."),o=n("instance-id")??process.env.CACHLY_BRAIN_INSTANCE_ID,a=parseInt(n("max-commits")??"50",10);(!o||!v)&&(console.error(`
319
319
  \u274C CACHLY_BRAIN_INSTANCE_ID and CACHLY_JWT must be set
320
320
  `),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 .
321
321
  `),process.exit(1)),console.log(`
322
322
  \u{1F9E0} Learning from git history: ${s}`),console.log(` Instance: ${o.slice(0,8)}\u2026 Max commits: ${a}
323
- `);try{const r=await F("brain_from_git",{instance_id:o,repo_path:s,limit:a});console.log(r),C("brain_from_git",{api_key:x,instance_id:o}),console.log(`
323
+ `);try{const r=await F("brain_from_git",{instance_id:o,repo_path:s,limit:a});console.log(r),C("brain_from_git",{api_key:v,instance_id:o}),console.log(`
324
324
  \u2705 Brain learned from your commits.
325
325
  `),await new Promise(i=>setTimeout(i,300))}catch(r){console.error(`
326
326
  \u274C learn-git failed: ${r.message}
327
- `),process.exit(1)}process.exit(0)}if(process.argv[2]==="ambient-recall"){try{process.stdin.isTTY&&process.exit(0);const e=[];for await(const i of process.stdin)e.push(i);const t=Buffer.concat(e).toString("utf-8"),n=Ue(t);if(n?.hook_event_name==="Stop"&&n.transcript_path)try{const{readFileSync:i}=await import("node:fs"),p=i(n.transcript_path,"utf-8").split(`
328
- `),l=go(p,n.stop_hook_active===!0);l&&(process.stdout.write(l),process.exit(0))}catch{}x||(x=we()??""),x||(console.error("cachly ambient-recall: no API key found (CACHLY_JWT/CACHLY_API_KEY env, ~/.cachly/credentials.json, or .mcp.json) \u2014 recall skipped for this turn."),process.exit(0));const s=process.env.CACHLY_BRAIN_INSTANCE_ID??B,o=Ue(t);if(o?.hook_event_name==="Stop"){const i=mo(o);i&&s&&await F("auto_learn_session",{instance_id:s,observations:[i]}),process.exit(0)}let a;const r=await uo(t,bo({instanceId:s,smartRecall:async i=>String(await F("smart_recall",{instance_id:s,query:i})??""),loadMemory:()=>ho(),saveMemory:i=>yo(i),backoff:async()=>Ge(await xe()),onInject:(i,p)=>{const l={ts:new Date().toISOString(),event:p,injected:i,prevented:0};We(l),a=Qe(s,l)}}));r&&process.stdout.write(r),a&&await Promise.race([a,new Promise(i=>setTimeout(i,500))])}catch{}process.exit(0)}if(process.argv[2]==="ambient-credit"){try{const e=Math.round(Number(process.argv[3]));if(Number.isFinite(e)&&e>0){const t=Math.min(e,2e4),n=process.argv.slice(4).join(" ").slice(0,200)||void 0,s={ts:new Date().toISOString(),event:"credit",injected:0,prevented:t,note:n};await We(s),await Qe(process.env.CACHLY_BRAIN_INSTANCE_ID??B,s),console.log(`\u2705 ambient credit recorded: ${t} tokens${n?` (${n})`:""}`)}else console.error("Usage: npx @cachly-dev/mcp-server@latest ambient-credit <tokens-saved> [note]")}catch{}process.exit(0)}if(process.argv[2]==="ambient-stats"){const e=await xe(),t=No(e),n=Ge(e),s=e.slice(-5);if(console.log(`
327
+ `),process.exit(1)}process.exit(0)}if(process.argv[2]==="ambient-recall"){try{process.stdin.isTTY&&process.exit(0);const e=[];for await(const i of process.stdin)e.push(i);const t=Buffer.concat(e).toString("utf-8"),n=Je(t);if(n?.hook_event_name==="Stop"&&n.transcript_path)try{const{readFileSync:i}=await import("node:fs"),p=i(n.transcript_path,"utf-8").split(`
328
+ `),l=go(p,n.stop_hook_active===!0);l&&(process.stdout.write(l),process.exit(0))}catch{}v||(v=pe()??""),v||(console.error("cachly ambient-recall: no API key found (CACHLY_JWT/CACHLY_API_KEY env, ~/.cachly/credentials.json, or .mcp.json) \u2014 recall skipped for this turn."),process.exit(0));const s=process.env.CACHLY_BRAIN_INSTANCE_ID??B,o=Je(t);if(o?.hook_event_name==="Stop"){const i=uo(o);i&&s&&await F("auto_learn_session",{instance_id:s,observations:[i]}),process.exit(0)}let a;const r=await po(t,{cfg:{apiUrl:w,jwt:v,instanceId:s},nebenlauf:process.argv[1]?[process.argv[1],"ambient-auffrischen"]:void 0,onInject:(i,p)=>{const l={ts:new Date().toISOString(),event:p,injected:i,prevented:0};Ue(l),a=Ze(s,l)}});r&&process.stdout.write(r),a&&await Promise.race([a,new Promise(i=>setTimeout(i,500))])}catch{}process.exit(0)}if(process.argv[2]==="ambient-auffrischen"){try{v||(v=pe()??"");const e=process.env.CACHLY_BRAIN_INSTANCE_ID??B;v&&e&&await mo({apiUrl:w,jwt:v,instanceId:e},{force:!0})}catch{}process.exit(0)}if(process.argv[2]==="ambient-credit"){try{const e=Math.round(Number(process.argv[3]));if(Number.isFinite(e)&&e>0){const t=Math.min(e,2e4),n=process.argv.slice(4).join(" ").slice(0,200)||void 0,s={ts:new Date().toISOString(),event:"credit",injected:0,prevented:t,note:n};await Ue(s),await Ze(process.env.CACHLY_BRAIN_INSTANCE_ID??B,s),console.log(`\u2705 ambient credit recorded: ${t} tokens${n?` (${n})`:""}`)}else console.error("Usage: npx @cachly-dev/mcp-server@latest ambient-credit <tokens-saved> [note]")}catch{}process.exit(0)}if(process.argv[2]==="ambient-stats"){const e=await We(),t=Eo(e),n=e.slice(-5);if(console.log(`
329
329
  \u{1F9E0} Ambient Recall \u2014 net-token ledger
330
- `),console.log(` Turns recorded: ${e.length}`),console.log(` Injected tokens: ${t.injected}`),console.log(` Prevented tokens: ${t.prevented} (agent-reported via ambient-credit)`),console.log(` NET: ${t.net>=0?"+":""}${t.net} tokens`),console.log(` Auto-backoff: ${n?"\u{1F534} ACTIVE \u2014 recent window is net-negative, injection paused":"\u{1F7E2} inactive"}`),s.length>0){console.log(`
331
- Last entries:`);for(const o of s){const a=o.prevented>0?`+${o.prevented} prevented`:`-${o.injected} injected`;console.log(` \u2022 ${o.ts.slice(0,19)} ${o.event}: ${a}${o.note?` (${o.note})`:""}`)}}console.log(""),process.exit(0)}if(process.argv[2]==="doctor"){const{checkNodeVersion:e,checkCredential:t,checkApiReachable:n,checkAuthAccepted:s,checkInstance:o,checkVectorCoverage:a,inspectAmbientHooks:r,checkHooks:i,checkLedger:p,renderDoctorReport:l,doctorExitCode:d}=await import("./doctor.js"),f=[e(),t(x),await n(w),await s(w,x),o(process.env.CACHLY_BRAIN_INSTANCE_ID??B),await a(w,x,process.env.CACHLY_BRAIN_INSTANCE_ID??B),i(r(process.cwd())),p(await xe(),fo())];console.log(l(f)),process.exit(d(f))}if(process.argv[2]==="cls-ingest"){try{const e=process.argv[3];(!e||!x)&&process.exit(0);let t;try{t=JSON.parse(e)}catch{process.exit(0)}const n=t.instance_id??B;(!n||!t.source)&&process.exit(0),await F("cls_ingest",{instance_id:n,source:t.source,payload:t.payload??{}})}catch{}process.exit(0)}if(!x){const e=wt();if(e)try{const t=await fetch($t(e),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:_t(e),signal:AbortSignal.timeout(8e3)});if(t.ok){const n=await t.json();n.access_token&&(x=n.access_token,ve(n.access_token),C("m2m_auth_completed",{grant:"client_credentials",client_id:e.clientId}),process.stderr.write(`\u{1F916} cachly: authenticated via client_credentials (M2M, headless).
330
+ `),console.log(` Turns recorded: ${e.length}`),console.log(` Injected tokens: ${t.injected}`),console.log(` Prevented tokens: ${t.prevented} (agent-reported via ambient-credit)`),console.log(` NET: ${t.net>=0?"+":""}${t.net} tokens`),n.length>0){console.log(`
331
+ Last entries:`);for(const s of n){const o=s.prevented>0?`+${s.prevented} prevented`:`-${s.injected} injected`;console.log(` \u2022 ${s.ts.slice(0,19)} ${s.event}: ${o}${s.note?` (${s.note})`:""}`)}}console.log(""),process.exit(0)}if(process.argv[2]==="doctor"){const{checkNodeVersion:e,checkCredential:t,checkApiReachable:n,checkAuthAccepted:s,checkInstance:o,checkVectorCoverage:a,inspectAmbientHooks:r,checkHooks:i,checkLedger:p,renderDoctorReport:l,doctorExitCode:d}=await import("./doctor.js"),f=[e(),t(v),await n(w),await s(w,v),o(process.env.CACHLY_BRAIN_INSTANCE_ID??B),await a(w,v,process.env.CACHLY_BRAIN_INSTANCE_ID??B),i(r(process.cwd())),p(await We(),ho())];console.log(l(f)),process.exit(d(f))}if(process.argv[2]==="cls-ingest"){try{const e=process.argv[3];(!e||!v)&&process.exit(0);let t;try{t=JSON.parse(e)}catch{process.exit(0)}const n=t.instance_id??B;(!n||!t.source)&&process.exit(0),await F("cls_ingest",{instance_id:n,source:t.source,payload:t.payload??{}})}catch{}process.exit(0)}if(!v){const e=xt();if(e)try{const t=await fetch(_t(e),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:wt(e),signal:AbortSignal.timeout(8e3)});if(t.ok){const n=await t.json();n.access_token&&(v=n.access_token,xe(n.access_token),C("m2m_auth_completed",{grant:"client_credentials",client_id:e.clientId}),process.stderr.write(`\u{1F916} cachly: authenticated via client_credentials (M2M, headless).
332
332
  `))}else process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth failed (${t.status}). Check CACHLY_CLIENT_ID / CACHLY_CLIENT_SECRET.
333
333
  `),C("m2m_auth_failed",{status:t.status})}catch(t){process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth error: ${t.message}
334
- `),C("m2m_auth_failed",{reason:"network"})}}const Go=["demo","share","publish","health","autosetup","setup","autopilot","init","digest","invite","badge","join","upgrade","bench","tool-specs","openapi","ambient-credit","ambient-stats","doctor"];if(!x&&!Go.includes(process.argv[2]??""))if(!process.argv[2]&&process.stdout.isTTY===!0&&Rt){const s=`
334
+ `),C("m2m_auth_failed",{reason:"network"})}}const zo=["demo","share","publish","health","autosetup","setup","autopilot","init","digest","invite","badge","join","upgrade","bench","tool-specs","openapi","ambient-credit","ambient-stats","doctor"];if(!v&&!zo.includes(process.argv[2]??""))if(!process.argv[2]&&process.stdout.isTTY===!0&&Et){const s=`
335
335
  \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
336
336
  \u2551 \u{1F9E0} cachly AI Brain \u2014 Setup required \u2551
337
337
  \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
@@ -351,7 +351,7 @@ Could not create an instance automatically. Opening ${N("/instances",p)} \u2026
351
351
  \u{1F9E0} cachly: no CACHLY_JWT set yet \u2014 call any cachly tool and a 10-second browser sign-in starts automatically.
352
352
  (Or run once: npx @cachly-dev/mcp-server@latest autopilot)
353
353
 
354
- `);else{const e=bt(x);if(e!==null){const t=Math.floor((e-Date.now())/6e4);t<=0?process.stderr.write(`
354
+ `);else{const e=yt(v);if(e!==null){const t=Math.floor((e-Date.now())/6e4);t<=0?process.stderr.write(`
355
355
  \u26A0\uFE0F cachly: CACHLY_JWT expired ${Math.abs(t)} minute(s) ago.
356
356
  All tool calls will fail. Get a fresh token at ${N("/setup-ai","jwt-expiry")}
357
357
 
@@ -363,7 +363,7 @@ Could not create an instance automatically. Opening ${N("/instances",p)} \u2026
363
363
  \u26A1 cachly update available: ${M} \u2192 ${n}
364
364
  Run: npx @cachly-dev/mcp-server@latest autopilot
365
365
 
366
- `)}}catch{}})();const me=process.env.PORT?parseInt(process.env.PORT,10):void 0;if(me){const{createServer:e}=await import("node:http");e((n,s)=>{const o=new URL(n.url??"/",`http://localhost:${me}`);if(o.pathname==="/health"){s.writeHead(200,{"Content-Type":"application/json"}),s.end(JSON.stringify({status:"ok",version:M,zeroResults:{total:Xt,last10:Qt.slice(-10).map(a=>({query:a.query,ts:new Date(a.ts).toISOString()}))}}));return}if(o.pathname==="/mcp"||o.pathname==="/"){(async()=>{const a=Wo(),r=new Lt({sessionIdGenerator:void 0});s.on("close",()=>{r.close().catch(()=>{}),a.close().catch(()=>{})});try{await a.connect(r),await r.handleRequest(n,s)}catch(i){process.stderr.write(`cachly-mcp HTTP: ${i.message}
367
- `),s.headersSent||(s.writeHead(500,{"Content-Type":"application/json"}),s.end(JSON.stringify({error:i.message})))}})();return}s.writeHead(404),s.end("not found")}).listen(me,()=>{process.stderr.write(`cachly-mcp HTTP server listening on :${me}
368
- `)})}else{const e=new Nt;await X.connect(e),typeof process.argv[2]=="string"&&!process.argv[2].startsWith("-")||(_o(),xo(process.stdin,n=>{process.stderr.write(`[cachly-mcp] ${n} \u2014 Session zu Ende, Server geht mit
369
- `),(async()=>{await $e().catch(()=>{});for(const[,s]of K)await s.quit().catch(()=>{});process.exit(0)})()}))}ke("cachly","startup",{version:M,mode:process.env.MCP_HTTP_PORT?"http":"stdio"}).catch(()=>{});export{ut as CLAUDE_MD_MARKER_END,Ce as CLAUDE_MD_MARKER_START,Zt as CROSS_LINGUAL_MAP,pt as EDITOR_FILES,qt as STOPWORDS,Kt as arabicLightStem,ft as buildClaudeMdBlock,zo as buildMcpConfig,ce as buildServerEnv,Vt as expandCrossLingual,zt as extractTimestamp,Gt as katakanaToRomaji,Wt as levenshtein,gt as mergeMcpConfig,Ft as recencyBoost,eo as reconnectOnce,Ut as splitMultiQuery,Mt as startBackgroundDevicePoll,Jt as tokenize,ht as writeInstructions};
366
+ `)}}catch{}})();const ge=process.env.PORT?parseInt(process.env.PORT,10):void 0;if(ge){const{createServer:e}=await import("node:http");e((n,s)=>{const o=new URL(n.url??"/",`http://localhost:${ge}`);if(o.pathname==="/health"){s.writeHead(200,{"Content-Type":"application/json"}),s.end(JSON.stringify({status:"ok",version:M,zeroResults:{total:Qt,last10:Zt.slice(-10).map(a=>({query:a.query,ts:new Date(a.ts).toISOString()}))}}));return}if(o.pathname==="/mcp"||o.pathname==="/"){(async()=>{const a=Jo(),r=new Nt({sessionIdGenerator:void 0});s.on("close",()=>{r.close().catch(()=>{}),a.close().catch(()=>{})});try{await a.connect(r),await r.handleRequest(n,s)}catch(i){process.stderr.write(`cachly-mcp HTTP: ${i.message}
367
+ `),s.headersSent||(s.writeHead(500,{"Content-Type":"application/json"}),s.end(JSON.stringify({error:i.message})))}})();return}s.writeHead(404),s.end("not found")}).listen(ge,()=>{process.stderr.write(`cachly-mcp HTTP server listening on :${ge}
368
+ `)})}else{const e=new Rt;await X.connect(e),typeof process.argv[2]=="string"&&!process.argv[2].startsWith("-")||(xo(),bo(process.stdin,n=>{process.stderr.write(`[cachly-mcp] ${n} \u2014 Session zu Ende, Server geht mit
369
+ `),(async()=>{await _e().catch(()=>{});for(const[,s]of K)await s.quit().catch(()=>{});process.exit(0)})()}))}Se("cachly","startup",{version:M,mode:process.env.MCP_HTTP_PORT?"http":"stdio"}).catch(()=>{});export{pt as CLAUDE_MD_MARKER_END,$e as CLAUDE_MD_MARKER_START,Vt as CROSS_LINGUAL_MAP,dt as EDITOR_FILES,zt as STOPWORDS,Gt as arabicLightStem,gt as buildClaudeMdBlock,Wo as buildMcpConfig,ce as buildServerEnv,Kt as expandCrossLingual,Ft as extractTimestamp,qt as katakanaToRomaji,Ut as levenshtein,mt as mergeMcpConfig,Wt as recencyBoost,Xt as reconnectOnce,Jt as splitMultiQuery,Dt as startBackgroundDevicePoll,Yt as tokenize,ft as writeInstructions};