wyrm-mcp 9.1.0 → 9.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/read-memo.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{createHash as A}from"node:crypto";import{basename as g,extname as b,isAbsolute as f,resolve as p}from"node:path";import{commandSegments as y}from"./wyrm-guard.js";const S=1400,N=40,E=90,
|
|
2
|
-
`),o=b(t).replace(/^\./,"").toLowerCase(),
|
|
3
|
-
`)}function m(e){return typeof e=="string"&&e.length>0?e:null}function x(e,t){return f(e)?p(e):t&&f(t)?p(t,e):null}const
|
|
1
|
+
import{createHash as A}from"node:crypto";import{basename as g,extname as b,isAbsolute as f,resolve as p}from"node:path";import{commandSegments as y}from"./wyrm-guard.js";const S=1400,N=40,E=90,T=12,_="Whole-file read already done this week and unchanged. Prefer Read with offset/limit on the lines you need, or grep. (wyrm-memo)";function L(e){return A("sha256").update(e).digest("hex")}function H(e){return e<=0?0:Math.ceil(e/4)}function c(e,t){return e.replace(/[\x00-\x1f\x7f]/g," ").replace(/\s+/g," ").trim().slice(0,t)}const M=[{exts:["md","markdown","txt"],test:e=>/^#{1,4}\s+\S/.test(e)},{exts:["ts","js","mjs","cjs","tsx","jsx","mts","cts"],test:e=>/^(export\s+(default\s+)?(async\s+)?(function|class|const|let|var|interface|type|enum)\b|(async\s+)?function\s+[A-Za-z_$]|class\s+[A-Za-z_$]|(interface|type|enum)\s+[A-Za-z_$])/.test(e)},{exts:["py"],test:e=>/^(async\s+def|def|class)\s+[A-Za-z_]/.test(e)},{exts:["rs"],test:e=>/^(pub(\([^)]*\))?\s+)?(fn|struct|enum|impl|trait|mod)\b/.test(e)},{exts:["go"],test:e=>/^(func|type)\s+[A-Za-z_]/.test(e)},{exts:["css","scss","less"],test:e=>/^\/\*\s*[-=]{3,}/.test(e)||/^(\.|#|@|:root|[a-z][a-z0-9-]*)[^{;]*\{\s*$/.test(e)},{exts:["astro","html","htm","vue","svelte"],test:e=>/^\s*<(section|main|header|footer|nav|article|aside|h1|h2|h3)\b/.test(e)||/^\s*\{\/\*/.test(e)||/^---\s*$/.test(e)},{exts:["json"],test:e=>/^\s{0,2}"[^"]+"\s*:/.test(e)},{exts:["yaml","yml","toml"],test:e=>/^[A-Za-z_"[][^:=]{0,60}[:=]/.test(e)}];function j(e,t){const s=e.split(`
|
|
2
|
+
`),o=b(t).replace(/^\./,"").toLowerCase(),r=M.find(n=>n.exts.includes(o)),a=Buffer.byteLength(e,"utf8"),l=`${c(g(t),80)} | ${s.length} lines | ${a} bytes | sha ${L(e).slice(0,12)}`,i=[];if(r)for(let n=0;n<s.length&&i.length<N;n++)r.test(s[n])&&i.push(`L${n+1}: ${c(s[n],E)}`);if(i.length===0)for(let n=0;n<s.length&&i.length<T;n++)s[n].trim().length>0&&i.push(`L${n+1}: ${c(s[n],E)}`);const u=S-l.length-_.length-2,d=[];let h=0;for(const n of i){if(h+n.length+1>u)break;d.push(n),h+=n.length+1}return[l,...d,_].join(`
|
|
3
|
+
`)}const R=8e3;function O(e){const t=Math.min(e.length,R);if(t===0)return!0;let s=0;for(let o=0;o<t;o++){const r=e[o];if(r===0)return!1;(r<32&&r!==9&&r!==10&&r!==13||r===127)&&s++}return s/t<=.1}function m(e){return typeof e=="string"&&e.length>0?e:null}function x(e,t){return f(e)?p(e):t&&f(t)?p(t,e):null}const C=/^cat(?:\s+-[A-Za-z]+)*\s+(?:'([^']+)'|"([^"]+)"|([^\s'"|<>&;]+))\s*$/;function v(e){const t=e.tool_name,s=e.tool_input;if(typeof t!="string"||typeof s!="object"||s===null)return null;const o=s,r=m(e.cwd);if(t==="Read"){const a=m(o.file_path);if(!a||typeof o.limit=="number"||typeof o.offset=="number"&&o.offset>1)return null;const l=x(a,r);return l?{absPath:l,tool:"Read",display:c(a,120)}:null}if(t==="Bash"){const a=m(o.command)?.trim();if(!a)return null;const l=y(a);if(l.length!==1)return null;const i=l[0].match(C);if(!i)return null;const u=i[1]??i[2]??i[3];if(!u)return null;const d=x(u,r);return d?{absPath:d,tool:"Bash",display:c(l[0],120)}:null}return null}function D(e,t,s=Date.now()){const o=Date.parse(e.replace(" ","T")+"Z");return Number.isFinite(o)?o<s-t*864e5:!0}class w{db;constructor(t){this.db=t}get(t){return this.db.prepare("SELECT * FROM read_memos WHERE path = ?").get(t)??null}upsert(t){return this.db.prepare(`
|
|
4
4
|
INSERT INTO read_memos (path, sha256, bytes, lines, distilled, tool, project_id, session_id)
|
|
5
5
|
VALUES (@path, @sha256, @bytes, @lines, @distilled, @tool, @projectId, @sessionId)
|
|
6
6
|
ON CONFLICT(path) DO UPDATE SET
|
|
@@ -20,4 +20,4 @@ import{createHash as A}from"node:crypto";import{basename as g,extname as b,isAbs
|
|
|
20
20
|
UPDATE read_memos SET hits = hits + 1, tokens_avoided = tokens_avoided + ? WHERE path = ?
|
|
21
21
|
`).run(Math.max(0,Math.floor(s)),t)}prune(t){const s=Math.max(0,Math.floor(t));return this.db.prepare("DELETE FROM read_memos WHERE last_seen < datetime('now', ?)").run(`-${s} days`).changes}summary(){const t=this.db.prepare(`
|
|
22
22
|
SELECT COUNT(*) AS memos, COALESCE(SUM(hits), 0) AS hits, COALESCE(SUM(tokens_avoided), 0) AS tokensAvoided FROM read_memos
|
|
23
|
-
`).get();return{memos:t.memos,hits:t.hits,tokensAvoided:t.tokensAvoided}}}export{
|
|
23
|
+
`).get();return{memos:t.memos,hits:t.hits,tokensAvoided:t.tokensAvoided}}}export{w as ReadMemos,j as distill,H as estimateTokens,D as isExpired,O as isProbablyText,v as readTarget,L as sha256Hex};
|
package/dist/tool-manifest.json
CHANGED
package/dist/wyrm-manifest.json
CHANGED
package/dist/wyrm-memo.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFileSync as
|
|
3
|
-
`)}function
|
|
4
|
-
`).length,x=C(
|
|
2
|
+
import{readFileSync as _,realpathSync as U,statSync as D}from"node:fs";import{homedir as O}from"node:os";import{dirname as v,join as A}from"node:path";import{fileURLToPath as L}from"node:url";import{openDatabase as h}from"./storage/index.js";import{logSavings as N}from"./statusline.js";import{resolveProjectForPath as R}from"./project-resolve.js";import{ReadMemos as y,distill as C,estimateTokens as E,isExpired as F,isProbablyText as I,readTarget as B,sha256Hex as T}from"./read-memo.js";const e={exitCode:0,stdout:"",stderr:""},W=6e3,j=7,k=2e6;function M(s,t,n){const r=Number(s[t]);return Number.isFinite(r)&&r>=0?r:n}function z(s,t){return["<wyrm-memory>",`wyrm-memo: you already read this exact file in full (unchanged since ${s} UTC). Its map:`,t,"</wyrm-memory>"].join(`
|
|
3
|
+
`)}function H(s,t=process.env){let n=null,r=null;try{const i=(t.WYRM_MEMO_MODE??"observe").toLowerCase();if(i==="off"||!s||!s.trim())return e;const l=JSON.parse(s);if(typeof l!="object"||l===null)return e;const m=l,u=m.hook_event_name;if(u!=="PreToolUse"&&u!=="PostToolUse")return e;const o=B(m);if(!o)return e;const c=D(o.absPath);if(!c.isFile()||c.size>M(t,"WYRM_MEMO_MAX_BYTES",k))return e;const f=t.WYRM_DB_PATH??A(O(),".wyrm","wyrm.db"),P=typeof m.session_id=="string"?m.session_id.slice(0,64):null;if(u==="PostToolUse"){const d=_(o.absPath);if(!I(d))return e;const p=d.toString("utf8"),w=p.length===0?0:p.split(`
|
|
4
|
+
`).length,x=C(p,o.absPath);r=h(f,{fileMustExist:!0}),r.pragma("busy_timeout = 50");const{id:Y}=R(r,v(o.absPath));return new y(r).upsert({path:o.absPath,sha256:T(d),bytes:c.size,lines:w,distilled:x,tool:o.tool,projectId:Y,sessionId:P}),e}if(c.size<M(t,"WYRM_MEMO_MIN_BYTES",W))return e;n=h(f,{readonly:!0,fileMustExist:!0}),n.pragma("busy_timeout = 100");const a=new y(n).get(o.absPath);if(!a||F(a.last_seen,M(t,"WYRM_MEMO_TTL_DAYS",j))||T(_(o.absPath))!==a.sha256)return e;const g=Math.max(0,E(c.size)-E(a.distilled.length));try{r=h(f,{fileMustExist:!0}),r.pragma("busy_timeout = 50"),new y(r).recordHit(o.absPath,g),N(r,"wyrm-memo","cached_preamble",g,void 0,"conservative")}catch{}if(i!=="warn")return e;const S={hookSpecificOutput:{hookEventName:"PreToolUse",additionalContext:z(a.last_seen,a.distilled)}};return{exitCode:0,stdout:JSON.stringify(S)+`
|
|
5
5
|
`,stderr:""}}catch(i){return t.WYRM_MEMO_DEBUG==="1"?{exitCode:0,stdout:"",stderr:`wyrm-memo: internal error (fail-open): ${(i instanceof Error?i.message:String(i)).slice(0,200)}
|
|
6
|
-
`}:e}finally{try{n?.close()}catch{}try{r?.close()}catch{}}}const
|
|
6
|
+
`}:e}finally{try{n?.close()}catch{}try{r?.close()}catch{}}}const J=L(import.meta.url);let b=!1;try{b=typeof process.argv[1]=="string"&&U(process.argv[1])===J}catch{b=!1}if(b){let s="";try{s=_(0,"utf-8")}catch{s=""}const t=H(s);t.stdout&&process.stdout.write(t.stdout),t.stderr&&process.stderr.write(t.stderr),process.exit(t.exitCode)}export{H as runMemo};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wyrm-mcp",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.1",
|
|
4
4
|
"mcpName": "lk.ghosts/wyrm",
|
|
5
5
|
"description": "Local-first persistent memory for AI agents over MCP. Ground truths, negative learning (recorded failures block repeats), decision causality, hybrid recall, negotiated recall (clean-mode injection you steer), live memory streams, run-attributed fleet memory \u2014 a structured SQLite memory on your machine, no cloud or LLM required. Claude / Copilot / Cursor / Windsurf / Codex.",
|
|
6
6
|
"type": "module",
|