@cachly-dev/mcp-server 0.10.201 → 0.10.203

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -234,21 +234,47 @@ Run `health` to see what is wired up in your editor. The full catalog is generat
234
234
 
235
235
  ```bash
236
236
  npx @cachly-dev/mcp-server@latest autopilot # One command: signs in, configures every editor, fills the Brain from git
237
- npx @cachly-dev/mcp-server@latest claim # Move a test Brain into your account, lessons included
238
- npx @cachly-dev/mcp-server@latest demo # Preview your Brain from git history (no account needed)
239
- npx @cachly-dev/mcp-server@latest bench # Run the recall benchmark (no sign-in needed)
240
- npx @cachly-dev/mcp-server@latest autosetup # Interactive variant: pick editors yourself
241
- npx @cachly-dev/mcp-server@latest health # Check token, API, editors and git hook
242
- npx @cachly-dev/mcp-server@latest export # Write every lesson to lessons.md and lessons.jsonl
243
- npx @cachly-dev/mcp-server@latest digest # Weekly Brain summary, shareable
244
- npx @cachly-dev/mcp-server@latest share # Generate a shareable stats card
245
- npx @cachly-dev/mcp-server@latest publish # Publish your Brain as an importable link (--public)
246
- npx @cachly-dev/mcp-server@latest badge # Get a live README badge for your Brain
247
- npx @cachly-dev/mcp-server@latest invite # Invite a teammate to share your Brain
248
- npx @cachly-dev/mcp-server@latest index . # Index a project's code into the Brain (CI-friendly)
249
- npx @cachly-dev/mcp-server@latest learn-git # Learn lessons from recent git commits
250
237
  ```
251
238
 
239
+ Every command below runs as `npx @cachly-dev/mcp-server@latest <command>`. Key and Brain
240
+ instance come from the environment or from `~/.cachly/credentials.json`, the file `autopilot` writes.
241
+
242
+ | Every day | |
243
+ |---|---|
244
+ | `status` | Lessons, recalls and team at a glance |
245
+ | `ambient-stats` | Tokens injected vs saved — the honest net, even when negative |
246
+ | `doctor` | Diagnose a broken or missing install, with the fix for each step |
247
+ | `health` | Check key, API, editor configs and git hook |
248
+ | `digest` | What your Brain learned this week, shareable |
249
+
250
+ | Set up | |
251
+ |---|---|
252
+ | `demo` | Preview your Brain from git history (no account needed) |
253
+ | `setup` (alias `autosetup`) | Interactive variant: pick editors yourself |
254
+ | `init --editor <id>` | Write the config for one editor, with flags |
255
+ | `claim` | Move a test Brain into your account, lessons included |
256
+ | `upgrade` | Check for updates |
257
+ | `uninstall` | Take cachly out of this project again. Shows your numbers first, then the plan; `--dry-run` only lists, `--global` adds the home folder |
258
+
259
+ | Your data | |
260
+ |---|---|
261
+ | `export` | Write every lesson to `lessons.md` and `lessons.jsonl` |
262
+ | `index [dir]` | Index a project's code into the Brain (CI-friendly) |
263
+ | `learn-git [repo]` | Learn lessons from recent git commits |
264
+
265
+ | Team & sharing | |
266
+ |---|---|
267
+ | `invite [email]` | Invite a teammate to share your Brain |
268
+ | `join <token>` | Accept a Brain invite |
269
+ | `share` | Generate a shareable stats card |
270
+ | `publish` | Publish your Brain as an importable link (`--public`) |
271
+ | `badge` | Get a live README badge for your Brain |
272
+
273
+ | More | |
274
+ |---|---|
275
+ | `bench` | Run the recall benchmark (no sign-in needed) |
276
+ | `tool-specs` / `openapi` | Tool definitions for other agent frameworks (OpenAI, Anthropic, LangChain, OpenAPI) |
277
+
252
278
  The method behind `bench` is described in [BENCH.md](./BENCH.md).
253
279
 
254
280
  > **Tip: learn from every merged PR.** Run `learn-git` in CI with the
@@ -1,9 +1,9 @@
1
- import{existsSync as H,readFileSync as R}from"node:fs";import{readFile as A,writeFile as k,chmod as D,mkdir as y}from"node:fs/promises";import{dirname as j,resolve as l}from"node:path";import{fileURLToPath as et}from"node:url";import{CURSOR_FLAG as rt}from"./cursor-hook.js";import{COPILOT_FLAG as nt,COPILOT_HOOK_EVENTS as st}from"./copilot-hook.js";import{CODEX_FLAG as it,CODEX_HOOK_EVENTS as ct}from"./codex-hook.js";import{GEMINI_FLAG as at,GEMINI_HOOK_EVENTS as ut}from"./gemini-hook.js";import{istCachlyEintrag as L}from"./hook-zugang.js";const G="v5",Zt="ambient-recall",S="cachly-ambient-einblendung.mjs";function E(t){return t.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}function P(t,o){return["#!/usr/bin/env node",`// cachly Ambient Recall \u2014 ${t} ${G}`,"// Pushes relevant memory into context automatically. Cross-platform Node hook","// (no shell script \u2014 runs identically on Windows/macOS/Linux). Never blocks","// the agent: every failure path exits 0 with no output (graceful degrade).",`// Runs the hook bundle next to this file (${S}) in this process.`,`process.env.CACHLY_BRAIN_INSTANCE_ID = '${E(o.instanceId)}';`,`process.env.CACHLY_HOOK_EVENT = '${E(t)}';`,`process.argv.splice(2, process.argv.length, '${E(t)}');`,"try {",` await import('./${S}');`,"} catch {"," process.exit(0);","}"].join(`
2
- `)}function M(){const t=j(et(import.meta.url));for(const o of[l(t,"..",w,S),l(t,"..","..",w,S)])if(H(o))return o;return null}function mt(t){return P("SessionStart",t)}function pt(t){return P("UserPromptSubmit",t)}function lt(t){return P("PreToolUse",t)}function St(t){return P("Stop",t)}const ft={SessionStart:30,UserPromptSubmit:10,PreToolUse:10,Stop:60},ht="Edit|Write|MultiEdit|NotebookEdit";function v(t,o){const e=(r,s,u)=>({...u?{matcher:u}:{},hooks:[{type:"command",command:`node "${s}"${o?` ${o(r)}`:""}`,timeout:ft[r]}]}),n={SessionStart:[e("SessionStart",t.sessionStart)],UserPromptSubmit:[e("UserPromptSubmit",t.userPromptSubmit)]};return t.preToolUse&&(n.PreToolUse=[e("PreToolUse",t.preToolUse,ht)]),t.stop&&(n.Stop=[e("Stop",t.stop)]),n}const K=".claude/hooks",dt=".claude/settings.json",J={SessionStart:"cachly-ambient-session-start.mjs",UserPromptSubmit:"cachly-ambient-prompt-submit.mjs",PreToolUse:"cachly-ambient-pre-tool.mjs",Stop:"cachly-ambient-stop.mjs"},bt=".claude/hooks/cachly-ambient-";function kt(t,o){const e=t.hooks??[];return e.length>0&&e.every(n=>{const r=n.command??"";return r.includes(bt)||o.has(r)||[...o].some(s=>r.includes(`"${s}"`))})}function gt(t,o){const e={...t,hooks:{...t.hooks??{}}},n=e.hooks,r=v(o),s=new Set([o.sessionStart,o.userPromptSubmit,o.preToolUse,o.stop].filter(c=>!!c));for(const[c,i]of Object.entries(r)){const a=(Array.isArray(n[c])?n[c]:[]).filter(f=>!kt(f,s));n[c]=[...a,...i]}const u=JSON.stringify(e)!==JSON.stringify(t);return{settings:e,changed:u}}async function qt(t,o,e,n={}){const r=l(t,K);await y(r,{recursive:!0});const s={instanceId:o,apiKey:e},u=["SessionStart","UserPromptSubmit","PreToolUse","Stop"],c={SessionStart:mt(s),UserPromptSubmit:pt(s),PreToolUse:lt(s),Stop:St(s)},i=m=>l(r,J[m]),a=M();if(!a)throw new Error(`cachly hook bundle ${S} missing from the package`);const f=R(a,"utf-8"),b=l(r,S),g=async m=>{try{return await A(m,"utf-8")}catch{return""}};let N=!1,O=await g(b)===f;for(const m of u){const $=await g(i(m));$&&(N=!0),$!==c[m]+`
3
- `&&(O=!1)}const d=O?"unchanged":N?"upgraded":"written";if(d!=="unchanged"){await k(b,f,"utf-8");for(const m of u)await k(i(m),c[m]+`
4
- `,"utf-8"),await D(i(m),493).catch(()=>{})}const p=l(t,dt),h=H(p);let U={};if(h)try{U=JSON.parse(await A(p,"utf-8"))}catch{U={}}const _=m=>n.portable?`$CLAUDE_PROJECT_DIR/${K}/${J[m]}`:i(m),{settings:tt,changed:ot}=gt(U,{sessionStart:_("SessionStart"),userPromptSubmit:_("UserPromptSubmit"),preToolUse:_("PreToolUse"),stop:_("Stop")});let T;return h?ot?T="merged":T="unchanged":T="written",T!=="unchanged"&&(await y(l(t,".claude"),{recursive:!0}),await k(p,JSON.stringify(tt,null,2)+`
5
- `,"utf-8")),{sessionStartPath:i("SessionStart"),promptSubmitPath:i("UserPromptSubmit"),preToolUsePath:i("PreToolUse"),stopPath:i("Stop"),bundlePath:b,scripts:d,settings:T}}const B=".cursor/hooks",Ot=".cursor/hooks.json",F="cachly-ambient-cursor.mjs",Tt={sessionStart:30,beforeSubmitPrompt:10,postToolUse:5};function I(t,o,e,n){return["#!/usr/bin/env node",`// cachly Ambient Recall \u2014 ${t} ${G}`,`// Einblendung fuer ${t}: ${e.join(", ")}.`,"// Blockiert nie: jeder Fehler endet mit Exit 0. Ruft das Buendel daneben",`// (${S}) in diesem Prozess.`,`process.env.CACHLY_BRAIN_INSTANCE_ID = '${E(n.instanceId)}';`,`process.argv.push('${o}');`,"try {",` await import('./${S}');`,"} catch {"," process.exit(0);","}"].join(`
6
- `)}function _t(t){return I("Cursor",rt,["sessionStart","beforeSubmitPrompt","postToolUse"],t)}function yt(){const t=o=>[{command:`node ${B}/${F} ${o}`,timeout:Tt[o]}];return{sessionStart:t("sessionStart"),beforeSubmitPrompt:t("beforeSubmitPrompt"),postToolUse:t("postToolUse")}}function Et(t){return V(t,yt())}function V(t,o){const e={...t.hooks??{}};for(const[r,s]of Object.entries(o)){Y(e[r],r);const u=(e[r]??[]).filter(c=>!L(c));e[r]=[...u,...s]}const n={...t,version:typeof t.version=="number"?t.version:1,hooks:e};return{datei:n,changed:JSON.stringify(n)!==JSON.stringify(t)}}function X(t,o){const e={...t.hooks??{}};for(const[r,s]of Object.entries(o)){Y(e[r],r);const u=(e[r]??[]).flatMap(c=>{const i=c?.hooks;if(!Array.isArray(i))return[c];const a=i.filter(f=>!L(f));return a.length===i.length?[c]:a.length?[{...c,hooks:a}]:[]});e[r]=[...u,...s]}const n={...t,hooks:e};return{datei:n,changed:JSON.stringify(n)!==JSON.stringify(t)}}async function x(t){const o=l(t.projectDir,t.hookDir),e=M();if(!e)throw new Error(`cachly hook bundle ${S} missing from the package`);const n=R(e,"utf-8"),r=l(o,S),s=l(o,t.skriptName),u=t.skript+`
7
- `,c=async p=>{try{return await A(p,"utf-8")}catch{return""}},i=l(t.projectDir,t.configDatei),a=H(i)?await c(i):"",f=!a.trim();let b;try{const p=a.charCodeAt(0)===65279?a.slice(1):a,h=f?{}:JSON.parse(p);if(!z(h))throw new C("is not a JSON object");if(h.hooks!==void 0&&!z(h.hooks))throw new C('has a "hooks" field that is not an object');b=t.merge(h,s)}catch(p){const h=p instanceof C?p.message:/^\s*\/\/|\/\*/m.test(a)?"has comments, and cachly only rewrites plain JSON":"is not valid JSON";return{scriptPath:s,bundlePath:r,hooksPath:i,scripts:"unchanged",hooks:"skipped",grund:h}}await y(o,{recursive:!0});const g=await c(s),O=g===u&&await c(r)===n?"unchanged":g?"upgraded":"written";O!=="unchanged"&&(await k(r,n,"utf-8"),await k(s,u,"utf-8"),await D(s,493).catch(()=>{}));let d;if(f?d="written":b.changed?d="merged":d="unchanged",d!=="unchanged"){const p=/^([ \t]+)"/m.exec(a)?.[1]??2;await y(j(i),{recursive:!0}),await k(i,JSON.stringify(b.datei,null,p)+`
8
- `,"utf-8")}return{scriptPath:s,bundlePath:r,hooksPath:i,scripts:O,hooks:d}}function z(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}class C extends Error{}function Y(t,o){if(t!==void 0&&!Array.isArray(t))throw new C(`has a "hooks.${o}" entry that is not a list`)}async function to(t,o){return x({projectDir:t,hookDir:B,skriptName:F,skript:_t({instanceId:o}),configDatei:Ot,merge:e=>Et(e)})}const W=".github/hooks",Pt=".github/hooks/cachly-ambient.json",Q="cachly-ambient-copilot.mjs",It={sessionStart:30,userPromptSubmitted:10,postToolUse:5};function xt(t){return I("VS Code / Copilot",nt,st,t)}function Ct(){const t=o=>[{type:"command",command:`node ${W}/${Q} ${o}`,cwd:".",timeoutSec:It[o]}];return{sessionStart:t("sessionStart"),userPromptSubmitted:t("userPromptSubmitted"),postToolUse:t("postToolUse")}}function Nt(t){return V(t,Ct())}async function oo(t,o){return x({projectDir:t,hookDir:W,skriptName:Q,skript:xt({instanceId:o}),configDatei:Pt,merge:e=>Nt(e)})}const Ut=".codex/hooks",Ht=".codex/hooks.json",At="cachly-ambient-codex.mjs",wt={SessionStart:30,UserPromptSubmit:10};function $t(t){return I("Codex",it,ct,t)}function Rt(t){const o=e=>[{hooks:[{type:"command",command:`node "${t}" ${e}`,timeout:wt[e]}]}];return{SessionStart:o("SessionStart"),UserPromptSubmit:o("UserPromptSubmit")}}function Dt(t,o){return X(t,Rt(o))}async function eo(t,o){return x({projectDir:t,hookDir:Ut,skriptName:At,skript:$t({instanceId:o}),configDatei:Ht,merge:(e,n)=>Dt(e,n)})}const Z=".gemini/hooks",jt=".gemini/settings.json",q="cachly-ambient-gemini.mjs",Lt={SessionStart:3e4,BeforeAgent:1e4},Gt={SessionStart:"cachly-briefing",BeforeAgent:"cachly-recall"};function Mt(t){return I("Gemini CLI",at,ut,t)}function vt(){const t=o=>[{hooks:[{name:Gt[o],type:"command",command:`node ${Z}/${q} ${o}`,timeout:Lt[o]}]}];return{SessionStart:t("SessionStart"),BeforeAgent:t("BeforeAgent")}}function Kt(t){return X(t,vt())}async function ro(t,o){return x({projectDir:t,hookDir:Z,skriptName:q,skript:Mt({instanceId:o}),configDatei:jt,merge:e=>Kt(e)})}const no=["SessionStart","UserPromptSubmit","Stop"],w="hooks";function so(){const t=`\${CLAUDE_PLUGIN_ROOT}/${w}/${S}`,o=v({sessionStart:t,userPromptSubmit:t,stop:t},e=>`${e} --plugin`);return JSON.stringify({hooks:o},null,2)+`
9
- `}export{Zt as AMBIENT_CLI_SUBCOMMAND,G as AMBIENT_HOOK_VERSION,Ht as CODEX_HOOKS_DATEI,Ut as CODEX_HOOK_DIR,At as CODEX_SKRIPT,wt as CODEX_TIMEOUTS,Pt as COPILOT_HOOKS_DATEI,W as COPILOT_HOOK_DIR,Q as COPILOT_SKRIPT,It as COPILOT_TIMEOUTS,B as CURSOR_HOOK_DIR,F as CURSOR_SKRIPT,Tt as CURSOR_TIMEOUTS,Z as GEMINI_HOOK_DIR,jt as GEMINI_SETTINGS_DATEI,q as GEMINI_SKRIPT,Lt as GEMINI_TIMEOUTS_MS,S as HOOK_BUENDEL,w as PLUGIN_HOOK_DIR,no as PLUGIN_HOOK_EVENTS,ht as PRE_TOOL_USE_MATCHER,v as buildAmbientSettingsHooks,$t as buildCodexHook,Rt as buildCodexHooks,xt as buildCopilotHook,Ct as buildCopilotHooks,_t as buildCursorHook,yt as buildCursorHooks,Mt as buildGeminiHook,vt as buildGeminiHooks,so as buildPluginHooksJson,lt as buildPreToolUseHook,mt as buildSessionStartHook,St as buildStopHook,pt as buildUserPromptSubmitHook,M as hookBuendelQuelle,qt as installAmbientHooks,eo as installCodexHooks,oo as installCopilotHooks,to as installCursorHooks,ro as installGeminiHooks,gt as mergeAmbientSettings,Dt as mergeCodexHooks,Nt as mergeCopilotHooks,Et as mergeCursorHooks,Kt as mergeGeminiHooks};
1
+ import{existsSync as A,readFileSync as D}from"node:fs";import{readFile as H,writeFile as k,chmod as R,mkdir as E}from"node:fs/promises";import{dirname as L,resolve as l}from"node:path";import{fileURLToPath as et}from"node:url";import{CURSOR_FLAG as rt}from"./cursor-hook.js";import{COPILOT_FLAG as nt,COPILOT_HOOK_EVENTS as st}from"./copilot-hook.js";import{CODEX_FLAG as it,CODEX_HOOK_EVENTS as ct}from"./codex-hook.js";import{GEMINI_FLAG as at,GEMINI_HOOK_EVENTS as ut}from"./gemini-hook.js";import{istCachlyEintrag as j}from"./hook-zugang.js";const G="v5",Zt="ambient-recall",S="cachly-ambient-einblendung.mjs";function y(t){return t.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}function P(t,o){return["#!/usr/bin/env node",`// cachly Ambient Recall \u2014 ${t} ${G}`,"// Pushes relevant memory into context automatically. Cross-platform Node hook","// (no shell script \u2014 runs identically on Windows/macOS/Linux). Never blocks","// the agent: every failure path exits 0 with no output (graceful degrade).",`// Runs the hook bundle next to this file (${S}) in this process.`,`process.env.CACHLY_BRAIN_INSTANCE_ID = '${y(o.instanceId)}';`,`process.env.CACHLY_HOOK_EVENT = '${y(t)}';`,`process.argv.splice(2, process.argv.length, '${y(t)}');`,"try {",` await import('./${S}');`,"} catch {"," process.exit(0);","}"].join(`
2
+ `)}function M(){const t=L(et(import.meta.url));for(const o of[l(t,"..",w,S),l(t,"..","..",w,S)])if(A(o))return o;return null}function mt(t){return P("SessionStart",t)}function pt(t){return P("UserPromptSubmit",t)}function lt(t){return P("PreToolUse",t)}function St(t){return P("Stop",t)}const ft={SessionStart:30,UserPromptSubmit:10,PreToolUse:10,Stop:60},ht="Edit|Write|MultiEdit|NotebookEdit";function v(t,o){const e=(r,s,u)=>({...u?{matcher:u}:{},hooks:[{type:"command",command:`node "${s}"${o?` ${o(r)}`:""}`,timeout:ft[r]}]}),n={SessionStart:[e("SessionStart",t.sessionStart)],UserPromptSubmit:[e("UserPromptSubmit",t.userPromptSubmit)]};return t.preToolUse&&(n.PreToolUse=[e("PreToolUse",t.preToolUse,ht)]),t.stop&&(n.Stop=[e("Stop",t.stop)]),n}const K=".claude/hooks",dt=".claude/settings.json",J={SessionStart:"cachly-ambient-session-start.mjs",UserPromptSubmit:"cachly-ambient-prompt-submit.mjs",PreToolUse:"cachly-ambient-pre-tool.mjs",Stop:"cachly-ambient-stop.mjs"},bt=".claude/hooks/cachly-ambient-";function kt(t,o){const e=t.hooks??[];return e.length>0&&e.every(n=>{const r=n.command??"";return r.includes(bt)||o.has(r)||[...o].some(s=>r.includes(`"${s}"`))})}function gt(t,o){const e={...t,hooks:{...t.hooks??{}}},n=e.hooks,r=v(o),s=new Set([o.sessionStart,o.userPromptSubmit,o.preToolUse,o.stop].filter(c=>!!c));for(const[c,i]of Object.entries(r)){const a=(Array.isArray(n[c])?n[c]:[]).filter(f=>!kt(f,s));n[c]=[...a,...i]}const u=JSON.stringify(e)!==JSON.stringify(t);return{settings:e,changed:u}}async function qt(t,o,e,n={}){const r=l(t,K);await E(r,{recursive:!0});const s={instanceId:o,apiKey:e},u=["SessionStart","UserPromptSubmit","PreToolUse","Stop"],c={SessionStart:mt(s),UserPromptSubmit:pt(s),PreToolUse:lt(s),Stop:St(s)},i=m=>l(r,J[m]),a=M();if(!a)throw new Error(`cachly hook bundle ${S} missing from the package`);const f=D(a,"utf-8"),b=l(r,S),g=async m=>{try{return await H(m,"utf-8")}catch{return""}};let U=!1,O=await g(b)===f;for(const m of u){const $=await g(i(m));$&&(U=!0),$!==c[m]+`
3
+ `&&(O=!1)}const d=O?"unchanged":U?"upgraded":"written";if(d!=="unchanged"){await k(b,f,"utf-8");for(const m of u)await k(i(m),c[m]+`
4
+ `,"utf-8"),await R(i(m),493).catch(()=>{})}const p=l(t,dt),h=A(p);let N={};if(h)try{N=JSON.parse(await H(p,"utf-8"))}catch{N={}}const T=m=>n.portable?`$CLAUDE_PROJECT_DIR/${K}/${J[m]}`:i(m),{settings:tt,changed:ot}=gt(N,{sessionStart:T("SessionStart"),userPromptSubmit:T("UserPromptSubmit"),preToolUse:T("PreToolUse"),stop:T("Stop")});let _;return h?ot?_="merged":_="unchanged":_="written",_!=="unchanged"&&(await E(l(t,".claude"),{recursive:!0}),await k(p,JSON.stringify(tt,null,2)+`
5
+ `,"utf-8")),{sessionStartPath:i("SessionStart"),promptSubmitPath:i("UserPromptSubmit"),preToolUsePath:i("PreToolUse"),stopPath:i("Stop"),bundlePath:b,scripts:d,settings:_}}const B=".cursor/hooks",Ot=".cursor/hooks.json",F="cachly-ambient-cursor.mjs",_t={sessionStart:30,beforeSubmitPrompt:10,postToolUse:5};function I(t,o,e,n){return["#!/usr/bin/env node",`// cachly Ambient Recall \u2014 ${t} ${G}`,`// Einblendung fuer ${t}: ${e.join(", ")}.`,"// Blockiert nie: jeder Fehler endet mit Exit 0. Ruft das Buendel daneben",`// (${S}) in diesem Prozess.`,`process.env.CACHLY_BRAIN_INSTANCE_ID = '${y(n.instanceId)}';`,`process.argv.push('${o}');`,"try {",` await import('./${S}');`,"} catch {"," process.exit(0);","}"].join(`
6
+ `)}function Tt(t){return I("Cursor",rt,["sessionStart","beforeSubmitPrompt","postToolUse"],t)}function Et(){const t=o=>[{command:`node ${B}/${F} ${o}`,timeout:_t[o]}];return{sessionStart:t("sessionStart"),beforeSubmitPrompt:t("beforeSubmitPrompt"),postToolUse:t("postToolUse")}}function yt(t){return V(t,Et())}function V(t,o){const e={...t.hooks??{}};for(const[r,s]of Object.entries(o)){Y(e[r],r);const u=(e[r]??[]).filter(c=>!j(c));e[r]=[...u,...s]}const n={...t,version:typeof t.version=="number"?t.version:1,hooks:e};return{datei:n,changed:JSON.stringify(n)!==JSON.stringify(t)}}function X(t,o){const e={...t.hooks??{}};for(const[r,s]of Object.entries(o)){Y(e[r],r);const u=(e[r]??[]).flatMap(c=>{const i=c?.hooks;if(!Array.isArray(i))return[c];const a=i.filter(f=>!j(f));return a.length===i.length?[c]:a.length?[{...c,hooks:a}]:[]});e[r]=[...u,...s]}const n={...t,hooks:e};return{datei:n,changed:JSON.stringify(n)!==JSON.stringify(t)}}async function x(t){const o=l(t.projectDir,t.hookDir),e=M();if(!e)throw new Error(`cachly hook bundle ${S} missing from the package`);const n=D(e,"utf-8"),r=l(o,S),s=l(o,t.skriptName),u=t.skript+`
7
+ `,c=async p=>{try{return await H(p,"utf-8")}catch{return""}},i=l(t.projectDir,t.configDatei),a=A(i)?await c(i):"",f=!a.trim();let b;try{const p=a.charCodeAt(0)===65279?a.slice(1):a,h=f?{}:JSON.parse(p);if(!z(h))throw new C("is not a JSON object");if(h.hooks!==void 0&&!z(h.hooks))throw new C('has a "hooks" field that is not an object');b=t.merge(h,s)}catch(p){const h=p instanceof C?p.message:/^\s*\/\/|\/\*/m.test(a)?"has comments, and cachly only rewrites plain JSON":"is not valid JSON";return{scriptPath:s,bundlePath:r,hooksPath:i,scripts:"unchanged",hooks:"skipped",grund:h}}await E(o,{recursive:!0});const g=await c(s),O=g===u&&await c(r)===n?"unchanged":g?"upgraded":"written";O!=="unchanged"&&(await k(r,n,"utf-8"),await k(s,u,"utf-8"),await R(s,493).catch(()=>{}));let d;if(f?d="written":b.changed?d="merged":d="unchanged",d!=="unchanged"){const p=/^([ \t]+)"/m.exec(a)?.[1]??2;await E(L(i),{recursive:!0}),await k(i,JSON.stringify(b.datei,null,p)+`
8
+ `,"utf-8")}return{scriptPath:s,bundlePath:r,hooksPath:i,scripts:O,hooks:d}}function z(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}class C extends Error{}function Y(t,o){if(t!==void 0&&!Array.isArray(t))throw new C(`has a "hooks.${o}" entry that is not a list`)}async function to(t,o){return x({projectDir:t,hookDir:B,skriptName:F,skript:Tt({instanceId:o}),configDatei:Ot,merge:e=>yt(e)})}const W=".github/hooks",Pt=".github/hooks/cachly-ambient.json",Q="cachly-ambient-copilot.mjs",It={sessionStart:30,userPromptSubmitted:10,postToolUse:5};function xt(t){return I("VS Code / Copilot",nt,st,t)}function Ct(){const t=o=>[{type:"command",command:`node ${W}/${Q} ${o}`,cwd:".",timeoutSec:It[o]}];return{sessionStart:t("sessionStart"),userPromptSubmitted:t("userPromptSubmitted"),postToolUse:t("postToolUse")}}function Ut(t){return V(t,Ct())}async function oo(t,o){return x({projectDir:t,hookDir:W,skriptName:Q,skript:xt({instanceId:o}),configDatei:Pt,merge:e=>Ut(e)})}const Nt=".codex/hooks",At=".codex/hooks.json",Ht="cachly-ambient-codex.mjs",wt={SessionStart:30,UserPromptSubmit:10};function $t(t){return I("Codex",it,ct,t)}function Dt(t){const o=e=>[{hooks:[{type:"command",command:`node "${t}" ${e}`,timeout:wt[e]}]}];return{SessionStart:o("SessionStart"),UserPromptSubmit:o("UserPromptSubmit")}}function Rt(t,o){return X(t,Dt(o))}async function eo(t,o){return x({projectDir:t,hookDir:Nt,skriptName:Ht,skript:$t({instanceId:o}),configDatei:At,merge:(e,n)=>Rt(e,n)})}const Z=".gemini/hooks",Lt=".gemini/settings.json",q="cachly-ambient-gemini.mjs",jt={SessionStart:3e4,BeforeAgent:1e4},Gt={SessionStart:"cachly-briefing",BeforeAgent:"cachly-recall"};function Mt(t){return I("Gemini CLI",at,ut,t)}function vt(){const t=o=>[{hooks:[{name:Gt[o],type:"command",command:`node ${Z}/${q} ${o}`,timeout:jt[o]}]}];return{SessionStart:t("SessionStart"),BeforeAgent:t("BeforeAgent")}}function Kt(t){return X(t,vt())}async function ro(t,o){return x({projectDir:t,hookDir:Z,skriptName:q,skript:Mt({instanceId:o}),configDatei:Lt,merge:e=>Kt(e)})}const no=["SessionStart","UserPromptSubmit","Stop"],w="hooks";function so(){const t=`\${CLAUDE_PLUGIN_ROOT}/${w}/${S}`,o=v({sessionStart:t,userPromptSubmit:t,stop:t},e=>`${e} --plugin`);return JSON.stringify({hooks:o},null,2)+`
9
+ `}export{Zt as AMBIENT_CLI_SUBCOMMAND,G as AMBIENT_HOOK_VERSION,K as CLAUDE_HOOK_DIR,dt as CLAUDE_SETTINGS_DATEI,At as CODEX_HOOKS_DATEI,Nt as CODEX_HOOK_DIR,Ht as CODEX_SKRIPT,wt as CODEX_TIMEOUTS,Pt as COPILOT_HOOKS_DATEI,W as COPILOT_HOOK_DIR,Q as COPILOT_SKRIPT,It as COPILOT_TIMEOUTS,Ot as CURSOR_HOOKS_DATEI,B as CURSOR_HOOK_DIR,F as CURSOR_SKRIPT,_t as CURSOR_TIMEOUTS,Z as GEMINI_HOOK_DIR,Lt as GEMINI_SETTINGS_DATEI,q as GEMINI_SKRIPT,jt as GEMINI_TIMEOUTS_MS,S as HOOK_BUENDEL,w as PLUGIN_HOOK_DIR,no as PLUGIN_HOOK_EVENTS,ht as PRE_TOOL_USE_MATCHER,v as buildAmbientSettingsHooks,$t as buildCodexHook,Dt as buildCodexHooks,xt as buildCopilotHook,Ct as buildCopilotHooks,Tt as buildCursorHook,Et as buildCursorHooks,Mt as buildGeminiHook,vt as buildGeminiHooks,so as buildPluginHooksJson,lt as buildPreToolUseHook,mt as buildSessionStartHook,St as buildStopHook,pt as buildUserPromptSubmitHook,M as hookBuendelQuelle,qt as installAmbientHooks,eo as installCodexHooks,oo as installCopilotHooks,to as installCursorHooks,ro as installGeminiHooks,gt as mergeAmbientSettings,Rt as mergeCodexHooks,Ut as mergeCopilotHooks,yt as mergeCursorHooks,Kt as mergeGeminiHooks};
@@ -1,8 +1,8 @@
1
- import{existsSync as _}from"node:fs";import{readFile as m,writeFile as o,chmod as c,mkdir as p}from"node:fs/promises";import{resolve as s}from"node:path";import{instanzIdFuerSkript as f,schluesselFuerSkript as $}from"./git-ohne-shell.js";const u="v1",h=/(?:#!\/bin\/sh\n)?# cachly brain_watch[\s\S]*?\nexit 0\n?/;async function H(r,e,d){if(!_(s(r,".git")))return{result:"skipped-no-git",hookPath:""};const l=s(r,".git","hooks"),t=s(l,"post-commit");await p(l,{recursive:!0});const i=w(e,d);let n="";try{n=await m(t,"utf-8")}catch{}if(!n)return await o(t,i+`
1
+ import{existsSync as _}from"node:fs";import{readFile as p,writeFile as o,chmod as c,mkdir as m}from"node:fs/promises";import{resolve as s}from"node:path";import{instanzIdFuerSkript as f,schluesselFuerSkript as $}from"./git-ohne-shell.js";const u="v1",h=/(?:#!\/bin\/sh\n)?# cachly brain_watch[\s\S]*?\nexit 0\n?/;async function H(r,e,d){if(!_(s(r,".git")))return{result:"skipped-no-git",hookPath:""};const l=s(r,".git","hooks"),t=s(l,"post-commit");await m(l,{recursive:!0});const i=w(e,d);let n="";try{n=await p(t,"utf-8")}catch{}if(!n)return await o(t,i+`
2
2
  `,"utf-8"),await c(t,493).catch(()=>{}),{result:"written",hookPath:t};if(n.includes(`cachly brain_watch \u2014 Auto-Learn ${u}`))return{result:"unchanged",hookPath:t};if(h.test(n)){const a=n.replace(h,i);return await o(t,a.endsWith(`
3
3
  `)?a:a+`
4
4
  `,"utf-8"),await c(t,493).catch(()=>{}),{result:"upgraded",hookPath:t}}return await o(t,n.trimEnd()+`
5
5
 
6
6
  `+i+`
7
7
  `,"utf-8"),await c(t,493).catch(()=>{}),{result:"appended",hookPath:t}}function w(r,e){return r=f(r),e&&(e=$(e)),["#!/bin/sh",`# cachly brain_watch \u2014 Auto-Learn ${u}`,"# Silently teaches your Brain after every commit \u2014 no manual brain_from_git needed.",...e?[`CACHLY_JWT="${e}"`]:[],'_BW_SHA=$(git rev-parse HEAD 2>/dev/null || echo "")',"_BW_MSG=$(git log -1 --pretty=%B 2>/dev/null | head -1 | cut -c1-200)","_BW_FILES=$(git diff-tree --no-commit-id -r --name-only HEAD 2>/dev/null | tr '\\n' '\\t' | sed 's/\\t$//')","(curl -s -o /dev/null -m 8 \\",` -X POST "https://api.cachly.dev/api/v1/instances/${r}/learn" \\`,' -H "Authorization: Bearer ${CACHLY_JWT}" \\',' -H "Content-Type: application/json" \\',` --data-raw "{\\"message\\":\\"$(echo "$_BW_MSG" | sed 's/"/\\\\"/g')\\",\\"sha\\":\\"$_BW_SHA\\",\\"files\\":[$(echo "$_BW_FILES" | tr '\\t' '\\n' | grep -v '^$' | sed 's/.*/\\"&\\"/' | tr '\\n' ',' | sed 's/,$//')],\\"source\\":\\"brain_watch\\"}" \\`,") 2>/dev/null &","exit 0"].join(`
8
- `)}export{u as BRAIN_WATCH_HOOK_VERSION,w as buildBrainWatchHook,H as installBrainWatchHook};
8
+ `)}export{h as BRAIN_WATCH_BLOCK_RE,u as BRAIN_WATCH_HOOK_VERSION,w as buildBrainWatchHook,H as installBrainWatchHook};
@@ -1,8 +1,8 @@
1
- import{existsSync as S}from"node:fs";import{readFile as m,writeFile as r,chmod as s,mkdir as d}from"node:fs/promises";import{resolve as a}from"node:path";import{instanzIdFuerSkript as C}from"./git-ohne-shell.js";const p="v3",u=/(?:#!\/bin\/sh\n)?# cachly CLS[\s\S]*?\nexit 0\n?/;async function A(e,c,h){if(!S(a(e,".git")))return"skipped-no-git";const l=a(e,".git","hooks"),t=a(l,"post-commit");await d(l,{recursive:!0});const n=L(c);let i="";try{i=await m(t,"utf-8")}catch{}if(!i)return await r(t,n+`
1
+ import{existsSync as S}from"node:fs";import{readFile as m,writeFile as r,chmod as s,mkdir as d}from"node:fs/promises";import{resolve as a}from"node:path";import{instanzIdFuerSkript as C}from"./git-ohne-shell.js";const p="v3",u=/(?:#!\/bin\/sh\n)?# cachly CLS[\s\S]*?\nexit 0\n?/;async function x(e,c,h){if(!S(a(e,".git")))return"skipped-no-git";const l=a(e,".git","hooks"),t=a(l,"post-commit");await d(l,{recursive:!0});const n=L(c);let i="";try{i=await m(t,"utf-8")}catch{}if(!i)return await r(t,n+`
2
2
  `,"utf-8"),await s(t,493).catch(()=>{}),"written";if(i.includes(`cachly CLS \u2014 Continuous Learning Stream ${p}`))return"unchanged";if(u.test(i)){const o=i.replace(u,n);return await r(t,o.endsWith(`
3
3
  `)?o:o+`
4
4
  `,"utf-8"),await s(t,493).catch(()=>{}),"upgraded"}return await r(t,i.trimEnd()+`
5
5
 
6
6
  `+n+`
7
7
  `,"utf-8"),await s(t,493).catch(()=>{}),"appended"}const _="try{var p={instance_id:process.env.CACHLY_BRAIN_INSTANCE_ID,source:'git_commit',payload:{message:process.env.CLS_MSG||'',sha:process.env.CLS_SHA||'',files:(process.env.CLS_FILES||'').split(',').filter(Boolean)}};require('child_process').execFileSync('npx',['@cachly-dev/mcp-server@latest','cls-ingest',JSON.stringify(p)],{stdio:'ignore',timeout:8000});}catch(e){}";function L(e,c){return e=C(e),["#!/bin/sh",`# cachly CLS \u2014 Continuous Learning Stream ${p}`,"# Runs silently on every commit to keep your brain up to date.",`export CACHLY_BRAIN_INSTANCE_ID="${e}"`,'CLS_SHA=$(git rev-parse HEAD 2>/dev/null || echo "")',"CLS_MSG=$(git log -1 --pretty=%B 2>/dev/null | head -1 | cut -c1-200)","CLS_FILES=$(git diff-tree --no-commit-id -r --name-only HEAD 2>/dev/null | tr '\\n' ',' | sed 's/,$//')","export CLS_SHA CLS_MSG CLS_FILES",`node -e "${_}" 2>/dev/null &`,"exit 0"].join(`
8
- `)}export{p as CLS_HOOK_VERSION,L as buildClsPostCommitHook,A as installClsPostCommitHook};
8
+ `)}export{u as CLS_BLOCK_RE,p as CLS_HOOK_VERSION,L as buildClsPostCommitHook,x as installClsPostCommitHook};