@cachly-dev/mcp-server 0.10.173 → 0.10.175

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
@@ -340,9 +340,9 @@ MCP tool — bulk-ingests past outcomes the same way `brain_from_git` ingests co
340
340
 
341
341
  ---
342
342
 
343
- ## MCP Tools (123 total, 27 in the default catalogue)
343
+ ## MCP Tools (124 total, 27 in the default catalogue)
344
344
 
345
- **Your editor sees 27 of them, not 123 — on purpose.** The full list cost
345
+ **Your editor sees 27 of them, not 124 — on purpose.** The full list cost
346
346
  ~27,750 tokens in *every* request, which is 14 % of a 200k window gone before
347
347
  you type anything. The tools you use daily are listed individually; the other
348
348
  96 sit behind one dispatcher:
@@ -354,7 +354,7 @@ cachly_tool(tool: "team_roster", describe: true) get its schema first
354
354
 
355
355
  Nothing is unreachable: the server dispatches by name and never consults the
356
356
  catalogue, so `team_roster` called directly still works. Set
357
- `CACHLY_ALLE_WERKZEUGE=1` to get all 123 listed again.
357
+ `CACHLY_ALLE_WERKZEUGE=1` to get all 124 listed again.
358
358
 
359
359
  The full tool catalog is generated from `sdk/mcp/src/tools.ts`. Cross-surface
360
360
  coverage is tracked in [`../../docs/generated/surface-parity.md`](../../docs/generated/surface-parity.md),
@@ -467,7 +467,7 @@ following. Manual snippets are in the **Manual Setup** section below.
467
467
 
468
468
  | Editor / Client | Auto-setup | Config file written | Global config | Notes |
469
469
  |---|---|---|---|---|
470
- | **Claude Code** | ✅ | `~/.claude/mcp.json` + `.mcp.json` | ✅ global always | Runtime device-flow sign-in on first tool call |
470
+ | **Claude Code** | ✅ | `~/.claude/mcp.json` + `.mcp.json` | ✅ global always | No key: test Brain on first tool call; browser sign-in only as fallback |
471
471
  | **Cursor** | ✅ detected via `.cursor/` | `.cursor/mcp.json` | — | Project-level; restart Cursor after setup |
472
472
  | **Windsurf** | ✅ detected via `.windsurf/` | `.windsurf/mcp.json` | — | Project-level; restart Windsurf after setup |
473
473
  | **VS Code + Copilot** | ✅ detected via `.vscode/` | `.vscode/mcp.json` | — | Requires VS Code MCP extension or Copilot chat |
@@ -483,7 +483,8 @@ following. Manual snippets are in the **Manual Setup** section below.
483
483
  |---|---|
484
484
  | `autosetup` from a real terminal (TTY) | OAuth device-flow → browser click → API key saved automatically |
485
485
  | `autosetup` from VSCode task / CI (non-TTY) | Auto-detects non-interactive, opens browser with step-by-step guide, prints `CACHLY_JWT=... autosetup` instruction |
486
- | First tool call from Claude Code (no JWT yet) | Inline device-flow: MCP returns URL + code, browser opens automatically, next call proceeds |
486
+ | First tool call without any key | Instant trial: an anonymous test Brain on EU servers, key saved to `~/.cachly/credentials.json` and `~/.claude/mcp.json`, the call proceeds. If that fails (offline, rate limit): inline device-flow with URL + code |
487
+ | First tool call with `CACHLY_BRAIN_INSTANCE_ID` set but no key | Inline device-flow (you already have a Brain — no second account is created) |
487
488
  | `CACHLY_JWT=cky_live_xxx npx ... autosetup` | Skips auth step entirely, uses provided key |
488
489
 
489
490
  > **Tip — fastest per-project setup from inside Claude Code:**
@@ -509,7 +510,8 @@ following. Manual snippets are in the **Manual Setup** section below.
509
510
  }
510
511
  }
511
512
  ```
512
- On the first tool call your AI will prompt you to sign in — takes 10 seconds.
513
+ Without a key, the first tool call creates a test Brain on EU servers — no sign-up.
514
+ Run `npx @cachly-dev/mcp-server@latest autopilot` to use your own account instead.
513
515
  </details>
514
516
 
515
517
  <details>
@@ -1,7 +1,2 @@
1
- import{decideRecall as p,commitInjection as h,emptyMemory as g,isTrivialPrompt as y,selectInjectable as d,estimateTokens as l}from"./ambient-recall.js";import{rahmeEin as b}from"./einblendung-rahmen.js";function v(e){const t=(e??"").trim();if(!t)return null;try{const r=JSON.parse(t);return r&&typeof r=="object"?r:null}catch{return null}}const S=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);function k(e){const t=e.hook_event_name??"UserPromptSubmit";if(t==="SessionStart")return e.source==="compact"||e.source==="clear"?null:"session start: recent lessons, active pitfalls, and known failure modes for this project";if(t==="PreToolUse"){if(e.tool_name&&!S.has(e.tool_name))return null;const n=e.tool_input?.file_path;return typeof n!="string"||!n.trim()?null:`known pitfalls, past bugs and lessons for file ${n.trim()}`}if(t==="Stop")return null;const r=(e.prompt??"").trim();return!r||y(r)?null:r}const w=/\b(fixed|resolved|behoben|gefixt|root cause|the bug was|der fehler (lag|war)|ursache (war|gefunden)|now passes|tests? (are|is|sind) (green|grün)|deployed successfully)\b/i;function O(e){const t=(e.last_assistant_message??"").trim();return t.length<80||!w.test(t)?null:{action:(t.split(`
2
- `).find(n=>n.trim().length>0)?.trim()??t).slice(0,200),outcome:"success",details:t.slice(0,500),severity:"minor"}}function $(e,t){const r=e.trim();if(l(r)<=t)return r;const n=Math.max(0,t*4),o=r.slice(0,n),i=o.lastIndexOf(" ");return(i>n*.6?o.slice(0,i):o).trimEnd()+"\u2026"}const x="(If this memory just saved you from a wrong path, record it: `npx @cachly-dev/mcp-server@latest ambient-credit <tokens-saved>`)";function _(e){const t=[];if(e.learnedAt){const r=new Date(e.learnedAt);Number.isNaN(r.getTime())||t.push(`am ${String(r.getDate()).padStart(2,"0")}.${String(r.getMonth()+1).padStart(2,"0")}.`)}if(e.files?.length){const r=e.files.slice(0,2).join(", ");t.push(`in ${r}${e.files.length>2?` (+${e.files.length-2})`:""}`)}return e.outcome==="failure"?t.push("ging damals schief"):e.outcome==="success"&&t.push("so ging es damals gut aus"),t.length?` \u21B3 ${t.join(" \xB7 ")}`:""}function T(e,t=!1){if(e.length===0)return"";const r=e.length===1&&e[0].summary.includes(`
3
- `)?e[0].summary.trim():`\u{1F9E0} Relevant memory from your cachly brain (auto-recalled):
4
- `+e.map(o=>{const i=_(o);return`- ${o.summary.trim()}`+(i?`
5
- `+i:"")}).join(`
6
- `),n=b(r);return t?`${n}
7
- ${x}`:n}function P(e,t){return t?JSON.stringify({hookSpecificOutput:{hookEventName:e,additionalContext:t}}):""}async function j(e,t,r){let n;const o=new Promise(i=>{n=setTimeout(()=>i(r),t)});try{return await Promise.race([e,o])}finally{n&&clearTimeout(n)}}async function M(e,t){const r=v(e);if(!r)return"";const n=r.hook_event_name??"UserPromptSubmit",o=k(r);if(o===null)return"";try{if(t.backoff&&await t.backoff())return""}catch{}let i=[];try{i=await j(t.recall(o,n),t.timeoutMs??3e3,[])}catch{return""}if(!Array.isArray(i)||i.length===0)return"";const c=n==="UserPromptSubmit"?r.prompt??o:o,a=t.loadMemory?.()??g(),s=t.loadMemory?p(c,i,a,t.gate):{...d(c,i,t.gate),risk:"normal",suppressedDuplicates:[]};if(t.saveMemory)try{t.saveMemory(h(a,s))}catch{}if(!s.inject)return"";const m=n==="UserPromptSubmit"||n==="PreToolUse",u=T(s.selected,m),f=l(u);try{t.onInject?.(f,n)}catch{}return P(n,u)}export{x as CREDIT_FOOTER,P as buildHookOutput,T as formatContextBlock,_ as formatProvenance,v as parseHookPayload,k as recallQueryFor,M as runAmbient,O as stopObservation,$ as truncateToTokens};
1
+ import{promptEinblendung as c,holeBestand as u,sitzungsKontext as l,hookAusgabe as i,estimateTokens as a}from"./einblendung.js";function f(e){const t=(e??"").trim();if(!t)return null;try{const n=JSON.parse(t);return n&&typeof n=="object"?n:null}catch{return null}}const m=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);function p(e){const t=e.hook_event_name??"UserPromptSubmit";if(t==="SessionStart"||t==="Stop")return null;if(t==="PreToolUse"){if(e.tool_name&&!m.has(e.tool_name))return null;const r=e.tool_input?.file_path;if(typeof r!="string"||!r.trim())return null;const o=r.trim().replace(/\\/g,"/"),s=(e.cwd??"").replace(/\\/g,"/").replace(/\/+$/,"");return s&&o.toLowerCase().startsWith(s.toLowerCase()+"/")?o.slice(s.length+1):o}return(e.prompt??"").trim()||null}const g=/\b(fixed|resolved|behoben|gefixt|root cause|the bug was|der fehler (lag|war)|ursache (war|gefunden)|now passes|tests? (are|is|sind) (green|grün)|deployed successfully)\b/i;function b(e){const t=(e.last_assistant_message??"").trim();return t.length<80||!g.test(t)?null:{action:(t.split(`
2
+ `).find(r=>r.trim().length>0)?.trim()??t).slice(0,200),outcome:"success",details:t.slice(0,500),severity:"minor"}}function d(e){const t=e.action.toLowerCase().replace(/[^a-z0-9:\-_\s]/g,"").trim().split(/\s+/).slice(0,4).join("-");return{topic:t?t.includes(":")?t:`auto:${t}`:"auto:stop",outcome:e.outcome,what_worked:e.action,context:e.details,severity:e.severity,source:"ambient-stop",tags:["auto-learned"]}}const x=i,h=5e3;async function k(e,t){try{const n=f(e);if(!n)return"";const r=n.hook_event_name??"UserPromptSubmit";if(!t.cfg.jwt||!t.cfg.instanceId)return"";let o="";if(r==="SessionStart"){const{lessons:s}=await u(t.cfg,{force:!0,fetchFn:t.fetchFn});o=l(s)}else{const s=p(n);if(s===null)return"";o=(await c(s,t.cfg,{nebenlauf:t.nebenlauf,abrufMs:h,leser:r!=="PreToolUse",session:n.session_id??null,protokoll:t.protokoll,fetchFn:t.fetchFn})).kontext}if(!o)return"";try{t.onInject?.(a(o),r)}catch{}return i(r,o)}catch{return""}}export{h as PROMPT_ABRUF_MS,x as buildHookOutput,f as parseHookPayload,p as recallQueryFor,k as runEinblendung,d as stopLernanfrage,b as stopObservation};
@@ -0,0 +1 @@
1
+ import{fileURLToPath as o}from"node:url";import{AUFFRISCHEN as r,auffrischenHauptlauf as t,hookHauptlauf as i}from"./ambient-hook.js";const a=process.argv.slice(2);a[0]===r?await t():await i(a,o(import.meta.url));
@@ -0,0 +1,2 @@
1
+ import{readFileSync as w}from"node:fs";import{parseHookPayload as f,runEinblendung as y,stopLernanfrage as b,stopObservation as g}from"./ambient-cli.js";import{stopAntwort as U}from"./schreibbeleg.js";import{holeBestand as P}from"./einblendung.js";import{appendLedgerEntry as I,reportLedgerEntry as A}from"./ambient-ledger.js";import{findeInstanz as u,findeSchluessel as l,hookUmfeld as d,projektHatHook as H}from"./hook-zugang.js";const T="https://api.cachly.dev",v="ambient-auffrischen",m=new Set(["SessionStart","UserPromptSubmit","PreToolUse","Stop"]);async function k(t){try{const e=f(t.raw),n=e?.hook_event_name??t.args.find(o=>m.has(o))??t.umfeld.env.CACHLY_HOOK_EVENT??"";if(t.args.includes("--plugin")&&n&&H(n,t.umfeld))return"";if(n==="Stop"&&e?.transcript_path)try{const o=w(e.transcript_path,"utf-8").split(`
2
+ `),a=U(o,e.stop_hook_active===!0);if(a)return a}catch{}const i=l(t.umfeld),c=u(t.umfeld);if(!i||!c)return"";const s={apiUrl:t.apiUrl,jwt:i,instanceId:c};if(n==="Stop"){const o=e?g(e):null;return o&&await(t.fetchFn??fetch)(`${s.apiUrl}/api/v1/instances/${s.instanceId}/learn`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s.jwt}`},body:JSON.stringify(b(o)),signal:AbortSignal.timeout(8e3)}).catch(()=>{}),""}let r;const _=await(t.einblenden??y)(t.raw,{cfg:s,nebenlauf:t.selbst?[t.selbst,v]:void 0,fetchFn:t.fetchFn,onInject:(o,a)=>{const p={ts:new Date().toISOString(),event:a,injected:o,prevented:0};I(p),r=A(s,p,t.fetchFn)}});return r&&await Promise.race([r,new Promise(o=>setTimeout(o,500))]),_}catch{return""}}async function O(){if(process.stdin.isTTY)return"";const t=[];for await(const e of process.stdin)t.push(e);return Buffer.concat(t).toString("utf-8")}function h(){return process.env.CACHLY_API_URL||T}const S={SessionStart:25e3,UserPromptSubmit:8e3,PreToolUse:8e3,Stop:5e4};async function R(t,e){try{const n=await O(),i=f(n)?.hook_event_name??t.find(r=>m.has(r))??"",c=Number(process.env.CACHLY_HOOK_FRIST_MS)||S[i]||S.UserPromptSubmit,s=await Promise.race([k({args:t,raw:n,umfeld:d(),apiUrl:h(),selbst:e}),new Promise(r=>setTimeout(()=>r(""),c))]);s&&await new Promise(r=>process.stdout.write(s,()=>r()))}catch{}process.exit(0)}async function N(){try{const t=d(),e=l(t),n=u(t);e&&n&&await P({apiUrl:h(),jwt:e,instanceId:n},{force:!0})}catch{}process.exit(0)}export{v as AUFFRISCHEN,S as HOOK_FRIST_MS,T as STANDARD_API_URL,N as auffrischenHauptlauf,k as hookAntwort,R as hookHauptlauf};
@@ -1,5 +1,6 @@
1
- import{existsSync as v}from"node:fs";import{readFile as E,writeFile as y,chmod as N,mkdir as A}from"node:fs/promises";import{resolve as S}from"node:path";const O="v4",H="ambient-recall",w=`npx @cachly-dev/mcp-server@latest ${H}`;function P(t){return t.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}function d(t,o){const e=o.cliCommand??w;return["#!/usr/bin/env node",`// cachly Ambient Recall \u2014 ${t} ${O}`,"// 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).","import { spawn } from 'node:child_process';",`process.env.CACHLY_BRAIN_INSTANCE_ID = '${P(o.instanceId)}';`,"if (!process.env.CACHLY_JWT && process.env.CACHLY_API_KEY) process.env.CACHLY_JWT = process.env.CACHLY_API_KEY;",`process.env.CACHLY_HOOK_EVENT = '${P(t)}';`,"try {",` const child = spawn('${P(e)}', { shell: true, stdio: ['inherit', 'inherit', 'ignore'] });`," child.on('error', () => process.exit(0));"," child.on('close', () => process.exit(0));","} catch {"," process.exit(0);","}"].join(`
2
- `)}function L(t){return d("SessionStart",t)}function R(t){return d("UserPromptSubmit",t)}function $(t){return d("PreToolUse",t)}function M(t){return d("Stop",t)}const Y={SessionStart:30,UserPromptSubmit:10,PreToolUse:10,Stop:60},F="Edit|Write|MultiEdit|NotebookEdit";function J(t){const o=(c,n,r)=>({...r?{matcher:r}:{},hooks:[{type:"command",command:`node "${n}"`,timeout:Y[c]}]}),e={SessionStart:[o("SessionStart",t.sessionStart)],UserPromptSubmit:[o("UserPromptSubmit",t.userPromptSubmit)]};return t.preToolUse&&(e.PreToolUse=[o("PreToolUse",t.preToolUse,F)]),t.stop&&(e.Stop=[o("Stop",t.stop)]),e}const C=".claude/hooks",j=".claude/settings.json",k={SessionStart:"cachly-ambient-session-start.mjs",UserPromptSubmit:"cachly-ambient-prompt-submit.mjs",PreToolUse:"cachly-ambient-pre-tool.mjs",Stop:"cachly-ambient-stop.mjs"},K=".claude/hooks/cachly-ambient-";function B(t,o){const e=t.hooks??[];return e.length>0&&e.every(c=>{const n=c.command??"";return n.includes(K)||o.has(n)||[...o].some(r=>n.includes(`"${r}"`))})}function D(t,o){const e={...t,hooks:{...t.hooks??{}}},c=e.hooks,n=J(o),r=new Set([o.sessionStart,o.userPromptSubmit,o.preToolUse,o.stop].filter(a=>!!a));for(const[a,i]of Object.entries(n)){const f=(Array.isArray(c[a])?c[a]:[]).filter(m=>!B(m,r));c[a]=[...f,...i]}const l=JSON.stringify(e)!==JSON.stringify(t);return{settings:e,changed:l}}async function q(t,o,e,c={}){const n=S(t,C);await A(n,{recursive:!0});const r={instanceId:o,apiKey:e},l=["SessionStart","UserPromptSubmit","PreToolUse","Stop"],a={SessionStart:L(r),UserPromptSubmit:R(r),PreToolUse:$(r),Stop:M(r)},i=s=>S(n,k[s]),f=async s=>{try{return await E(s,"utf-8")}catch{return""}};let m=!1,g=!0;for(const s of l){const _=await f(i(s));_&&(m=!0),_!==a[s]+`
3
- `&&(g=!1)}const T=g?"unchanged":m?"upgraded":"written";if(T!=="unchanged")for(const s of l)await y(i(s),a[s]+`
4
- `,"utf-8"),await N(i(s),493).catch(()=>{});const h=S(t,j),U=v(h);let b={};if(U)try{b=JSON.parse(await E(h,"utf-8"))}catch{b={}}const p=s=>c.portable?`$CLAUDE_PROJECT_DIR/${C}/${k[s]}`:i(s),{settings:x,changed:I}=D(b,{sessionStart:p("SessionStart"),userPromptSubmit:p("UserPromptSubmit"),preToolUse:p("PreToolUse"),stop:p("Stop")});let u;return U?I?u="merged":u="unchanged":u="written",u!=="unchanged"&&(await A(S(t,".claude"),{recursive:!0}),await y(h,JSON.stringify(x,null,2)+`
5
- `,"utf-8")),{sessionStartPath:i("SessionStart"),promptSubmitPath:i("UserPromptSubmit"),preToolUsePath:i("PreToolUse"),stopPath:i("Stop"),scripts:T,settings:u}}export{H as AMBIENT_CLI_SUBCOMMAND,O as AMBIENT_HOOK_VERSION,F as PRE_TOOL_USE_MATCHER,J as buildAmbientSettingsHooks,$ as buildPreToolUseHook,L as buildSessionStartHook,M as buildStopHook,R as buildUserPromptSubmitHook,q as installAmbientHooks,D as mergeAmbientSettings};
1
+ import{existsSync as I,readFileSync as L}from"node:fs";import{readFile as A,writeFile as U,chmod as M,mkdir as w}from"node:fs/promises";import{dirname as j,resolve as l}from"node:path";import{fileURLToPath as B}from"node:url";const D="v5",st="ambient-recall",m="cachly-ambient-einblendung.mjs";function T(t){return t.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}function b(t,o){return["#!/usr/bin/env node",`// cachly Ambient Recall \u2014 ${t} ${D}`,"// 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 (${m}) in this process.`,`process.env.CACHLY_BRAIN_INSTANCE_ID = '${T(o.instanceId)}';`,`process.env.CACHLY_HOOK_EVENT = '${T(t)}';`,`process.argv.splice(2, process.argv.length, '${T(t)}');`,"try {",` await import('./${m}');`,"} catch {"," process.exit(0);","}"].join(`
2
+ `)}function J(){const t=j(B(import.meta.url));for(const o of[l(t,"..",E,m),l(t,"..","..",E,m)])if(I(o))return o;return null}function K(t){return b("SessionStart",t)}function F(t){return b("UserPromptSubmit",t)}function G(t){return b("PreToolUse",t)}function V(t){return b("Stop",t)}const W={SessionStart:30,UserPromptSubmit:10,PreToolUse:10,Stop:60},Y="Edit|Write|MultiEdit|NotebookEdit";function $(t,o){const e=(n,i,u)=>({...u?{matcher:u}:{},hooks:[{type:"command",command:`node "${i}"${o?` ${o(n)}`:""}`,timeout:W[n]}]}),r={SessionStart:[e("SessionStart",t.sessionStart)],UserPromptSubmit:[e("UserPromptSubmit",t.userPromptSubmit)]};return t.preToolUse&&(r.PreToolUse=[e("PreToolUse",t.preToolUse,Y)]),t.stop&&(r.Stop=[e("Stop",t.stop)]),r}const H=".claude/hooks",Q=".claude/settings.json",R={SessionStart:"cachly-ambient-session-start.mjs",UserPromptSubmit:"cachly-ambient-prompt-submit.mjs",PreToolUse:"cachly-ambient-pre-tool.mjs",Stop:"cachly-ambient-stop.mjs"},q=".claude/hooks/cachly-ambient-";function z(t,o){const e=t.hooks??[];return e.length>0&&e.every(r=>{const n=r.command??"";return n.includes(q)||o.has(n)||[...o].some(i=>n.includes(`"${i}"`))})}function X(t,o){const e={...t,hooks:{...t.hooks??{}}},r=e.hooks,n=$(o),i=new Set([o.sessionStart,o.userPromptSubmit,o.preToolUse,o.stop].filter(a=>!!a));for(const[a,c]of Object.entries(n)){const p=(Array.isArray(r[a])?r[a]:[]).filter(f=>!z(f,i));r[a]=[...p,...c]}const u=JSON.stringify(e)!==JSON.stringify(t);return{settings:e,changed:u}}async function nt(t,o,e,r={}){const n=l(t,H);await w(n,{recursive:!0});const i={instanceId:o,apiKey:e},u=["SessionStart","UserPromptSubmit","PreToolUse","Stop"],a={SessionStart:K(i),UserPromptSubmit:F(i),PreToolUse:G(i),Stop:V(i)},c=s=>l(n,R[s]),p=J();if(!p)throw new Error(`cachly hook bundle ${m} missing from the package`);const f=L(p,"utf-8"),h=l(n,m),k=async s=>{try{return await A(s,"utf-8")}catch{return""}};let y=!1,O=await k(h)===f;for(const s of u){const x=await k(c(s));x&&(y=!0),x!==a[s]+`
3
+ `&&(O=!1)}const _=O?"unchanged":y?"upgraded":"written";if(_!=="unchanged"){await U(h,f,"utf-8");for(const s of u)await U(c(s),a[s]+`
4
+ `,"utf-8"),await M(c(s),493).catch(()=>{})}const P=l(t,Q),N=I(P);let g={};if(N)try{g=JSON.parse(await A(P,"utf-8"))}catch{g={}}const d=s=>r.portable?`$CLAUDE_PROJECT_DIR/${H}/${R[s]}`:c(s),{settings:C,changed:v}=X(g,{sessionStart:d("SessionStart"),userPromptSubmit:d("UserPromptSubmit"),preToolUse:d("PreToolUse"),stop:d("Stop")});let S;return N?v?S="merged":S="unchanged":S="written",S!=="unchanged"&&(await w(l(t,".claude"),{recursive:!0}),await U(P,JSON.stringify(C,null,2)+`
5
+ `,"utf-8")),{sessionStartPath:c("SessionStart"),promptSubmitPath:c("UserPromptSubmit"),preToolUsePath:c("PreToolUse"),stopPath:c("Stop"),bundlePath:h,scripts:_,settings:S}}const rt=["SessionStart","UserPromptSubmit","Stop"],E="hooks";function it(){const t=`\${CLAUDE_PLUGIN_ROOT}/${E}/${m}`,o=$({sessionStart:t,userPromptSubmit:t,stop:t},e=>`${e} --plugin`);return JSON.stringify({hooks:o},null,2)+`
6
+ `}export{st as AMBIENT_CLI_SUBCOMMAND,D as AMBIENT_HOOK_VERSION,m as HOOK_BUENDEL,E as PLUGIN_HOOK_DIR,rt as PLUGIN_HOOK_EVENTS,Y as PRE_TOOL_USE_MATCHER,$ as buildAmbientSettingsHooks,it as buildPluginHooksJson,G as buildPreToolUseHook,K as buildSessionStartHook,V as buildStopHook,F as buildUserPromptSubmitHook,J as hookBuendelQuelle,nt as installAmbientHooks,X as mergeAmbientSettings};
@@ -1,6 +1,6 @@
1
- import{appendFile as u,readFile as s,rename as f,writeFile as p}from"node:fs/promises";import{mkdir as d}from"node:fs/promises";import{homedir as m}from"node:os";import{dirname as l,resolve as y}from"node:path";function a(){return y(m(),".cachly","ambient-ledger.jsonl")}function v(t){return JSON.stringify({ts:t.ts,event:t.event,injected:Math.max(0,Math.round(t.injected)),prevented:Math.max(0,Math.round(t.prevented)),...t.note?{note:t.note.slice(0,200)}:{}})}function g(t){const n=[];for(const i of t.split(`
2
- `)){const o=i.trim();if(o)try{const e=JSON.parse(o);if(typeof e!="object"||e===null)continue;const r=Number(e.injected),c=Number(e.prevented);if(!Number.isFinite(r)||!Number.isFinite(c))continue;n.push({ts:typeof e.ts=="string"?e.ts:"",event:typeof e.event=="string"?e.event:"unknown",injected:Math.max(0,r),prevented:Math.max(0,c),...typeof e.note=="string"?{note:e.note}:{}})}catch{}}return n}const h=256*1024,x=400;async function b(t,n=a()){try{await d(l(n),{recursive:!0}),await u(n,v(t)+`
3
- `,"utf-8");const i=await s(n,"utf-8");if(Buffer.byteLength(i,"utf-8")>h){const e=i.split(`
4
- `).filter(Boolean).slice(-x).join(`
1
+ import{appendFile as u,readFile as a,rename as d,writeFile as p}from"node:fs/promises";import{mkdir as f}from"node:fs/promises";import{homedir as m}from"node:os";import{dirname as l,resolve as y}from"node:path";function c(){return y(m(),".cachly","ambient-ledger.jsonl")}function v(e){return JSON.stringify({ts:e.ts,event:e.event,injected:Math.max(0,Math.round(e.injected)),prevented:Math.max(0,Math.round(e.prevented)),...e.note?{note:e.note.slice(0,200)}:{}})}function h(e){const n=[];for(const r of e.split(`
2
+ `)){const o=r.trim();if(o)try{const t=JSON.parse(o);if(typeof t!="object"||t===null)continue;const i=Number(t.injected),s=Number(t.prevented);if(!Number.isFinite(i)||!Number.isFinite(s))continue;n.push({ts:typeof t.ts=="string"?t.ts:"",event:typeof t.event=="string"?t.event:"unknown",injected:Math.max(0,i),prevented:Math.max(0,s),...typeof t.note=="string"?{note:t.note}:{}})}catch{}}return n}const E=256*1024,j=400;async function L(e,n=c()){try{await f(l(n),{recursive:!0}),await u(n,v(e)+`
3
+ `,"utf-8");const r=await a(n,"utf-8");if(Buffer.byteLength(r,"utf-8")>E){const t=r.split(`
4
+ `).filter(Boolean).slice(-j).join(`
5
5
  `)+`
6
- `,r=n+".tmp";await p(r,e,"utf-8"),await f(r,n)}}catch{}}async function L(t=a()){try{return g(await s(t,"utf-8"))}catch{return[]}}export{b as appendLedgerEntry,a as defaultLedgerPath,g as parseLedger,L as readLedger,v as serializeEntry};
6
+ `,i=n+".tmp";await p(i,t,"utf-8"),await d(i,n)}}catch{}}async function N(e=c()){try{return h(await a(e,"utf-8"))}catch{return[]}}function M(e,n,r=fetch){return!e.instanceId||!e.jwt||process.env.CACHLY_NO_TELEMETRY==="1"?Promise.resolve():r(`${e.apiUrl}/api/v1/instances/${e.instanceId}/ambient-events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.jwt}`},body:JSON.stringify({events:[n]}),signal:AbortSignal.timeout(3e3)}).then(()=>{},()=>{})}export{L as appendLedgerEntry,c as defaultLedgerPath,h as parseLedger,N as readLedger,M as reportLedgerEntry,v as serializeEntry};
@@ -0,0 +1 @@
1
+ function l(o){return[...o].sort((e,r)=>r-e)}function i(o,e){const r=o.filter(t=>e.has(t.key)).sort((t,c)=>(e.get(t.key)??0)-(e.get(c.key)??0)),s=o.filter(t=>!e.has(t.key)).sort((t,c)=>c.hybridScore-t.hybridScore),u=[];let n=0,h=0;for(;n<r.length||h<s.length;)h<s.length&&(n>=r.length||s[h].hybridScore>r[n].hybridScore)?u.push(s[h++]):u.push(r[n++]);return u}export{i as ordneNachHausordnung,l as rangWerte};
@@ -0,0 +1 @@
1
+ function o(t){const e=t.toLowerCase();return/\b(fix|fixed|fixes|bug|hotfix|patch|revert|resolve|closes? #\d+)\b/.test(e)?{category:"fix",outcome:"success",severity:/\b(critical|crash|security|auth|data loss|outage|prod|production)\b/.test(e)?"critical":/\b(major|breaking|regression|hotfix)\b/.test(e)?"major":"minor"}:/\b(feat|feature|add|added|implement|new|introduce)\b/.test(e)?{category:"feat",outcome:"success",severity:"minor"}:/\b(refactor|clean|cleanup|improve|simplify|extract|rename)\b/.test(e)?{category:"refactor",outcome:"success",severity:"minor"}:/\b(perf|optimize|speed|cache|latency|memory|performance)\b/.test(e)?{category:"perf",outcome:"success",severity:"major"}:/\b(security|cve|auth|csrf|xss|sql|injection|sanitize|escape|encrypt)\b/.test(e)?{category:"security",outcome:"success",severity:"critical"}:/\b(deploy|ci|cd|build|docker|k8s|helm|infra|devops)\b/.test(e)?{category:"deploy",outcome:"success",severity:"major"}:/\b(test|spec|coverage|assert|mock|unit|integration)\b/.test(e)?{category:"test",outcome:"success",severity:"minor"}:{category:"chore",outcome:"success",severity:"minor"}}function c(t){return o(t).category}function i(t){return t.toLowerCase().replace(/[^a-z0-9\s\-_]/g," ").split(/\s+/).filter(s=>s.length>3&&!["that","this","with","from","when","into","also","some","were"].includes(s)).slice(0,3).join("-")||"general"}function n(t){return`${c(t)}:${i(t)}`}function a(t){const e=new Set;for(const r of t)r&&e.add(n(r));return e.size}function u(t){return/^\s*["']?revert\b/i.test(t)}export{o as classifyCommit,c as commitArt,i as extractDomain,u as istRueckbau,n as lektionsThema,a as zaehleLektionen};
@@ -1 +1 @@
1
- import{existsSync as o,mkdirSync as d,writeFileSync as p,renameSync as a,chmodSync as f,readFileSync as i}from"node:fs";import{resolve as s,dirname as y}from"node:path";function m(){return process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??""}function h(e){return/^\$\{[^}]*\}$/.test(e.trim())}function r(e){if(!(typeof e!="string"||e.length===0))return h(e)?void 0:e}function u(e={}){const n=e.home??m();return s(n,".cachly","credentials.json")}function C(e,n={}){try{const t=u(n);d(y(t),{recursive:!0});const c=`${t}.${process.pid}-${Date.now()}.tmp`;p(c,JSON.stringify({apiKey:e},null,2),"utf8");try{f(c,384)}catch{}a(c,t)}catch{}}function l(e){try{const n=u(e);if(!o(n))return;const t=JSON.parse(i(n,"utf8"));return r(t.apiKey)}catch{return}}function S(e){try{const n=s(e.cwd??process.cwd(),".mcp.json");if(!o(n))return;const t=JSON.parse(i(n,"utf8"));return r(t.mcpServers?.cachly?.env?.CACHLY_JWT)}catch{return}}function P(e={}){const n=e.env??process.env;return r(n.CACHLY_JWT)??r(n.CACHLY_API_KEY)??l(e)??S(e)}export{u as credentialsPath,h as istPlatzhalter,P as resolveApiKey,C as saveApiKey};
1
+ import{existsSync as o,mkdirSync as f,writeFileSync as p,renameSync as l,chmodSync as y,readFileSync as s}from"node:fs";import{resolve as a,dirname as m}from"node:path";function h(){return process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??""}function S(e){return/^\$\{[^}]*\}$/.test(e.trim())}function r(e){if(!(typeof e!="string"||e.length===0))return S(e)?void 0:e}function u(e={}){const n=e.home??h();return a(n,".cachly","credentials.json")}function I(e,n={}){const t=i(n),c=t?.apiKey===e?r(t.instanceId):void 0;d({apiKey:e,...c?{instanceId:c}:{}},n)}function x(e,n){const t=i(n);!r(e)||!t?.apiKey||t.apiKey!==n.apiKey||t.instanceId!==e&&d({...t,instanceId:e},n)}function P(e={}){return r(i(e)?.instanceId)}function i(e){try{const n=u(e);if(!o(n))return null;const t=JSON.parse(s(n,"utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function d(e,n){try{const t=u(n);f(m(t),{recursive:!0});const c=`${t}.${process.pid}-${Date.now()}.tmp`;p(c,JSON.stringify(e,null,2),"utf8");try{y(c,384)}catch{}l(c,t)}catch{}}function v(e){return r(i(e)?.apiKey)}function C(e){try{const n=a(e.cwd??process.cwd(),".mcp.json");if(!o(n))return;const t=JSON.parse(s(n,"utf8"));return r(t.mcpServers?.cachly?.env?.CACHLY_JWT)}catch{return}}function H(e={}){const n=e.env??process.env;return r(n.CACHLY_JWT)??r(n.CACHLY_API_KEY)??v(e)??C(e)}export{u as credentialsPath,S as istPlatzhalter,P as readInstanceId,H as resolveApiKey,I as saveApiKey,x as saveInstanceId};
@@ -1,2 +1,2 @@
1
- import{existsSync as f,readFileSync as p}from"node:fs";import{resolve as g}from"node:path";import{AMBIENT_HOOK_VERSION as l}from"./ambient-hooks.js";import{netBalance as y,shouldBackoff as v}from"./ambient-recall.js";import{cachlyUrl as $}from"./cachly-url.js";const k=18;function H(t=process.version){const e=Number(t.replace(/^v/,"").split(".")[0]);return Number.isFinite(e)&&e>=k?{name:"Node.js",status:"ok",detail:`${t}`}:{name:"Node.js",status:"fail",detail:`${t} \u2014 too old`,hint:`cachly needs Node ${k}+ (built-in fetch). Install a current LTS from nodejs.org.`}}function P(t){if(!t)return{name:"Credential",status:"fail",detail:"CACHLY_JWT is not set",hint:"Run `npx @cachly-dev/mcp-server@latest autopilot` (browser sign-in) or export CACHLY_JWT=<cky_\u2026>."};const e=t.startsWith("cky_"),s=t.split(".").length===3;return!e&&!s?{name:"Credential",status:"warn",detail:"CACHLY_JWT is set but looks neither like a cky_\u2026 key nor a JWT",hint:"Re-copy the key from the dashboard (API Keys) \u2014 it may be truncated."}:{name:"Credential",status:"ok",detail:e?"API key (cky_\u2026)":"JWT"}}async function R(t,e=fetch){try{const s=await e(`${t}/health`,{signal:AbortSignal.timeout(5e3)});return s.ok?{name:"API",status:"ok",detail:`${t} reachable`}:{name:"API",status:"fail",detail:`${t}/health returned HTTP ${s.status}`,hint:`The API answered but is unhealthy \u2014 check ${$("/status","doctor")} or your CACHLY_API_URL.`}}catch{return{name:"API",status:"fail",detail:`${t} not reachable`,hint:"Check your network/proxy. Self-hosted: is CACHLY_API_URL correct and the API running?"}}}async function S(t,e,s=fetch){if(!e)return{name:"Auth",status:"fail",detail:"skipped \u2014 no credential",hint:"Fix the Credential check first."};try{const r=await s(`${t}/api/v1/instances`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(5e3)});return r.ok?{name:"Auth",status:"ok",detail:"credential accepted"}:r.status===401||r.status===403?{name:"Auth",status:"fail",detail:`API rejected the credential (HTTP ${r.status})`,hint:"The key is expired or revoked. Create a new one in the dashboard, or re-run autopilot."}:{name:"Auth",status:"warn",detail:`unexpected HTTP ${r.status} from /api/v1/instances`}}catch{return{name:"Auth",status:"warn",detail:"could not verify (network error)"}}}async function L(t,e,s,r=fetch){if(!e||!s)return{name:"Vektoren",status:"warn",detail:"skipped \u2014 no credential or instance"};try{const n=await r(`${t}/api/v1/instances/${s}/vector-coverage`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(12e3)});if(!n.ok)return{name:"Vektoren",status:"warn",detail:`coverage not measured (HTTP ${n.status})`};const a=await n.json();return a.status==="leer"?{name:"Vektoren",status:"ok",detail:"no lessons yet"}:a.status==="nicht-gemessen"?{name:"Vektoren",status:"warn",detail:"instance not running \u2014 not measured"}:a.status==="aus"?{name:"Vektoren",status:"fail",detail:`semantic search is OFF: ${a.lessons} lessons, 0 vectors`,hint:"Embeddings never ran for this instance. Check the embed provider; recall runs word-only until fixed."}:a.status==="luecke"?{name:"Vektoren",status:"warn",detail:`${a.vectors}/${a.lessons} lessons have vectors (${a.percent.toFixed(0)}%)`,hint:"Some lessons are invisible to semantic search. Large writes under the rate limit can skip embedding."}:{name:"Vektoren",status:"ok",detail:`${a.vectors}/${a.lessons} vectors (${a.percent.toFixed(0)}%)`}}catch{return{name:"Vektoren",status:"warn",detail:"could not verify (network error)"}}}function V(t){return t?/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)?{name:"Instance",status:"ok",detail:t.slice(0,8)+"\u2026"}:{name:"Instance",status:"warn",detail:`"${t.slice(0,24)}" does not look like an instance UUID`,hint:"Copy the instance ID from the dashboard (Instances \u2192 your brain)."}:{name:"Instance",status:"warn",detail:"no CACHLY_BRAIN_INSTANCE_ID set and no default instance resolved",hint:"Run `npx @cachly-dev/mcp-server@latest init` in your project, or export CACHLY_BRAIN_INSTANCE_ID."}}function j(t){const e={settingsExists:!1,wiredEvents:[],scriptFiles:[]};try{const s=g(t,".claude/settings.json");if(e.settingsExists=f(s),e.settingsExists){const r=JSON.parse(p(s,"utf-8"));for(const[n,a]of Object.entries(r.hooks??{})){const u=o=>(o??"").replace(/\\/g,"/");if((a??[]).some(o=>(o.hooks??[]).some(i=>u(i.command).includes(".claude/hooks/cachly-ambient-")))){e.wiredEvents.push(n);for(const o of a??[])for(const i of o.hooks??[]){const h=u(i.command).match(/["']?([^"']*\.claude\/hooks\/cachly-ambient-[^"']+)["']?/);if(!h)continue;const c=h[1].replace("$CLAUDE_PROJECT_DIR",t),d=f(c);let m="unknown";if(d)try{m=p(c,"utf-8").includes(l)?"current":"stale"}catch{}e.scriptFiles.push({path:c,exists:d,version:m})}}}}}catch{}return e}const A=["SessionStart","UserPromptSubmit","PreToolUse","Stop"];function F(t){if(!t.settingsExists||t.wiredEvents.length===0)return{name:"Hooks",status:"warn",detail:"Ambient Recall hooks are not installed in this project",hint:"Run `npx @cachly-dev/mcp-server@latest init` here \u2014 memory then injects itself (no hooks = pull-only)."};const e=A.filter(n=>!t.wiredEvents.includes(n)),s=t.scriptFiles.filter(n=>!n.exists),r=t.scriptFiles.filter(n=>n.exists&&n.version==="stale");return s.length>0?{name:"Hooks",status:"fail",detail:`settings.json wires hooks whose script files are missing (${s.length})`,hint:"Re-run `npx @cachly-dev/mcp-server@latest init` to rewrite the scripts."}:r.length>0?{name:"Hooks",status:"warn",detail:`installed hooks are an older version (current: ${l}); v1/v2 shell hooks never ran on native Windows`,hint:"Re-run `npx @cachly-dev/mcp-server@latest init` to upgrade in place."}:e.length>0?{name:"Hooks",status:"warn",detail:`partial install \u2014 missing events: ${e.join(", ")}`,hint:"Re-run `npx @cachly-dev/mcp-server@latest init` to add the missing hooks."}:{name:"Hooks",status:"ok",detail:`all 4 events wired, scripts ${l}`}}function O(t,e){const s=y(t),r=v(t);return t.length===0?{name:"Ledger",status:"ok",detail:`empty (${e}) \u2014 fills up once ambient hooks inject`}:r?{name:"Ledger",status:"warn",detail:`${t.length} entries, net ${s.net} tokens \u2014 auto-backoff ACTIVE, injection paused`,hint:"The agent has not reported prevented tokens lately. This self-heals; `ambient-stats` shows details."}:{name:"Ledger",status:"ok",detail:`${t.length} entries, net ${s.net>=0?"+":""}${s.net} tokens`}}const w={ok:"\u2705",warn:"\u26A0\uFE0F ",fail:"\u274C"};function J(t){const e=["","\u{1FA7A} cachly doctor",""];for(const n of t)e.push(` ${w[n.status]} ${n.name.padEnd(11)} ${n.detail}`),n.hint&&n.status!=="ok"&&e.push(` \u21B3 ${n.hint}`);const s=t.filter(n=>n.status==="fail").length,r=t.filter(n=>n.status==="warn").length;return e.push(""),e.push(s>0?` ${s} problem${s>1?"s":""} to fix${r?`, ${r} warning${r>1?"s":""}`:""}.`:r>0?` No blockers \u2014 ${r} warning${r>1?"s":""}.`:" Everything looks healthy. Your brain is wired."),e.push(""),e.join(`
2
- `)}function B(t){return t.some(e=>e.status==="fail")?1:0}export{R as checkApiReachable,S as checkAuthAccepted,P as checkCredential,F as checkHooks,V as checkInstance,O as checkLedger,H as checkNodeVersion,L as checkVectorCoverage,B as doctorExitCode,j as inspectAmbientHooks,J as renderDoctorReport};
1
+ import{existsSync as f,readFileSync as p}from"node:fs";import{resolve as y}from"node:path";import{AMBIENT_HOOK_VERSION as l}from"./ambient-hooks.js";import{netBalance as g}from"./ambient-recall.js";import{cachlyUrl as v}from"./cachly-url.js";const k=18;function N(t=process.version){const e=Number(t.replace(/^v/,"").split(".")[0]);return Number.isFinite(e)&&e>=k?{name:"Node.js",status:"ok",detail:`${t}`}:{name:"Node.js",status:"fail",detail:`${t} \u2014 too old`,hint:`cachly needs Node ${k}+ (built-in fetch). Install a current LTS from nodejs.org.`}}function H(t){if(!t)return{name:"Credential",status:"fail",detail:"CACHLY_JWT is not set",hint:"Run `npx @cachly-dev/mcp-server@latest autopilot` (browser sign-in) or export CACHLY_JWT=<cky_\u2026>."};const e=t.startsWith("cky_"),n=t.split(".").length===3;return!e&&!n?{name:"Credential",status:"warn",detail:"CACHLY_JWT is set but looks neither like a cky_\u2026 key nor a JWT",hint:"Re-copy the key from the dashboard (API Keys) \u2014 it may be truncated."}:{name:"Credential",status:"ok",detail:e?"API key (cky_\u2026)":"JWT"}}async function P(t,e=fetch){try{const n=await e(`${t}/health`,{signal:AbortSignal.timeout(5e3)});return n.ok?{name:"API",status:"ok",detail:`${t} reachable`}:{name:"API",status:"fail",detail:`${t}/health returned HTTP ${n.status}`,hint:`The API answered but is unhealthy \u2014 check ${v("/status","doctor")} or your CACHLY_API_URL.`}}catch{return{name:"API",status:"fail",detail:`${t} not reachable`,hint:"Check your network/proxy. Self-hosted: is CACHLY_API_URL correct and the API running?"}}}async function R(t,e,n=fetch){if(!e)return{name:"Auth",status:"fail",detail:"skipped \u2014 no credential",hint:"Fix the Credential check first."};try{const r=await n(`${t}/api/v1/instances`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(5e3)});return r.ok?{name:"Auth",status:"ok",detail:"credential accepted"}:r.status===401||r.status===403?{name:"Auth",status:"fail",detail:`API rejected the credential (HTTP ${r.status})`,hint:"The key is expired or revoked. Create a new one in the dashboard, or re-run autopilot."}:{name:"Auth",status:"warn",detail:`unexpected HTTP ${r.status} from /api/v1/instances`}}catch{return{name:"Auth",status:"warn",detail:"could not verify (network error)"}}}async function S(t,e,n,r=fetch){if(!e||!n)return{name:"Vektoren",status:"warn",detail:"skipped \u2014 no credential or instance"};try{const s=await r(`${t}/api/v1/instances/${n}/vector-coverage`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(12e3)});if(!s.ok)return{name:"Vektoren",status:"warn",detail:`coverage not measured (HTTP ${s.status})`};const a=await s.json();return a.status==="leer"?{name:"Vektoren",status:"ok",detail:"no lessons yet"}:a.status==="nicht-gemessen"?{name:"Vektoren",status:"warn",detail:"instance not running \u2014 not measured"}:a.status==="aus"?{name:"Vektoren",status:"fail",detail:`semantic search is OFF: ${a.lessons} lessons, 0 vectors`,hint:"Embeddings never ran for this instance. Check the embed provider; recall runs word-only until fixed."}:a.status==="luecke"?{name:"Vektoren",status:"warn",detail:`${a.vectors}/${a.lessons} lessons have vectors (${a.percent.toFixed(0)}%)`,hint:"Some lessons are invisible to semantic search. Large writes under the rate limit can skip embedding."}:{name:"Vektoren",status:"ok",detail:`${a.vectors}/${a.lessons} vectors (${a.percent.toFixed(0)}%)`}}catch{return{name:"Vektoren",status:"warn",detail:"could not verify (network error)"}}}function L(t){return t?/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)?{name:"Instance",status:"ok",detail:t.slice(0,8)+"\u2026"}:{name:"Instance",status:"warn",detail:`"${t.slice(0,24)}" does not look like an instance UUID`,hint:"Copy the instance ID from the dashboard (Instances \u2192 your brain)."}:{name:"Instance",status:"warn",detail:"no CACHLY_BRAIN_INSTANCE_ID set and no default instance resolved",hint:"Run `npx @cachly-dev/mcp-server@latest init` in your project, or export CACHLY_BRAIN_INSTANCE_ID."}}function F(t){const e={settingsExists:!1,wiredEvents:[],scriptFiles:[]};try{const n=y(t,".claude/settings.json");if(e.settingsExists=f(n),e.settingsExists){const r=JSON.parse(p(n,"utf-8"));for(const[s,a]of Object.entries(r.hooks??{})){const u=o=>(o??"").replace(/\\/g,"/");if((a??[]).some(o=>(o.hooks??[]).some(i=>u(i.command).includes(".claude/hooks/cachly-ambient-")))){e.wiredEvents.push(s);for(const o of a??[])for(const i of o.hooks??[]){const h=u(i.command).match(/["']?([^"']*\.claude\/hooks\/cachly-ambient-[^"']+)["']?/);if(!h)continue;const c=h[1].replace("$CLAUDE_PROJECT_DIR",t),d=f(c);let m="unknown";if(d)try{m=p(c,"utf-8").includes(l)?"current":"stale"}catch{}e.scriptFiles.push({path:c,exists:d,version:m})}}}}}catch{}return e}const $=["SessionStart","UserPromptSubmit","PreToolUse","Stop"];function V(t){if(!t.settingsExists||t.wiredEvents.length===0)return{name:"Hooks",status:"warn",detail:"Ambient Recall hooks are not installed in this project",hint:"Run `npx @cachly-dev/mcp-server@latest init` here \u2014 memory then injects itself (no hooks = pull-only)."};const e=$.filter(s=>!t.wiredEvents.includes(s)),n=t.scriptFiles.filter(s=>!s.exists),r=t.scriptFiles.filter(s=>s.exists&&s.version==="stale");return n.length>0?{name:"Hooks",status:"fail",detail:`settings.json wires hooks whose script files are missing (${n.length})`,hint:"Re-run `npx @cachly-dev/mcp-server@latest init` to rewrite the scripts."}:r.length>0?{name:"Hooks",status:"warn",detail:`installed hooks are an older version (current: ${l}); v1/v2 shell hooks never ran on native Windows`,hint:"Re-run `npx @cachly-dev/mcp-server@latest init` to upgrade in place."}:e.length>0?{name:"Hooks",status:"warn",detail:`partial install \u2014 missing events: ${e.join(", ")}`,hint:"Re-run `npx @cachly-dev/mcp-server@latest init` to add the missing hooks."}:{name:"Hooks",status:"ok",detail:`all 4 events wired, scripts ${l}`}}function j(t,e){const n=g(t);return t.length===0?{name:"Ledger",status:"ok",detail:`empty (${e}) \u2014 fills up once ambient hooks inject`}:{name:"Ledger",status:"ok",detail:`${t.length} entries, net ${n.net>=0?"+":""}${n.net} tokens`}}const A={ok:"\u2705",warn:"\u26A0\uFE0F ",fail:"\u274C"};function O(t){const e=["","\u{1FA7A} cachly doctor",""];for(const s of t)e.push(` ${A[s.status]} ${s.name.padEnd(11)} ${s.detail}`),s.hint&&s.status!=="ok"&&e.push(` \u21B3 ${s.hint}`);const n=t.filter(s=>s.status==="fail").length,r=t.filter(s=>s.status==="warn").length;return e.push(""),e.push(n>0?` ${n} problem${n>1?"s":""} to fix${r?`, ${r} warning${r>1?"s":""}`:""}.`:r>0?` No blockers \u2014 ${r} warning${r>1?"s":""}.`:" Everything looks healthy. Your brain is wired."),e.push(""),e.join(`
2
+ `)}function J(t){return t.some(e=>e.status==="fail")?1:0}export{P as checkApiReachable,R as checkAuthAccepted,H as checkCredential,V as checkHooks,L as checkInstance,j as checkLedger,N as checkNodeVersion,S as checkVectorCoverage,J as doctorExitCode,F as inspectAmbientHooks,O as renderDoctorReport};
@@ -0,0 +1,8 @@
1
+ import{readFileSync as b,existsSync as I,writeFileSync as v,mkdirSync as P,statSync as D,appendFileSync as J}from"node:fs";import{dirname as w,join as h}from"node:path";import{tmpdir as y}from"node:os";import{createHash as Y}from"node:crypto";import{spawn as q}from"node:child_process";import{Einblendbestand as k,torWoerter as N}from"./einblendung-kern.js";import{rahmeEin as x}from"./einblendung-rahmen.js";import{leserText as z}from"./seltenheitsbestand.js";import{mischeMitLeser as L}from"./leser.js";import{LESER_TIEFE as Z,LESER_ZEITLIMIT_MS as F}from"./rangfolge-stellschrauben.js";export*from"./einblendung-kern.js";const K=600*1e3,T=8e3,W=60*1e3,C=120,j=Z,G=1500,R=F,V=h(y(),"cachly-ambient-netlog.jsonl");function Se(e=process.cwd()){const t={apiUrl:process.env.CACHLY_API_URL||"https://api.cachly.dev",jwt:process.env.CACHLY_JWT||"",instanceId:process.env.CACHLY_BRAIN_INSTANCE_ID||""};if(t.jwt&&t.instanceId)return t;let n=e;for(let s=0;s<8;s++){const o=h(n,".mcp.json");if(I(o))try{const i=JSON.parse(b(o,"utf8"))?.mcpServers?.cachly?.env??{};if(t.apiUrl=t.apiUrl||i.CACHLY_API_URL||"https://api.cachly.dev",t.jwt=t.jwt||i.CACHLY_JWT||"",t.instanceId=t.instanceId||i.CACHLY_BRAIN_INSTANCE_ID||"",t.jwt&&t.instanceId)return t}catch{}const r=w(n);if(r===n)break;n=r}return t}function $(e){return Y("sha1").update(e).digest("hex").slice(0,12)}function X(e){return h(y(),`cachly-ambient-bestand-${$(e)}.json`)}function Q(e){return h(y(),`cachly-ambient-auffrischen-${$(e)}.lock`)}async function M(e,{fetchFn:t=fetch,zeitlimitMs:n=T}={}){try{const s=await t(`${e.apiUrl}/api/v1/instances/${e.instanceId}/export`,{headers:{Authorization:`Bearer ${e.jwt}`},signal:AbortSignal.timeout(n)});if(!s.ok)return null;const o=await s.json();return Array.isArray(o?.lessons)?o.lessons.map(r=>typeof r=="string"?ee(r):r).filter(r=>!!r&&typeof r=="object"):null}catch{return null}}function ee(e){try{return JSON.parse(e)}catch{return null}}function O(e,t){try{P(w(e),{recursive:!0}),v(e,JSON.stringify({at:Date.now(),lessons:t}),{mode:384})}catch{}}function H(e){try{const t=JSON.parse(b(e,"utf8"));if(Array.isArray(t?.lessons))return{at:Number(t.at)||0,lessons:t.lessons}}catch{}return null}function te(e,t){const n=Q(e.instanceId);try{if(I(n)&&Date.now()-D(n).mtimeMs<W)return;v(n,String(Date.now()),{mode:384})}catch{return}try{q(process.execPath,t,{detached:!0,stdio:"ignore",env:{...process.env,CACHLY_API_URL:e.apiUrl,CACHLY_JWT:e.jwt,CACHLY_BRAIN_INSTANCE_ID:e.instanceId}}).unref()}catch{}}async function re(e,{force:t=!1,nebenlauf:n,abrufMs:s=T,fetchFn:o}={}){if(!e.jwt||!e.instanceId)return{lessons:[],quelle:"nicht-eingerichtet"};const r=X(e.instanceId);if(t){const a=await M(e,{fetchFn:o,zeitlimitMs:s});if(a)return O(r,a),{lessons:a,quelle:"server"};const u=H(r);return u?{lessons:u.lessons,quelle:"platte-alt"}:{lessons:[],quelle:"server-nicht-erreichbar"}}const i=H(r);if(i){const a=Date.now()-i.at<K;return!a&&n&&te(e,n),{lessons:i.lessons,quelle:a?"platte":"platte-alt"}}const l=await M(e,{fetchFn:o,zeitlimitMs:s});return l?(O(r,l),{lessons:l,quelle:"server"}):{lessons:[],quelle:"server-nicht-erreichbar"}}function _(e){return Math.ceil(String(e).length/4)}function S(e){const t=e.severity?`[${e.severity}] `:"",n=String(e.what_worked??"").replace(/\s+/g," ").trim(),s=n.length>C?`${n.slice(0,C)}\u2026`:n;return`- ${t}${e.topic}: ${s}`}const m={lessons:[],tokens:0,topScore:0,belege:0};function U(e,t,n){const s=[];let o=0;for(const{lektion:r}of e.slice(0,t)){const i=_(S(r));if(o+i>n)break;s.push(r),o+=i}return{lessons:s,tokens:o,topScore:Math.round(e[0].punkte*100)/100,belege:e[0].belege}}function Ee(e,t,{minBelege:n=2,topK:s=3,tokenBudget:o=600}={}){if(!Array.isArray(t)||t.length===0)return{...m};if(N(e).length===0)return{...m};const r=new k(t).sortiere(e).filter(i=>i.belege>=n);return r.length===0?{...m}:U(r,s,o)}function ne(e){return z(e,G)}async function se(e,t,n,{zeitlimitMs:s=R,fetchFn:o=fetch}={}){if(!e?.jwt||!e?.instanceId||n.length===0||["0","off","aus","false"].includes(String(process.env.CACHLY_LESER||"").toLowerCase()))return null;try{const r=await o(`${e.apiUrl}/api/v1/rerank`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.jwt}`},body:JSON.stringify({query:t,texts:n,instance_id:e.instanceId}),signal:AbortSignal.timeout(s)});if(!r.ok)return null;const i=await r.json(),l=Array.isArray(i.scores)?i.scores:null;return!l||l.length!==n.length||!l.every(a=>typeof a=="number"&&Number.isFinite(a))?null:{scores:l,provider:typeof i.provider=="string"?i.provider:"?",ms:Number(i.ms)||0}}catch{return null}}async function oe(e,t,n,{minBelege:s=2,topK:o=3,tokenBudget:r=600,tiefe:i=j,zeitlimitMs:l=R,fetchFn:a}={}){const u={...m,leser:"aus",leserMs:0};if(!Array.isArray(t)||t.length===0||N(e).length===0)return u;let c=new k(t).sortiere(e).filter(p=>p.belege>=s);if(c.length===0)return u;let E="aus",A=0;if(c.length>1&&i>0){const p=c.slice(0,i),B=c.slice(i),f=await se(n,e,p.map(g=>ne(g.lektion)),{zeitlimitMs:l,fetchFn:a});f&&(c=[...L(p.map(d=>d.punkte),f.scores,1).map(d=>p[d]),...B],E=f.provider,A=f.ms)}return{...U(c,o,r),leser:E,leserMs:A}}function ie(e){if(!e.lessons.length)return"";const t=e.lessons.map(S).join(`
2
+ `);return`\u{1F9E0} Cachly Brain \u2014 relevant lessons for this task (auto-recall, ${e.lessons.length}):
3
+ ${x(t)}
4
+ (ambient-recall \xB7 ~${e.tokens} tokens \xB7 match score ${e.topScore})`}const ae=5;function Ae(e){if(!e.length)return"";const t=e.filter(o=>{const r=String(o.topic??"");return!(/^auto:/.test(r)||/^[a-z]+:?$/.test(r))}),s=[...t.length?t:e].sort((o,r)=>(Number(r.recall_count)||0)-(Number(o.recall_count)||0)).slice(0,ae).map(S).join(`
5
+ `);return`\u{1F9E0} Cachly Brain \u2014 ambient recall active (${e.length} lessons). Top by proven reuse:
6
+ ${x(s)}
7
+ (Relevant lessons for each task are auto-injected per prompt. ~${_(s)} tokens.)`}function ge(e,t){return t?JSON.stringify({hookSpecificOutput:{hookEventName:e,additionalContext:t}}):""}async function be(e,t,{nebenlauf:n,abrufMs:s,leser:o=!0,session:r=null,protokoll:i=!0,fetchFn:l}={}){const{lessons:a,quelle:u}=await re(t,{nebenlauf:n,abrufMs:s,fetchFn:l}),c=await oe(e,a,t,{tiefe:o?j:0,fetchFn:l});if(i)try{J(V,JSON.stringify({at:Date.now(),session:r,prompt_tokens:_(e),injected_tokens:c.tokens,matches:c.lessons.length,top_score:c.topScore,belege:c.belege,leser:c.leser,leser_ms:c.leserMs,quelle:u,bestand:a.length})+`
8
+ `)}catch{}return{kontext:ie(c),auswahl:c,quelle:u,bestand:a.length}}export{T as ABRUF_TIMEOUT_MS,C as ANZEIGE_ZEICHEN,K as BESTAND_TTL_MS,R as LESER_HOOK_ZEITLIMIT_MS,G as LESER_MAX_ZEICHEN,j as LESER_TIEFE,V as NETZ_PROTOKOLL,ae as SITZUNG_TOP_N,X as bestandPfad,_ as estimateTokens,re as holeBestand,ge as hookAusgabe,se as leserPunkteApi,ne as leserText,L as mischeMitLeser,be as promptEinblendung,ie as promptKontext,S as renderLesson,Se as resolveConfig,Ee as selectRelevant,oe as selectRelevantMitLeser,Ae as sitzungsKontext,te as starteNebenlauf};