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