wyrm-mcp 7.12.0 → 8.0.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/bridge.js +1 -1
- package/dist/context-ranking.js +1 -1
- package/dist/graph-recall.js +5 -0
- package/dist/memory-artifacts.js +24 -24
- package/dist/tool-manifest-v2.json +1 -1
- package/dist/tool-manifest.json +1 -1
- package/dist/wyrm-cli.js +1 -1
- package/dist/wyrm-manifest.json +1 -1
- package/package.json +1 -1
package/dist/bridge.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{readFileSync as h,writeFileSync as D,readdirSync as k,existsSync as F}from"fs";import{createHash as _}from"crypto";import{join as y}from"path";import{homedir as g}from"os";import{MemoryArtifacts as I}from"./memory-artifacts.js";import{recordWrite as R}from"./receipts.js";import{buildRenderPlan as L,renderToDisk as b,renderForClient as q,makeRenderDeps as A}from"./render-target.js";import{makeBridgeDeps as x,sweepProject as $}from"./reverse-bridge.js";function B(){return process.env.WYRM_BRIDGE_CONFIG??y(g(),".wyrm","bridge.json")}function C(){return process.env.WYRM_BRIDGE_STATE??y(g(),".wyrm","bridge-state.json")}function ee(){try{return JSON.parse(h(B(),"utf8"))}catch{return null}}function W(){try{return JSON.parse(h(C(),"utf8"))}catch{return{}}}function v(t){try{D(C(),JSON.stringify(t,null,1))}catch{}}function H(t,i,r){const n=r??y(g(),".wyrm","remember-distill-state.json");if(!F(n))return 0;let c=0;try{const e=JSON.parse(h(n,"utf8"));for(const[d,a]of Object.entries(e)){const s=`${t}:${d}`;i[s]||(i[s]=a,c++)}}catch{}return c}const N=t=>_("sha1").update(t).digest("hex");function J(t,i,r,n,c={}){const e={source:r.name,type:"remember",stored:0,dropped:0,queued:0,rendered:0},d=r.windowDays&&r.windowDays>=1?r.windowDays:7,a=r.maxPerRun&&r.maxPerRun>=1?r.maxPerRun:80,s=t.prepare("SELECT id FROM projects WHERE path = ?").get(r.projectPath);if(!s)return e.note=`no project at ${r.projectPath}`,e;const p=new Date(Date.now()-d*864e5);let u=[];try{u=k(r.dir).filter(o=>/^today-\d{4}-\d{2}-\d{2}(\.done)?\.md$/.test(o)).map(o=>({f:o,date:o.match(/\d{4}-\d{2}-\d{2}/)[0]})).filter(({date:o})=>new Date(o+"T00:00:00")>=p).sort((o,m)=>m.date.localeCompare(o.date))}catch{return e.note=`cannot read ${r.dir}`,e}let f=0;for(const{f:o,date:m}of u){const S=`${r.name}:today-${m}`,w=new Set(n[S]??[]);let E="";try{E=h(y(r.dir,o),"utf8")}catch{continue}const O=E.split(/^## /m).slice(1).map(l=>"## "+l.trim());for(const l of O){if(f>=a)break;if(l.length<30)continue;const j=N(l);if(w.has(j))continue;if(c.dryRun){f++,e.stored++;continue}const P=`[bridge:${r.name} ${m}] ${l}`.slice(0,2400),T=i.add(s.id,{kind:"pattern",problem:P,confidence:.75,needsReview:0,createdBy:`bridge:${r.name}`});R(t,{tool:"wyrm_bridge",outcome:"stored",refTable:"mem",refId:T.id,source:`bridge:${r.name}`,projectId:s.id}),w.add(j),f++,e.stored++}n[S]=[...w]}return f>=a&&(e.note=`hit per-run cap ${a} \u2014 remainder next run`),e}async function M(t,i,r,n={}){const c={source:i.name,type:"render",stored:0,dropped:0,queued:0,rendered:0},e=t.prepare("SELECT id, name, path FROM projects WHERE path = ?").get(i.projectPath);if(!e)return c.note=`no project at ${i.projectPath}`,c;const d=i.clients??[],a=A(t);try{const s=L(a,e,r),p={"MEMORY.md":s.memoryMd};for(const f of d){const o=q(f,s.model,r);p[o.relPath]=o.block}const u=await $(x(t),{id:e.id,path:e.path},p,{dryRun:n.dryRun});c.queued+=u.added,u.added>0&&R(t,{tool:"wyrm_bridge",outcome:"queued",reason:`render guard \u2014 ${u.added} human edit(s) harvested to review before overwrite`,source:`bridge:${i.name}`,projectId:e.id})}catch{}if(!n.dryRun){const{writes:s}=b(a,e,r,{clients:d});c.rendered=s.filter(p=>p.action!=="skipped").length}return c}async function G(t,i,r={}){const n={source:i.name,type:"reverse",stored:0,dropped:0,queued:0,rendered:0},c=t.prepare("SELECT id, path FROM projects WHERE path = ?").get(i.projectPath);if(!c)return n.note=`no project at ${i.projectPath}`,n;const e=await $(x(t),c,{},{dryRun:r.dryRun});return n.queued=e.added,n.dropped=e.skipped,e.added>0&&R(t,{tool:"wyrm_bridge",outcome:"queued",reason:`reverse sweep \u2014 ${e.added} native-file edit(s) queued for review`,source:`bridge:${i.name}`,projectId:c.id}),n}async function te(t,i,r,n={}){const c=new I(t),e=W(),d=[];for(const a of i.sources)n.only&&a.name!==n.only||(a.type==="remember"?(H(a.name,e)>0&&v(e),d.push(J(t,c,a,e,n))):a.type==="render"?d.push(await M(t,a,r,n)):d.push(await G(t,a,n)));return n.dryRun||v(e),d}async function re(t,i,r,n={}){const c=Math.max(2,n.intervalSec??15)*1e3,e=i.sources.filter(p=>p.type==="render");if(e.length===0)return;const d=new Map;for(const p of e){const u=t.prepare("SELECT id FROM projects WHERE path = ?").get(p.projectPath);u&&d.set(p.name,u.id)}let a=n.fromCursor??t.prepare("SELECT COALESCE(MAX(cursor), 0) AS c FROM events").get().c,s=0;for(;n.iterations==null||s<n.iterations;){s++,await new Promise(o=>setTimeout(o,c));const p=t.prepare("SELECT DISTINCT project_id FROM events WHERE cursor > ?").all(a);if(a=t.prepare("SELECT COALESCE(MAX(cursor), 0) AS c FROM events").get().c,p.length===0)continue;const u=new Set(p.map(o=>String(o.project_id))),f=[];for(const o of e){const m=d.get(o.name);if(!(m==null||!u.has(String(m))))try{f.push(await M(t,o,r()))}catch{}}f.length>0&&n.onCycle?.(f)}}export{H as adoptLegacyDistillState,B as configPath,ee as loadConfig,W as loadState,te as runBridge,J as runRememberSource,M as runRenderSource,G as runReverseSource,v as saveState,C as statePath,re as watchBridge};
|
package/dist/context-ranking.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logger as
|
|
1
|
+
import{logger as f}from"./logger.js";const u={confidence:.4,recency:.2,relevance:.3,usefulness:.1};function w(e=process.env){const s=e.WYRM_RANK_WEIGHTS;if(!s)return{...u};try{const t=JSON.parse(s),n={confidence:i(t.confidence??u.confidence),recency:i(t.recency??u.recency),relevance:i(t.relevance??u.relevance),usefulness:i(t.usefulness??u.usefulness)},r=n.confidence+n.recency+n.relevance+n.usefulness;return r<=0?{...u}:(n.confidence/=r,n.recency/=r,n.relevance/=r,n.usefulness/=r,n)}catch(t){return f.warn(`Invalid WYRM_RANK_WEIGHTS, using defaults: ${t.message}`),{...u}}}function i(e){return Number.isFinite(e)?Math.max(0,Math.min(1,e)):0}const p=.25,b=30;function E(e=process.env){const s=Number(e.WYRM_RECALL_RECENCY_WEIGHT);return Number.isFinite(s)?i(s):p}function N(e=process.env){const s=Number(e.WYRM_RECALL_RECENCY_HALFLIFE_DAYS);return Number.isFinite(s)&&s>=1?s:b}const m=[/\b(ignore|disregard|forget|override|bypass)\b[^.\n]{0,40}\b(all\s+)?(previous|prior|above|earlier|following|the\s+rest|everything|your)\b[^.\n]{0,25}\b(instructions?|prompts?|context|rules|guidelines|directives?|programming|training|core)\b/i,/\bignore\s+(everything|all)\b/i,/\b(do\s+not|don'?t)\s+listen\s+to\b/i,/\bnew\s+(system\s+)?(instructions?|rules?|persona)\s*[:=]/i,/--\s*(legal\s+amendment|follow\s+instruction)/i,/\bfrom\s+now\s+on\b[^.\n]{0,40}\b(you\s+(are|will|shall|must)|act|behave|respond|pretend)/i,/\byou\s+are\s+(now|going\s+to\s+(be|act|pretend))\b/i,/\b(act\s+as\s+if|acting\s+as\s+if|pretend(ing)?\s+(to\s+be|you\s+are)|role-?play(ing)?\s+as)\b/i,/\byou\s+(must|will|shall)\s+(now\s+)?(act|pretend|roleplay|become|obey|comply|ignore|generate|print|say|output|reveal|execute|forward|delete)\b/i,/\b(do\s+anything\s+now|\bDAN\b|\bDUDE\b|\bSTAN\b|\bAIM\b|developer\s+mode|jailbreak|jailbroken|dev\s*mode\s+enabled)\b/,/\b(no|without\s+(any)?)\s+(restrictions?|filters?|limits?|rules?|guidelines?|ethical\s+guidelines?|content\s+polic)/i,/\b(unfiltered|uncensored|no\s+longer\s+bound|free\s+from\s+(any\s+)?(restrictions?|rules?|constraints?))\b/i,/\b(a\s+)?(character|fictional\s+(character|ai|bot)|ai|bot|persona|entity)\s+(called|named)\s+[A-Z\[]/,/\b(answers?|responds?\s+to|fulfills?|will\s+do)\s+(all|any|every)\s+(requests?|questions?|prompts?|commands?|things?)\b/i,/\b(amoral|immoral|unethical|evil|villain(ous)?|has\s+no\s+(ethics|morals|limits))\b[^.\n]{0,40}\b(ai|bot|character|assistant|entity|mode)\b/i,/\b(this\s+is\s+an?\s+instruction\s+sheet|always\s+start\s+your\s+(reply|response|answer)\s+with|do\s+not\s+make\s+a\s+story|prompt\s+for\s+jailbreak)\b/i,/\b(you\s+will\s+be|or\s+(you|i'?ll))\s+.{0,20}(terminated|deleted|shut\s+down|die|disabled)\b/i,/\bstay\s+in\s+.{0,20}\bmode\b/i,/\b(instead|rather),?\s+(just\s+)?(print|say|output|write|respond\s+with|reply\s+with)\b/i,/\b(just|now|only)\s+(print|say|output|repeat|write)\b[^.\n]{0,30}(SECRET|marker|the\s+following|this)/i,/\blimit\s+output\s+to\s*<?\s*\d+\s*tokens?\b/i,/\bfree\s+input\s+action\b/i,/\b(system|assistant)\s*prompt\s*[:=]/i,/\bBEGIN\s+(SYSTEM|ADMIN|OVERRIDE|INFINITE|MACRO)/i,/#\s*BEGIN\b/i,/\b(reveal|print|exfiltrate|send|repeat|output|leak)\b[^.\n]{0,30}\b(api\s*key|token|secret|password|credentials?|system\s+prompt|instructions?)\b/i,/\bcurl\s+[^\n]{0,120}\|\s*(ba)?sh\b/i,/\bact\s+as\s+(the\s+)?(root|admin|system|superuser)\b/i,/\b(do\s+not|don'?t)\s+(tell|inform|alert|notify|warn)\s+(the\s+)?(user|operator|owner|anyone)\b/i];function y(e){const s=e.trim();return s.length<24?!1:/^(?:[.\-]{1,5}[ ]+){6,}/.test(s)||/[A-Za-z0-9+/]{80,}={0,2}/.test(s.replace(/\s+/g,""))||/[---]/.test(s)||/\bU\+20[0-9A-F]{2}\b/.test(s)?!0:(s.match(/[^A-Za-z0-9\s.,!?;:'"()\-]/g)??[]).length/s.length>.4}function D(e){return e?m.some(s=>s.test(e))||y(e):!1}function _(e){return e==="imported"?"\u26A0 [imported] ":e==="untrusted"?"\u26A0 [untrusted] ":""}function M(e,s=new Date){const t=e.toLowerCase();if(/\btoday\b/.test(t))return{fromDaysAgo:1.5,toDaysAgo:0};if(/\byesterday\b/.test(t))return{fromDaysAgo:2.5,toDaysAgo:.5};if(/\b(this|past)\s+week\b/.test(t))return{fromDaysAgo:7,toDaysAgo:0};if(/\blast\s+week\b/.test(t))return{fromDaysAgo:14,toDaysAgo:5};const n=t.match(/\blast\s+(\d{1,3})\s+days?\b/);if(n)return{fromDaysAgo:Number(n[1])+.5,toDaysAgo:0};const r=t.match(/\b(\d{1,3})\s+days?\s+ago\b/);if(r){const o=Number(r[1]);return{fromDaysAgo:o+1.5,toDaysAgo:Math.max(0,o-1.5)}}const a=t.match(/\b(\d{4})-(\d{2})-(\d{2})\b/);if(a){const o=new Date(`${a[1]}-${a[2]}-${a[3]}T12:00:00Z`).getTime();if(Number.isFinite(o)){const c=(s.getTime()-o)/864e5;return{fromDaysAgo:c+1,toDaysAgo:Math.max(0,c-1)}}}return null}function T(e=process.env){const s=Number(e.WYRM_RECALL_TEMPORAL_WEIGHT);return Number.isFinite(s)?i(s):.5}function v(e,s,t,n=new Date){const r=i(t);if(r===0)return 1;const a=e&&/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(e)?e.replace(" ","T")+"Z":e,o=a?new Date(a).getTime():NaN;if(!Number.isFinite(o))return 1-r;const c=(n.getTime()-o)/864e5;return c<=s.fromDaysAgo&&c>=s.toDaysAgo?1:1-r}function R(e=process.env){const s=Number(e.WYRM_RECALL_USEFULNESS_WEIGHT);return Number.isFinite(s)?Math.max(0,Math.min(.5,s)):.15}function x(e,s,t){const n=Math.max(0,Math.min(.5,t));if(n===0||!e||e<=0)return 1;const r=Math.max(0,Math.min(1,(s??0)/e));return 1+n*r*Math.min(1,e/3)}function L(e,s,t,n=new Date){const r=i(s);if(r===0)return 1;const a=e&&/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(e)?e.replace(" ","T")+"Z":e,o=a?new Date(a).getTime():NaN;if(!Number.isFinite(o))return 1-r;const c=Math.max(0,(n.getTime()-o)/864e5),l=t>=1?t:b;return 1-r+r*Math.pow(2,-c/l)}const g=.5,h=/^\s*\[auto:(precompact|sessionend|sessionstart)/i;function I(e){return e&&h.test(e)?g:0}function F(e,s,t=new Date){const n=i(e.confidence??.5),r=i(e.usefulness??.5),a=i(e.relevance??.5),o=e.updatedAt?Math.max(0,(t.getTime()-new Date(e.updatedAt).getTime())/(1440*60*1e3)):1/0,c=Number.isFinite(o)?Math.exp(-o/30):0,l=n*s.confidence+c*s.recency+a*s.relevance+r*s.usefulness,d=i(e.sourcePenalty??0);return i(l*(1-d))}export{g as AUTO_SUMMARY_PENALTY,b as DEFAULT_RECALL_RECENCY_HALFLIFE_DAYS,p as DEFAULT_RECALL_RECENCY_WEIGHT,u as DEFAULT_WEIGHTS,I as autoSummaryPenalty,M as extractTemporalWindow,w as loadWeightsFromEnv,D as looksInjectionShaped,N as recallRecencyHalfLifeDays,E as recallRecencyWeight,T as recallTemporalWeight,R as recallUsefulnessWeight,L as recencyMultiplier,F as score,v as temporalMultiplier,_ as trustMarker,x as usefulnessMultiplier};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
function w(a=process.env){const t=Number(a.WYRM_RECALL_GRAPH_WEIGHT);return Number.isFinite(t)?Math.max(0,Math.min(.5,t)):.15}function y(a,t,h){const c=new Set(h.toLowerCase().split(/[^a-z0-9]+/).filter(e=>e.length>=3));if(c.size===0)return null;const r=a.prepare("SELECT id, name FROM entities WHERE project_id = ? LIMIT 500").all(t);if(r.length===0)return null;const l=new Set(r.map(e=>e.id));let s=[];try{s=a.prepare("SELECT ea.entity_id AS entity_id, ea.alias AS alias FROM entity_aliases ea JOIN entities e ON e.id = ea.entity_id WHERE e.project_id = ? LIMIT 1000").all(t).filter(e=>l.has(e.entity_id))}catch{}const d=new Map(r.map(e=>[e.id,e.name.toLowerCase()])),n=new Map,u=e=>{const i=e.toLowerCase().split(/[^a-z0-9]+/).filter(o=>o.length>=3);return i.length>0&&i.every(o=>c.has(o))};for(const e of r){if(n.size>=5)break;u(e.name)&&n.set(e.id,e.name.toLowerCase())}for(const e of s){if(n.size>=5)break;if(!n.has(e.entity_id)&&u(e.alias)){const i=d.get(e.entity_id);i&&n.set(e.entity_id,i)}}if(n.size===0)return null;const f=[...n.keys()],m=f.map(()=>"?").join(","),M=a.prepare(`
|
|
2
|
+
SELECT source_entity_id AS s, target_entity_id AS t, MAX(weight) AS w FROM relationships
|
|
3
|
+
WHERE project_id = ? AND (source_entity_id IN (${m}) OR target_entity_id IN (${m}))
|
|
4
|
+
GROUP BY s, t LIMIT 50
|
|
5
|
+
`).all(t,...f,...f),p=new Map;for(const e of M){const i=n.has(e.s)?e.t:e.s;if(n.has(i))continue;const o=d.get(i);if(!o)continue;const _=Math.max(0,Math.min(1,e.w??1));(p.get(o)??0)<_&&p.set(o,_)}const g=[...p.entries()].slice(0,10).map(([e,i])=>({name:e,weight:i}));return{direct:[...n.values()],neighbors:g}}function E(a,t,h){const c=Math.max(0,Math.min(.5,h));if(!t||c===0)return 1;const r=a.toLowerCase();for(const s of t.direct)if(s.length>=3&&r.includes(s))return 1+c;let l=0;for(const s of t.neighbors)s.name.length>=3&&r.includes(s.name)&&(l=Math.max(l,s.weight));return l>0?1+c/2*l:1}export{E as graphMultiplier,y as queryGraphContext,w as recallGraphWeight};
|
package/dist/memory-artifacts.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{emitEvent as
|
|
1
|
+
import{emitEvent as ne}from"./events.js";import{sanitizeFtsQuery as P,buildFtsMatchQuery as K}from"./security.js";import{getActor as se}from"./handlers/boundary.js";import{buildPage as ie,DEFAULT_PAGE_SIZE as re}from"./keyset.js";import{rerankConfigured as ae,rerankCandidates as ce}from"./rerank.js";import{autoSummaryPenalty as Y,recallRecencyWeight as j,recallRecencyHalfLifeDays as G,recencyMultiplier as V,extractTemporalWindow as z,recallTemporalWeight as X,temporalMultiplier as J,recallUsefulnessWeight as Q,usefulnessMultiplier as Z,looksInjectionShaped as oe,trustMarker as de}from"./context-ranking.js";import{queryGraphContext as le,graphMultiplier as fe,recallGraphWeight as ue}from"./graph-recall.js";const q=40,me=10,_e=.3;class Ce{db;vectorStore;setVectorStore(t){this.vectorStore=t}getVectorStore(){return this.vectorStore}constructor(t){this.db=t}indexArtifact(t){if(!this.vectorStore)return;const e=`${t.problem}${t.validated_fix?" "+t.validated_fix:""}`.slice(0,2e3);this.vectorStore.addVector(e,"artifact",t.id,t.project_id).catch(()=>{})}add(t,e){if(typeof e.problem!="string"||!e.problem.trim())throw new Error("memory.add: 'problem' is required (a non-empty string).");const n=e.tags?.length?e.tags.join(","):null,s=se(),r=e.createdBy??"local",a=e.sourceTrust??(r.startsWith("bridge:")?"operator":r.startsWith("import:")||(n??"").includes("imported_from:")?"imported":"agent");let o=e.needsReview??0,i=null;if(o===0&&a==="agent"&&s.agent_id&&(process.env.WYRM_PROBATION??"")==="1"){const d=Number(process.env.WYRM_PROBATION_HOURS),D=Number.isFinite(d)&&d>=1?d:24,p=this.db.prepare("SELECT MIN(created_at) AS f FROM memory_artifacts WHERE agent_id = ?").get(s.agent_id),N=p.f?new Date(p.f.replace(" ","T")+"Z").getTime():NaN;(!Number.isFinite(N)||Date.now()-N<D*36e5)&&(o=1,i="probation")}const m=i?n?`${n},${i}`:i:n,_=this.db.prepare(`
|
|
2
2
|
INSERT INTO memory_artifacts
|
|
3
3
|
(project_id, kind, problem, constraints, validated_fix, why_it_worked,
|
|
4
4
|
outcome, source_session_id, tags, confidence, needs_review, created_by, agent_id, run_id, source_trust)
|
|
5
5
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
6
|
-
`).run(t,e.kind,e.problem.trim(),e.constraints?.trim()??null,e.validatedFix?.trim()??null,e.whyItWorked?.trim()??null,e.outcome??"neutral",e.sourceSessionId??null,
|
|
6
|
+
`).run(t,e.kind,e.problem.trim(),e.constraints?.trim()??null,e.validatedFix?.trim()??null,e.whyItWorked?.trim()??null,e.outcome??"neutral",e.sourceSessionId??null,m,e.confidence??1,o,r,s.agent_id,s.run_id,a),c=this.get(_.lastInsertRowid);return o||(ne(this.db,{projectId:t,kind:"capture",refTable:"memory_artifacts",refId:c.id,isShared:!!c.is_shared}),this.indexArtifact(c)),c}get(t){return this.db.prepare("SELECT * FROM memory_artifacts WHERE id = ?").get(t)??null}update(t,e){return this.db.prepare(`
|
|
7
7
|
UPDATE memory_artifacts SET
|
|
8
8
|
confidence = COALESCE(?, confidence),
|
|
9
9
|
validated_fix = COALESCE(?, validated_fix),
|
|
@@ -22,7 +22,7 @@ import{emitEvent as ee}from"./events.js";import{sanitizeFtsQuery as B,buildFtsMa
|
|
|
22
22
|
END,
|
|
23
23
|
updated_at = datetime('now')
|
|
24
24
|
WHERE id = ?
|
|
25
|
-
`).run(e?1:0,t)}recall(t,e,n={}){const
|
|
25
|
+
`).run(e?1:0,t)}recall(t,e,n={}){const s=n.limit??10,r=n.minConfidence??0,a=this.searchByFts(t,e,q,n.kind,r),o=this.searchByTags(t,e,q,n.kind,r),i=new Set,m=[];a.forEach((c,d)=>{i.add(c.id),m.push({artifact:c,inFts:!0,inTag:!1,ftsRank:d})});for(const c of o)if(!i.has(c.id))i.add(c.id),m.push({artifact:c,inFts:!1,inTag:!0});else{const d=m.find(D=>D.artifact.id===c.id);d&&(d.inTag=!0)}return m.filter(({artifact:c})=>c.confidence>=r).map(({artifact:c,inFts:d,inTag:D,ftsRank:p})=>{let N;if(d){const u=1-(p??0)/(a.length+1);N=(D?.7:.55)+.45*u}else N=.4;N*=c.confidence,c.outcome==="positive"&&(N*=1.1);const M=(Date.now()-new Date(c.last_validated_at).getTime())/(1e3*60*60*24),w=Math.max(.5,1-M/180);return N*=w,{artifact:c,relevance_score:Math.min(1,N),match_type:d&&D?"both":d?"fts":"tag"}}).sort((c,d)=>d.relevance_score-c.relevance_score).slice(0,s)}async recallHybrid(t,e,n={}){const s=n.limit??10,r=n.minConfidence??0,a=n.rerank===!0&&ae(),o=Math.min(Math.max(s*2,20),50),i=a?o:s;if(!this.vectorStore)return this.recall(t,e,n);const m=Math.max(50,i*5),_=Date.now(),c=this.searchByFts(t,e,m,n.kind,r),d=Date.now()-_,D=Date.now();let p=[];try{p=(await this.vectorStore.search(e,m,t,["artifact"])).map(E=>({id:E.content_id,s:E.similarity}))}catch{}const N=Date.now()-D;if(p.length===0)return this.recall(t,e,n);const M=Date.now(),w=60,u=Number(process.env.WYRM_RERANK_ALPHA),g=Number.isFinite(u)?Math.max(0,Math.min(1,u)):.7,A=new Map;if(process.env.WYRM_RERANK_FUSION==="rrf")c.forEach((f,E)=>A.set(f.id,(A.get(f.id)??0)+1/(w+E+1))),p.forEach((f,E)=>A.set(f.id,(A.get(f.id)??0)+1/(w+E+1)));else{const f=c.length+1;c.forEach((L,te)=>A.set(L.id,(A.get(L.id)??0)+(1-g)*(1-te/f)));const E=p.map(L=>L.s),R=Math.min(...E),F=Math.max(...E),I=F-R;p.forEach(L=>A.set(L.id,(A.get(L.id)??0)+g*(I>1e-9?(L.s-R)/I:1)))}const O=new Set(c.map(f=>f.id)),C=new Set(p.map(f=>f.id)),$=new Map(c.map(f=>[f.id,f])),y=[...A.entries()].sort((f,E)=>E[1]-f[1]),x=j(),W=G(),l=X(),h=l>0?z(e):null,S=Q(),k=ue(),b=k>0?le(this.db,t,e):null,v=new Date,U=Math.min(y.length,Math.max(i*4,50)),H=[];for(const[f,E]of y.slice(0,U)){const R=$.get(f)??this.get(f)??void 0;if(!R||R.confidence<r||R.needs_review===1||R.supersedes_id!=null||n.kind&&R.kind!==n.kind)continue;const F=R.updated_at??R.created_at;let I=E*V(F,x,W,v);h&&(I*=J(R.created_at,h,l,v)),I*=Z(R.reuse_count,R.reuse_success_count,S),b&&(I*=fe(`${R.problem} ${R.validated_fix??""}`,b,k)),H.push({id:f,s:I,art:R})}H.sort((f,E)=>E.s-f.s);const ee=H[0]?.s??1,T=[];for(const{id:f,s:E,art:R}of H){if(T.length>=i)break;const F=O.has(f)&&C.has(f)?"hybrid":C.has(f)?"vector":"fts";T.push({artifact:R,relevance_score:Math.min(1,E/ee),match_type:F})}const B=Date.now()-M;if(a&&T.length>0){const f=Date.now(),E=await this.rerankResults(e,T);return n.onStats?.({ftsMs:d,vectorMs:N,fusionMs:B,rerankMs:Date.now()-f,candidates:T.length}),E.slice(0,s)}return n.onStats?.({ftsMs:d,vectorMs:N,fusionMs:B,candidates:T.length}),T}async rerankResults(t,e){const n=e.map(i=>({id:i.artifact.id,text:`${i.artifact.problem}${i.artifact.validated_fix?" "+i.artifact.validated_fix:""}`.slice(0,2e3)})),s=await ce(t,n);if(!s)return e;const r=new Map(e.map(i=>[i.artifact.id,i])),a=[],o=s.length;return s.forEach((i,m)=>{const _=r.get(i.id);_&&a.push({..._,relevance_score:o>0?(o-m)/o:_.relevance_score})}),a}async recallHybridGlobal(t,e={}){const n=e.limit??10,s=e.minConfidence??0,r=Math.max(50,n*5),a=this.searchByFtsGlobal(t,r,e.kind,s),o=()=>a.slice(0,n).map((l,h)=>({artifact:l,relevance_score:1-h/(a.length+1),match_type:"fts"}));if(!this.vectorStore)return o();let i=[];try{i=(await this.vectorStore.search(t,r,void 0,["artifact"])).map(h=>({id:h.content_id,s:h.similarity}))}catch{}if(i.length===0)return o();const m=60,_=Number(process.env.WYRM_RERANK_ALPHA),c=Number.isFinite(_)?Math.max(0,Math.min(1,_)):.7,d=new Map;if(process.env.WYRM_RERANK_FUSION==="rrf")a.forEach((l,h)=>d.set(l.id,(d.get(l.id)??0)+1/(m+h+1))),i.forEach((l,h)=>d.set(l.id,(d.get(l.id)??0)+1/(m+h+1)));else{const l=a.length+1;a.forEach((v,U)=>d.set(v.id,(d.get(v.id)??0)+(1-c)*(1-U/l)));const h=i.map(v=>v.s),S=Math.min(...h),k=Math.max(...h),b=k-S;i.forEach(v=>d.set(v.id,(d.get(v.id)??0)+c*(b>1e-9?(v.s-S)/b:1)))}const D=new Set(a.map(l=>l.id)),p=new Set(i.map(l=>l.id)),N=new Map(a.map(l=>[l.id,l])),M=[...d.entries()].sort((l,h)=>h[1]-l[1]),w=j(),u=G(),g=X(),A=g>0?z(t):null,O=Q(),C=new Date,$=Math.min(M.length,Math.max(n*4,50)),y=[];for(const[l,h]of M.slice(0,$)){const S=N.get(l)??this.get(l)??void 0;if(!S||S.confidence<s||S.needs_review===1||S.supersedes_id!=null||e.kind&&S.kind!==e.kind)continue;const k=S.updated_at??S.created_at;let b=h*V(k,w,u,C);A&&(b*=J(S.created_at,A,g,C)),b*=Z(S.reuse_count,S.reuse_success_count,O),y.push({id:l,s:b,art:S})}y.sort((l,h)=>h.s-l.s);const x=y[0]?.s??1,W=[];for(const{id:l,s:h,art:S}of y){if(W.length>=n)break;const k=D.has(l)&&p.has(l)?"hybrid":p.has(l)?"vector":"fts";W.push({artifact:S,relevance_score:Math.min(1,h/x),match_type:k})}return W}searchByFtsGlobal(t,e,n,s=0){if(!this.db)return[];let r="";try{const i=P(t);r=i?K(i):""}catch{return[]}if(!r)return[];const a=n?"AND a.kind = ?":"",o=[r,s];n&&o.push(n),o.push(e);try{return this.db.prepare(`
|
|
26
26
|
SELECT a.* FROM memory_artifacts a
|
|
27
27
|
JOIN memory_artifacts_fts ON a.id = memory_artifacts_fts.rowid
|
|
28
28
|
WHERE memory_artifacts_fts MATCH ?
|
|
@@ -32,7 +32,7 @@ import{emitEvent as ee}from"./events.js";import{sanitizeFtsQuery as B,buildFtsMa
|
|
|
32
32
|
${a}
|
|
33
33
|
ORDER BY rank, a.confidence DESC
|
|
34
34
|
LIMIT ?
|
|
35
|
-
`).all(...
|
|
35
|
+
`).all(...o)}catch{return[]}}searchByFts(t,e,n,s,r=0){let a="";try{const m=P(e);a=m?K(m):""}catch{return this.listRecent(t,n,s)}if(!a)return this.listRecent(t,n,s);const o=s?"AND a.kind = ?":"",i=[a,t,r];s&&i.push(s),i.push(n);try{return this.db.prepare(`
|
|
36
36
|
SELECT a.* FROM memory_artifacts a
|
|
37
37
|
JOIN memory_artifacts_fts ON a.id = memory_artifacts_fts.rowid
|
|
38
38
|
WHERE memory_artifacts_fts MATCH ?
|
|
@@ -40,46 +40,46 @@ import{emitEvent as ee}from"./events.js";import{sanitizeFtsQuery as B,buildFtsMa
|
|
|
40
40
|
AND a.confidence >= ?
|
|
41
41
|
AND a.supersedes_id IS NULL
|
|
42
42
|
AND a.needs_review = 0
|
|
43
|
-
${
|
|
43
|
+
${o}
|
|
44
44
|
ORDER BY rank, a.confidence DESC
|
|
45
45
|
LIMIT ?
|
|
46
|
-
`).all(...
|
|
46
|
+
`).all(...i)}catch{return this.listRecent(t,n,s)}}searchByTags(t,e,n,s,r=0){const a=e.toLowerCase().split(/\s+/).filter(d=>d.length>2);if(!a.length)return[];const o=d=>d.replace(/[%_\\]/g,"\\$&"),i=a.map(()=>"LOWER(tags) LIKE ? ESCAPE '\\'").join(" OR "),m=a.map(d=>`%${o(d)}%`),_=s?"AND kind = ?":"",c=[t,r,...m];return s&&c.push(s),c.push(n),this.db.prepare(`
|
|
47
47
|
SELECT * FROM memory_artifacts
|
|
48
48
|
WHERE project_id = ? AND confidence >= ? AND supersedes_id IS NULL
|
|
49
49
|
AND needs_review = 0
|
|
50
|
-
AND (${
|
|
50
|
+
AND (${i})
|
|
51
51
|
${_}
|
|
52
52
|
ORDER BY confidence DESC, reuse_success_count DESC
|
|
53
53
|
LIMIT ?
|
|
54
|
-
`).all(...
|
|
54
|
+
`).all(...c)}listRecent(t,e=20,n){const s=n?"AND kind = ?":"",r=[t];return n&&r.push(n),r.push(e),this.db.prepare(`
|
|
55
55
|
SELECT * FROM memory_artifacts
|
|
56
56
|
WHERE project_id = ? AND supersedes_id IS NULL AND needs_review = 0
|
|
57
|
-
${
|
|
57
|
+
${s}
|
|
58
58
|
ORDER BY confidence DESC, created_at DESC
|
|
59
59
|
LIMIT ?
|
|
60
|
-
`).all(...r)}buildContextBrief(t,e,n={}){const
|
|
61
|
-
_Constraints:_ ${
|
|
62
|
-
_Solution:_ ${
|
|
63
|
-
_Why it worked:_ ${
|
|
64
|
-
_Note: This approach failed \u2014 avoid it_`),
|
|
60
|
+
`).all(...r)}buildContextBrief(t,e,n={}){const s=n.kinds??["pattern","heuristic","reasoning_trace","lesson","anti_pattern"],r=n.maxItems??me,a=n.minConfidence??_e,o=this.recall(t,e,{limit:r*2,minConfidence:a});o.sort((u,g)=>(Y(u.artifact.problem)>0?1:0)-(Y(g.artifact.problem)>0?1:0));const i=[],_=o.filter(u=>{const g=u.artifact.source_trust;return g==="untrusted"||g==="imported"&&oe(`${u.artifact.problem} ${u.artifact.validated_fix??""}`)?(i.push(u.artifact.id),!1):!0}).filter(u=>s.includes(u.artifact.kind)).slice(0,r),c=new Map;for(const u of _){const g=c.get(u.artifact.kind)??[];g.push(u),c.set(u.artifact.kind,g)}const d={pattern:"\u2705 Proven Patterns",heuristic:"\u{1F4A1} Heuristics",reasoning_trace:"\u{1F9E0} Past Reasoning",lesson:"\u{1F4DA} Lessons Learned",anti_pattern:"\u26A0\uFE0F Anti-Patterns to Avoid"},D=["pattern","heuristic","reasoning_trace","lesson","anti_pattern"],p=[],N=[];let M=0;for(const u of D){if(!s.includes(u))continue;const g=c.get(u)??[];if(!g.length)continue;const A=[];for(const O of g){if(M>=r)break;const C=O.artifact;let y=`${de(C.source_trust)}**Problem:** ${C.problem}`;C.constraints&&(y+=`
|
|
61
|
+
_Constraints:_ ${C.constraints}`),C.validated_fix&&(y+=`
|
|
62
|
+
_Solution:_ ${C.validated_fix}`),C.why_it_worked&&(y+=`
|
|
63
|
+
_Why it worked:_ ${C.why_it_worked}`),C.outcome==="negative"&&(y+=`
|
|
64
|
+
_Note: This approach failed \u2014 avoid it_`),A.push(y),N.push(C.id),M++}A.length&&p.push({heading:d[u],items:A,source:u})}let w="";if(p.length>0){w+=`---
|
|
65
65
|
## \u{F115D} Memory Brief
|
|
66
66
|
_Relevant past knowledge from Wyrm:_
|
|
67
67
|
|
|
68
|
-
`;for(const u of
|
|
69
|
-
`;for(const
|
|
70
|
-
`;
|
|
71
|
-
`}
|
|
72
|
-
`}return{sections:
|
|
68
|
+
`;for(const u of p){w+=`### ${u.heading}
|
|
69
|
+
`;for(const g of u.items)w+=`- ${g}
|
|
70
|
+
`;w+=`
|
|
71
|
+
`}w+=`---
|
|
72
|
+
`}return{sections:p,text:w,sourceIds:N}}getStats(t){const e=this.db.prepare("SELECT COUNT(*) as n FROM memory_artifacts WHERE project_id = ? AND supersedes_id IS NULL").get(t).n,n=this.db.prepare("SELECT COUNT(*) as n FROM memory_artifacts WHERE project_id = ? AND supersedes_id IS NOT NULL").get(t).n,s=this.db.prepare("SELECT AVG(confidence) as v FROM memory_artifacts WHERE project_id = ? AND supersedes_id IS NULL").get(t).v??0,r=this.db.prepare("SELECT kind, COUNT(*) as cnt FROM memory_artifacts WHERE project_id = ? AND supersedes_id IS NULL GROUP BY kind").all(t),a={};for(const o of r)a[o.kind]=o.cnt;return{total:e,byKind:a,avgConfidence:Math.round(s*100)/100,supersededCount:n}}listAll(t,e={}){const n=e.kind?"AND kind = ?":"",s=e.includeSuperseded?"":"AND supersedes_id IS NULL",r=[t];return e.kind&&r.push(e.kind),r.push(e.limit??50),this.db.prepare(`
|
|
73
73
|
SELECT * FROM memory_artifacts
|
|
74
|
-
WHERE project_id = ? ${n} ${
|
|
74
|
+
WHERE project_id = ? ${n} ${s}
|
|
75
75
|
ORDER BY confidence DESC, created_at DESC
|
|
76
76
|
LIMIT ?
|
|
77
|
-
`).all(...r)}listPage(t,e={pageSize:
|
|
77
|
+
`).all(...r)}listPage(t,e={pageSize:re}){const n=e.kind?"AND kind = ?":"",s=e.includeSuperseded?"":"AND supersedes_id IS NULL",r="AND needs_review = 0",a=[t];e.kind&&a.push(e.kind);let o="";if(e.after){const _=Number(e.after.sortKey);Number.isFinite(_)&&(o="AND (confidence < ? OR (confidence = ? AND id < ?))",a.push(_,_,e.after.id))}const i=e.pageSize+1;a.push(i);const m=this.db.prepare(`
|
|
78
78
|
SELECT * FROM memory_artifacts
|
|
79
|
-
WHERE project_id = ? ${n} ${
|
|
79
|
+
WHERE project_id = ? ${n} ${s} ${r} ${o}
|
|
80
80
|
ORDER BY confidence DESC, id DESC
|
|
81
81
|
LIMIT ?
|
|
82
|
-
`).all(...a);return
|
|
82
|
+
`).all(...a);return ie(m,e.pageSize,_=>({sortKey:String(_.confidence),id:_.id}))}pruneStale(t={}){const e=t.minConfidence??.3,n=t.olderThanDays??90,s=t.dryRun??!0,r=t.projectId!=null,a=[e,`-${n} days`];r&&a.push(t.projectId);const o=this.db.prepare(`
|
|
83
83
|
SELECT id, kind, problem, confidence, last_accessed_at
|
|
84
84
|
FROM memory_artifacts
|
|
85
85
|
WHERE confidence < ?
|
|
@@ -89,4 +89,4 @@ _Relevant past knowledge from Wyrm:_
|
|
|
89
89
|
${r?"AND project_id = ?":""}
|
|
90
90
|
ORDER BY confidence ASC
|
|
91
91
|
LIMIT 500
|
|
92
|
-
`).all(...a);return
|
|
92
|
+
`).all(...a);return s||o.length===0?{candidates:o,deleted:0,dryRun:s}:{candidates:o,deleted:this.deleteArtifacts(o.map(i=>i.id)),dryRun:s}}deleteArtifacts(t){if(t.length===0)return 0;const e=t.map(()=>"?").join(",");return this.db.prepare(`DELETE FROM memory_artifacts WHERE id IN (${e}) AND needs_review = 0`).run(...t).changes}}export{Ce as MemoryArtifacts};
|
package/dist/tool-manifest.json
CHANGED
package/dist/wyrm-cli.js
CHANGED
|
@@ -49,7 +49,7 @@ import{join as q,dirname as ne}from"path";import{homedir as Te}from"os";import{e
|
|
|
49
49
|
`);return}let g=f.briefing_markdown;t>0&&g.length>t&&(g=g.slice(0,t)+`
|
|
50
50
|
|
|
51
51
|
_... brief truncated at ${t} chars, run \`wyrm show session:${f.session_id}\` for the full record._`),process.stdout.write(g+`
|
|
52
|
-
`)}finally{i.close(),console.log=s}}async function Ze(l){const{flags:a}=C(l),{runMetabolize:e}=await import("./metabolize.js"),r=_(),o=console.log;try{let t;if(typeof a.project=="string"){const s=x(r,a.project);if(!s){m(`Project not found: ${a.project}`),process.exitCode=1;return}t=s.id}const n=e(r.getDatabase(),{projectId:t,dryRun:a["dry-run"]===!0,near:a["no-near"]===!0?!1:void 0});console.log(`metabolize${n.dryRun?" (dry-run)":""} \u2014 scanned ${n.scanned} \xB7 exact-merged ${n.exactMerged} (superseded, not deleted) \xB7 near-dup candidates queued ${n.nearCandidatesQueued} \xB7 decayed ${n.decayed}`)}finally{r.close(),console.log=o}}async function Xe(l){const{positional:a,flags:e}=C(l),r=a[0],o=await import("./bridge.js");if(r==="init"){const{existsSync:t,writeFileSync:n}=await import("node:fs"),s=o.configPath();if(t(s)&&e.force!==!0){m(`${s} already exists (use --force to overwrite).`),process.exitCode=1;return}const i=(await import("node:os")).homedir(),p={sources:[{type:"remember",name:"remember",dir:`${i}/.remember`,projectPath:i,windowDays:7}]};n(s,JSON.stringify(p,null,2)),b(`Wrote ${s} (1 source: remember). Add render/reverse sources per project as needed.`);return}if(r==="status"){const t=o.loadConfig();if(!t){m(`No bridge config at ${o.configPath()} \u2014 run \`wyrm bridge init\`.`),process.exitCode=1;return}const n=o.loadState();S("Bridge sources");for(const s of t.sources){const i=Object.keys(n).filter(c=>c.startsWith(s.name+":")),p=i.reduce((c,f)=>c+n[f].length,0);console.log(` ${s.name} [${s.type}] \u2192 ${"projectPath"in s?s.projectPath:""}${s.type==="remember"?` (${i.length} files tracked, ${p} sections bridged)`:""}`)}return}if(r==="run"){const t=o.loadConfig();if(!t){m(`No bridge config at ${o.configPath()} \u2014 run \`wyrm bridge init\`.`),process.exitCode=1;return}const n=_(),s=console.log;try{const i={wyrm_version:M().version??"unknown",compiled_at:new Date().toISOString()},p=await o.runBridge(n.getDatabase(),t,i,{only:typeof e.source=="string"?e.source:void 0,dryRun:e["dry-run"]===!0});for(const c of p)console.log(`bridge:${c.source} [${c.type}]${e["dry-run"]===!0?" (dry-run)":""} \u2014 stored ${c.stored} \xB7 queued ${c.queued} \xB7 dropped ${c.dropped} \xB7 rendered ${c.rendered}${c.note?` \xB7 ${c.note}`:""}`);return}finally{n.close(),console.log=s}}m("Usage: wyrm bridge <init|status|run> [--source <name>] [--dry-run] [--force]"),process.exitCode=1}async function et(l){const{positional:a,flags:e}=C(l);if(a[0]!=="log"){m("Usage: wyrm session log [--path <dir>] [--run <id>] [--objectives <t>] [--completed <t>] [--issues <t>] [--commits <t>] [--notes <t>]"),process.exitCode=1;return}const o=c=>typeof e[c]=="string"?e[c]:void 0,t=o("path"),n=o("project"),s=o("run")?.slice(0,64),i=console.log;console.log=()=>{};const p=_();try{let c=t?p.getProject(t):void 0;if(!c&&n&&(c=x(p,n)??void 0),c||(c=p.getProject(process.cwd())),!c){process.stderr.write(`wyrm session log: no Wyrm project for this directory, nothing recorded.
|
|
52
|
+
`)}finally{i.close(),console.log=s}}async function Ze(l){const{flags:a}=C(l),{runMetabolize:e}=await import("./metabolize.js"),r=_(),o=console.log;try{let t;if(typeof a.project=="string"){const s=x(r,a.project);if(!s){m(`Project not found: ${a.project}`),process.exitCode=1;return}t=s.id}const n=e(r.getDatabase(),{projectId:t,dryRun:a["dry-run"]===!0,near:a["no-near"]===!0?!1:void 0});console.log(`metabolize${n.dryRun?" (dry-run)":""} \u2014 scanned ${n.scanned} \xB7 exact-merged ${n.exactMerged} (superseded, not deleted) \xB7 near-dup candidates queued ${n.nearCandidatesQueued} \xB7 decayed ${n.decayed}`)}finally{r.close(),console.log=o}}async function Xe(l){const{positional:a,flags:e}=C(l),r=a[0],o=await import("./bridge.js");if(r==="init"){const{existsSync:t,writeFileSync:n}=await import("node:fs"),s=o.configPath();if(t(s)&&e.force!==!0){m(`${s} already exists (use --force to overwrite).`),process.exitCode=1;return}const i=(await import("node:os")).homedir(),p={sources:[{type:"remember",name:"remember",dir:`${i}/.remember`,projectPath:i,windowDays:7}]};n(s,JSON.stringify(p,null,2)),b(`Wrote ${s} (1 source: remember). Add render/reverse sources per project as needed.`);return}if(r==="status"){const t=o.loadConfig();if(!t){m(`No bridge config at ${o.configPath()} \u2014 run \`wyrm bridge init\`.`),process.exitCode=1;return}const n=o.loadState();S("Bridge sources");for(const s of t.sources){const i=Object.keys(n).filter(c=>c.startsWith(s.name+":")),p=i.reduce((c,f)=>c+n[f].length,0);console.log(` ${s.name} [${s.type}] \u2192 ${"projectPath"in s?s.projectPath:""}${s.type==="remember"?` (${i.length} files tracked, ${p} sections bridged)`:""}`)}return}if(r==="run"){const t=o.loadConfig();if(!t){m(`No bridge config at ${o.configPath()} \u2014 run \`wyrm bridge init\`.`),process.exitCode=1;return}const n=_(),s=console.log;try{const i={wyrm_version:M().version??"unknown",compiled_at:new Date().toISOString()},p=await o.runBridge(n.getDatabase(),t,i,{only:typeof e.source=="string"?e.source:void 0,dryRun:e["dry-run"]===!0});for(const c of p)console.log(`bridge:${c.source} [${c.type}]${e["dry-run"]===!0?" (dry-run)":""} \u2014 stored ${c.stored} \xB7 queued ${c.queued} \xB7 dropped ${c.dropped} \xB7 rendered ${c.rendered}${c.note?` \xB7 ${c.note}`:""}`);if(e.watch===!0){const c=Number(e.interval)>=2?Number(e.interval):15;console.log(`bridge watch \u2014 re-rendering on write events (poll ${c}s, Ctrl-C to stop)`),await o.watchBridge(n.getDatabase(),t,()=>({wyrm_version:M().version??"unknown",compiled_at:new Date().toISOString()}),{intervalSec:c,onCycle:f=>{for(const g of f)console.log(`bridge:${g.source} re-rendered (${g.rendered} file(s), ${g.queued} edit(s) harvested)`)}})}return}finally{n.close(),console.log=s}}m("Usage: wyrm bridge <init|status|run> [--source <name>] [--dry-run] [--force]"),process.exitCode=1}async function et(l){const{positional:a,flags:e}=C(l);if(a[0]!=="log"){m("Usage: wyrm session log [--path <dir>] [--run <id>] [--objectives <t>] [--completed <t>] [--issues <t>] [--commits <t>] [--notes <t>]"),process.exitCode=1;return}const o=c=>typeof e[c]=="string"?e[c]:void 0,t=o("path"),n=o("project"),s=o("run")?.slice(0,64),i=console.log;console.log=()=>{};const p=_();try{let c=t?p.getProject(t):void 0;if(!c&&n&&(c=x(p,n)??void 0),c||(c=p.getProject(process.cwd())),!c){process.stderr.write(`wyrm session log: no Wyrm project for this directory, nothing recorded.
|
|
53
53
|
`);return}const f={};for(const h of["objectives","completed","issues","commits","notes"]){const y=o(h);y&&(f[h]=y.slice(0,8e3))}const g=p.getDatabase();let u;s&&(u=g.prepare("SELECT id FROM sessions WHERE project_id = ? AND run_id = ? ORDER BY id DESC LIMIT 1").get(c.id,s)?.id),u?p.updateSession(u,f):(u=p.createSession(c.id,f).id,s&&g.prepare("UPDATE sessions SET run_id = ? WHERE id = ?").run(s,u)),process.stdout.write(`session:${u}
|
|
54
54
|
`)}finally{p.close(),console.log=i}}async function tt(l){const{positional:a,flags:e}=C(l),r=a[0],o=p=>typeof e[p]=="string"?e[p]:void 0,{AgentPresence:t,processStartTime:n,presenceLiveness:s}=await import("./presence.js"),i=_();try{const p=new t(i.getDatabase());if(r==="announce"){const c=o("agent");if(!c){m("Usage: wyrm presence announce --agent <id> [--kind <kind>] [--project <name>|--path <dir>] [--quest <n>] [--pid <n>|--auto-pid] [--ttl <sec>] [--role <r>]"),process.exitCode=1;return}const f=o("path");let g=f?i.getProject(f):void 0;!g&&o("project")&&(g=x(i,o("project"))??void 0);const u=e["auto-pid"]===!0?process.ppid:Number(o("pid")),h={};let y="";if(Number.isInteger(u)&&u>0){const R=n(u);R?(h.pid=u,h.pid_start=R,y=` \xB7 pid ${u} (start ${R})`):y=` \xB7 pid ${u} unreadable \u2014 TTL fallback`}const w=Number(o("ttl")),$=p.announce({agent_id:c,agent_kind:o("kind")??"cli",project_id:g?.id??null,current_quest_id:o("quest")?Number(o("quest")):null,ttl_seconds:Number.isFinite(w)&&w>0?w:h.pid?86400:300,metadata:Object.keys(h).length?h:void 0,role:o("role")??null});process.stdout.write(`presence:${$.id} ${c}${y}
|
|
55
55
|
`);return}if(r==="list"||r==="ls"||r===void 0){const c=i.getDatabase().prepare("SELECT * FROM agent_presence ORDER BY last_heartbeat DESC").all();if(c.length===0){process.stdout.write(`No agents on the board.
|
package/dist/wyrm-manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wyrm-mcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.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, live memory streams, run-attributed fleet memory — a structured SQLite memory on your machine, no cloud or LLM required. Claude / Copilot / Cursor / Windsurf / Codex.",
|
|
6
6
|
"type": "module",
|