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