@cachly-dev/mcp-server 0.10.174 → 0.10.176
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 +5 -3
- package/dist/src/ambient-cli.js +2 -2
- package/dist/src/ambient-hook-start.js +1 -0
- package/dist/src/ambient-hook.js +2 -0
- package/dist/src/ambient-hooks.js +6 -5
- package/dist/src/ambient-ledger.js +5 -5
- package/dist/src/ausgabe-ordnung.js +1 -0
- package/dist/src/commit-art.js +1 -0
- package/dist/src/credentials.js +1 -1
- package/dist/src/einblendung.js +6 -6
- package/dist/src/embeddings.js +4 -4
- package/dist/src/handlers/brain.js +67 -67
- package/dist/src/handlers/fedbrain.js +31 -31
- package/dist/src/hook-zugang.js +1 -0
- package/dist/src/index.js +153 -154
- package/dist/src/leser-sicherung.js +1 -0
- package/dist/src/leser.js +1 -1
- package/dist/src/zugang.js +6 -0
- package/glama.json +1 -1
- package/hooks/cachly-ambient-einblendung.mjs +27 -0
- package/package.json +5 -2
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -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 |
|
|
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
|
|
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
|
-
|
|
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>
|
package/dist/src/ambient-cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{promptEinblendung as
|
|
2
|
-
`).find(r=>r.trim().length>0)?.trim()??t).slice(0,200),outcome:"success",details:t.slice(0,500),severity:"minor"}}const
|
|
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
|
|
2
|
-
`)}function
|
|
3
|
-
`&&(
|
|
4
|
-
`,"utf-8"),await
|
|
5
|
-
`,"utf-8")),{sessionStartPath:
|
|
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
|
|
2
|
-
`)){const o=
|
|
3
|
-
`,"utf-8");const
|
|
4
|
-
`).filter(Boolean).slice(-
|
|
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
|
-
`,
|
|
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};
|
package/dist/src/credentials.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as o,mkdirSync as
|
|
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};
|
package/dist/src/einblendung.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{readFileSync as w,existsSync as b,writeFileSync as v,mkdirSync as D,statSync as Y,appendFileSync as J}from"node:fs";import{dirname as k,join as h}from"node:path";import{tmpdir as m}from"node:os";import{createHash as q}from"node:crypto";import{spawn as Z}from"node:child_process";import{Einblendbestand as x,torWoerter as L}from"./einblendung-kern.js";import{rahmeEin as N}from"./einblendung-rahmen.js";import{leserText as z}from"./seltenheitsbestand.js";import{mischeMitLeser as C}from"./leser.js";import{LeserSicherung as F,dateiSpeicher as K,frageLeser as W}from"./leser-sicherung.js";import{LESER_TIEFE as G,LESER_ZEITLIMIT_MS as V}from"./rangfolge-stellschrauben.js";export*from"./einblendung-kern.js";const X=600*1e3,T=8e3,Q=60*1e3,j=120,R=G,ee=1500,$=V,te=h(m(),"cachly-ambient-netlog.jsonl");function we(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 r=e;for(let o=0;o<8;o++){const s=h(r,".mcp.json");if(b(s))try{const i=JSON.parse(w(s,"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 n=k(r);if(n===r)break;r=n}return t}function S(e){return q("sha1").update(e).digest("hex").slice(0,12)}function re(e){return h(m(),`cachly-ambient-bestand-${S(e)}.json`)}function ne(e){return h(m(),`cachly-leser-sicherung-${S(e)}.json`)}function se(e){return h(m(),`cachly-ambient-auffrischen-${S(e)}.lock`)}async function M(e,{fetchFn:t=fetch,zeitlimitMs:r=T}={}){try{const o=await t(`${e.apiUrl}/api/v1/instances/${e.instanceId}/export`,{headers:{Authorization:`Bearer ${e.jwt}`},signal:AbortSignal.timeout(r)});if(!o.ok)return null;const s=await o.json();return Array.isArray(s?.lessons)?s.lessons.map(n=>typeof n=="string"?oe(n):n).filter(n=>!!n&&typeof n=="object"):null}catch{return null}}function oe(e){try{return JSON.parse(e)}catch{return null}}function H(e,t){try{D(k(e),{recursive:!0}),v(e,JSON.stringify({at:Date.now(),lessons:t}),{mode:384})}catch{}}function O(e){try{const t=JSON.parse(w(e,"utf8"));if(Array.isArray(t?.lessons))return{at:Number(t.at)||0,lessons:t.lessons}}catch{}return null}function ie(e,t){const r=se(e.instanceId);try{if(b(r)&&Date.now()-Y(r).mtimeMs<Q)return;v(r,String(Date.now()),{mode:384})}catch{return}try{Z(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 ae(e,{force:t=!1,nebenlauf:r,abrufMs:o=T,fetchFn:s}={}){if(!e.jwt||!e.instanceId)return{lessons:[],quelle:"nicht-eingerichtet"};const n=re(e.instanceId);if(t){const c=await M(e,{fetchFn:s,zeitlimitMs:o});if(c)return H(n,c),{lessons:c,quelle:"server"};const l=O(n);return l?{lessons:l.lessons,quelle:"platte-alt"}:{lessons:[],quelle:"server-nicht-erreichbar"}}const i=O(n);if(i){const c=Date.now()-i.at<X;return!c&&r&&ie(e,r),{lessons:i.lessons,quelle:c?"platte":"platte-alt"}}const u=await M(e,{fetchFn:s,zeitlimitMs:o});return u?(H(n,u),{lessons:u,quelle:"server"}):{lessons:[],quelle:"server-nicht-erreichbar"}}function E(e){return Math.ceil(String(e).length/4)}function g(e){const t=e.severity?`[${e.severity}] `:"",r=String(e.what_worked??"").replace(/\s+/g," ").trim(),o=r.length>j?`${r.slice(0,j)}\u2026`:r;return`- ${t}${e.topic}: ${o}`}const d={lessons:[],tokens:0,topScore:0,belege:0};function U(e,t,r){const o=[];let s=0;for(const{lektion:n}of e.slice(0,t)){const i=E(g(n));if(s+i>r)break;o.push(n),s+=i}return{lessons:o,tokens:s,topScore:Math.round(e[0].punkte*100)/100,belege:e[0].belege}}function be(e,t,{minBelege:r=2,topK:o=3,tokenBudget:s=600}={}){if(!Array.isArray(t)||t.length===0)return{...d};if(L(e).length===0)return{...d};const n=new x(t).sortiere(e).filter(i=>i.belege>=r);return n.length===0?{...d}:U(n,o,s)}function ce(e){return z(e,ee)}async function P(e,t,r,{zeitlimitMs:o=$,fetchFn:s}={}){if(!e?.jwt||!e?.instanceId||r.length===0)return{art:"ohne"};if(["0","off","aus","false"].includes(String(process.env.CACHLY_LESER||"").toLowerCase()))return{art:"ohne"};const n=new F(K(ne(e.instanceId)));return W({url:`${e.apiUrl}/api/v1/rerank`,jwt:e.jwt,frage:t,texte:r,instanceId:e.instanceId,zeitlimitMs:o,fetchFn:s},n)}async function ve(e,t,r,o={}){const s=await P(e,t,r,o);return s.art==="punkte"?{scores:s.scores,provider:s.provider,ms:s.ms}:null}async function le(e,t,r,{minBelege:o=2,topK:s=3,tokenBudget:n=600,tiefe:i=R,zeitlimitMs:u=$,fetchFn:c}={}){const l={...d,leser:"aus",leserMs:0};if(!Array.isArray(t)||t.length===0||L(e).length===0)return l;let a=new x(t).sortiere(e).filter(p=>p.belege>=o);if(a.length===0)return l;let y="aus",A=0;if(a.length>1&&i>0){const p=a.slice(0,i),B=a.slice(i),f=await P(r,e,p.map(I=>ce(I.lektion)),{zeitlimitMs:u,fetchFn:c});f.art==="punkte"?(a=[...C(p.map(_=>_.punkte),f.scores,1).map(_=>p[_]),...B],y=f.provider,A=f.ms):f.art==="uebersprungen"&&(y="uebersprungen")}return{...U(a,s,n),leser:y,leserMs:A}}function ue(e){if(!e.lessons.length)return"";const t=e.lessons.map(g).join(`
|
|
2
2
|
`);return`\u{1F9E0} Cachly Brain \u2014 relevant lessons for this task (auto-recall, ${e.lessons.length}):
|
|
3
|
-
${
|
|
4
|
-
(ambient-recall \xB7 ~${e.tokens} tokens \xB7 match score ${e.topScore})`}const
|
|
3
|
+
${N(t)}
|
|
4
|
+
(ambient-recall \xB7 ~${e.tokens} tokens \xB7 match score ${e.topScore})`}const pe=5;function ke(e){if(!e.length)return"";const t=e.filter(s=>{const n=String(s.topic??"");return!(/^auto:/.test(n)||/^[a-z]+:?$/.test(n))}),o=[...t.length?t:e].sort((s,n)=>(Number(n.recall_count)||0)-(Number(s.recall_count)||0)).slice(0,pe).map(g).join(`
|
|
5
5
|
`);return`\u{1F9E0} Cachly Brain \u2014 ambient recall active (${e.length} lessons). Top by proven reuse:
|
|
6
|
-
${
|
|
7
|
-
(Relevant lessons for each task are auto-injected per prompt. ~${
|
|
8
|
-
`)}catch{}return{kontext:
|
|
6
|
+
${N(o)}
|
|
7
|
+
(Relevant lessons for each task are auto-injected per prompt. ~${E(o)} tokens.)`}function xe(e,t){return t?JSON.stringify({hookSpecificOutput:{hookEventName:e,additionalContext:t}}):""}async function Le(e,t,{nebenlauf:r,abrufMs:o,leser:s=!0,session:n=null,protokoll:i=!0,fetchFn:u}={}){const{lessons:c,quelle:l}=await ae(t,{nebenlauf:r,abrufMs:o,fetchFn:u}),a=await le(e,c,t,{tiefe:s?R:0,fetchFn:u});if(i)try{J(te,JSON.stringify({at:Date.now(),session:n,prompt_tokens:E(e),injected_tokens:a.tokens,matches:a.lessons.length,top_score:a.topScore,belege:a.belege,leser:a.leser,leser_ms:a.leserMs,quelle:l,bestand:c.length})+`
|
|
8
|
+
`)}catch{}return{kontext:ue(a),auswahl:a,quelle:l,bestand:c.length}}export{T as ABRUF_TIMEOUT_MS,j as ANZEIGE_ZEICHEN,X as BESTAND_TTL_MS,$ as LESER_HOOK_ZEITLIMIT_MS,ee as LESER_MAX_ZEICHEN,R as LESER_TIEFE,te as NETZ_PROTOKOLL,pe as SITZUNG_TOP_N,re as bestandPfad,E as estimateTokens,ae as holeBestand,xe as hookAusgabe,P as leserAnfrageApi,ve as leserPunkteApi,ce as leserText,C as mischeMitLeser,Le as promptEinblendung,ue as promptKontext,g as renderLesson,we as resolveConfig,be as selectRelevant,le as selectRelevantMitLeser,ne as sicherungsPfad,ke as sitzungsKontext,ie as starteNebenlauf};
|
package/dist/src/embeddings.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
const s={apiUrl:process.env.CACHLY_API_URL??"https://api.cachly.dev",jwt:process.env.CACHLY_JWT??"",model:process.env.CACHLY_EMBED_MODEL??""};function
|
|
1
|
+
const s={apiUrl:process.env.CACHLY_API_URL??"https://api.cachly.dev",jwt:process.env.CACHLY_JWT??"",model:process.env.CACHLY_EMBED_MODEL??""};function M(r){s.jwt=r,r&&!g&&d==="none"&&(d="cachly")}const u=Number(process.env.CACHLY_EMBED_TIMEOUT_MS??8e3),p=Number(process.env.CACHLY_EMBED_TIMEOUT_MAX_MS??45e3),A=12;function h(r,n){return n==="kurz"?u:Math.min(p,u+r.length*A)}function f(){return process.env.CACHLY_JWT?"cachly":process.env.OLLAMA_BASE_URL?"ollama":"none"}const g=!!process.env.CACHLY_EMBED_PROVIDER;let d=(process.env.CACHLY_EMBED_PROVIDER??f()).toLowerCase();async function I(r,n,a){const c=h(r,n);switch(d){case"cachly":{if(!s.jwt)throw new Error(`CACHLY_JWT not set.
|
|
2
2
|
|
|
3
3
|
The "cachly" provider uses server-side embeddings via the Cachly API.
|
|
4
4
|
Set CACHLY_JWT, or use another provider via CACHLY_EMBED_PROVIDER:
|
|
5
5
|
openai \u2192 OPENAI_API_KEY
|
|
6
6
|
gemini \u2192 GEMINI_API_KEY
|
|
7
|
-
ollama \u2192 OLLAMA_BASE_URL (local, no key needed)`);const t=`${s.apiUrl}/api/v1/embed`,o={text:r};(a??s.model)&&(o.model=a??s.model);const e=process.env.CACHLY_ADMIN_KEY??"",i=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s.jwt}`,...e?{"X-Admin-Key":e}:{}},body:JSON.stringify(o),signal:AbortSignal.timeout(
|
|
7
|
+
ollama \u2192 OLLAMA_BASE_URL (local, no key needed)`);const t=`${s.apiUrl}/api/v1/embed`,o={text:r};(a??s.model)&&(o.model=a??s.model);const e=process.env.CACHLY_ADMIN_KEY??"",i=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s.jwt}`,...e?{"X-Admin-Key":e}:{}},body:JSON.stringify(o),signal:AbortSignal.timeout(c)});if(!i.ok){const _=await i.text();let l=null;const m=Number(i.headers.get("retry-after"));if(Number.isFinite(m)&&m>=0)l=m;else try{const E=JSON.parse(_);typeof E.retry_after=="number"&&E.retry_after>=0&&(l=E.retry_after)}catch{}throw Object.assign(new Error(`Cachly embed API error ${i.status}: ${_.slice(0,200)}`),{status:i.status,retryAfterSek:l})}return(await i.json()).embedding}case"mistral":{const t=process.env.MISTRAL_API_KEY;if(!t)throw new Error("MISTRAL_API_KEY not set");const o=s.model!=="text-embedding-3-small"?s.model:"mistral-embed",e=await fetch("https://api.mistral.ai/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({model:o,input:[r]}),signal:AbortSignal.timeout(c)});if(!e.ok)throw new Error(`Mistral embedding error: ${e.statusText}`);const i=await e.json();if(!i.data?.[0]?.embedding)throw new Error("Mistral returned empty embedding response");return i.data[0].embedding}case"cohere":{const t=process.env.COHERE_API_KEY;if(!t)throw new Error("COHERE_API_KEY not set");const o=s.model!=="text-embedding-3-small"?s.model:"embed-english-v3.0",e=await fetch("https://api.cohere.com/v2/embed",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({model:o,texts:[r],input_type:"search_query",embedding_types:["float"]}),signal:AbortSignal.timeout(c)});if(!e.ok)throw new Error(`Cohere embedding error: ${e.statusText}`);return(await e.json()).embeddings.float[0]}case"ollama":{const t=process.env.OLLAMA_BASE_URL??"http://localhost:11434",o=a??(s.model!=="text-embedding-3-small"?s.model:"nomic-embed-text"),e=await fetch(`${t}/api/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:o,prompt:r}),signal:AbortSignal.timeout(c)});if(!e.ok)throw new Error(`Ollama embedding error: ${e.statusText}`);return(await e.json()).embedding}case"gemini":{const t=process.env.GEMINI_API_KEY;if(!t)throw new Error("GEMINI_API_KEY not set");const o=s.model!=="text-embedding-3-small"?s.model:"text-embedding-004",e=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${o}:embedContent?key=${t}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:`models/${o}`,content:{parts:[{text:r}]}}),signal:AbortSignal.timeout(c)});if(!e.ok)throw new Error(`Gemini embedding error: ${e.statusText}`);return(await e.json()).embedding.values}case"openai":{const t=process.env.OPENAI_API_KEY;if(!t)throw new Error(`OPENAI_API_KEY not set.
|
|
8
8
|
|
|
9
9
|
Set OPENAI_API_KEY in your .env, or switch provider:
|
|
10
10
|
CACHLY_EMBED_PROVIDER=gemini (+ GEMINI_API_KEY)
|
|
11
11
|
CACHLY_EMBED_PROVIDER=ollama (local, free)
|
|
12
|
-
CACHLY_EMBED_PROVIDER=cachly (server-side, no key needed)`);const o=s.model||"text-embedding-3-small",e=await fetch("https://api.openai.com/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({model:o,input:r}),signal:AbortSignal.timeout(
|
|
13
|
-
Supported: cachly (default), openai, mistral, cohere, ollama, gemini`)}}const b=3,
|
|
12
|
+
CACHLY_EMBED_PROVIDER=cachly (server-side, no key needed)`);const o=s.model||"text-embedding-3-small",e=await fetch("https://api.openai.com/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({model:o,input:r}),signal:AbortSignal.timeout(c)});if(!e.ok)throw new Error(`OpenAI embedding error: ${e.statusText}`);const i=await e.json();if(!i.data?.[0]?.embedding)throw new Error("OpenAI returned empty embedding response");return i.data[0].embedding}default:throw new Error(`Unknown CACHLY_EMBED_PROVIDER="${d}".
|
|
13
|
+
Supported: cachly (default), openai, mistral, cohere, ollama, gemini`)}}const b=3,y=4;function w(r){const n=r;if(typeof n?.status=="number")return n.status===429||n.status>=500;if(n?.name==="TimeoutError"||n?.name==="AbortError")return!1;if(/fetch failed/i.test(String(n?.message??"")))return!0;const a=n?.cause?.code??"";return["ECONNRESET","ECONNREFUSED","ETIMEDOUT","EAI_AGAIN","EPIPE","UND_ERR_SOCKET"].includes(a)}function C(r,n,a){if(n>=(a==="lang"?y:b)||!w(r))return null;const t=r?.retryAfterSek;if(typeof t=="number"&&Number.isFinite(t)&&t>=0){const o=t*1e3;return a==="kurz"?o<=2e3?o:null:Math.min(o,61e3)}return a==="lang"?Math.min(1e3*2**(n-1),8e3):250*2**(n-1)}async function O(r,n){const a=n?.geduld??"kurz";if(n?.modell&&d!=="cachly"&&d!=="ollama")throw new Error(`Anbieter "${d}" kann kein abweichendes Modell anfragen (verlangt: ${n.modell}).`);let c=0;for(;;){c++;try{return await I(r,a,n?.modell)}catch(t){const o=C(t,c,a);if(o===null)throw t;await new Promise(e=>setTimeout(e,o))}}}function S(){switch(d){case"cachly":return!!s.jwt;case"mistral":return!!process.env.MISTRAL_API_KEY;case"cohere":return!!process.env.COHERE_API_KEY;case"ollama":return!0;case"gemini":return!!process.env.GEMINI_API_KEY;case"openai":return!!process.env.OPENAI_API_KEY;case"none":return!1;default:return!1}}function v(){const r={cachly:"CACHLY_JWT (server-side, no extra key needed)",openai:"OPENAI_API_KEY",mistral:"MISTRAL_API_KEY",cohere:"COHERE_API_KEY",ollama:"OLLAMA_BASE_URL (optional, default: http://localhost:11434)",gemini:"GEMINI_API_KEY"};if(d==="none")return"No embedding provider configured. Set OPENAI_API_KEY, GEMINI_API_KEY, or another provider key in .env. Brain works without embedding.";const n=r[d]??"CACHLY_JWT";return`CACHLY_EMBED_PROVIDER=${d} \u2192 requires ${n}`}export{d as EMBED_PROVIDER,O as computeEmbedding,s as embedConfig,v as embedProviderHint,S as hasEmbedProvider,w as istVoruebergehend,M as setEmbedJwt,C as wiederholungMs,h as zeitlimitMs};
|