wyrm-mcp 8.5.7 → 8.6.0

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.
@@ -1,4 +1,4 @@
1
- import{applyBudget as w,resolveBudget as v}from"./token-budget.js";import{autoSummaryPenalty as T,score as p}from"./context-ranking.js";function E(g){const{groundTruths:y,scaffoldLib:h,memory:b,toolAnalytics:$,sessionSeen:u,tokenEstimator:d,rankWeights:f}=g;return function(t){const o=v({callArg:t.maxTokens,envValue:process.env.WYRM_CONTEXT_TOKEN_BUDGET,clientName:null}),x=t.sessionId?u().getSeen(t.sessionId):new Set,a=y.formatForContext(t.project.id),r=d.count(a??"");let m=a??"",k=r;r>o*.5&&!t.strictBudget&&process.stderr.write(`[wyrm_context_build] ground truths consume ${r} of ${o}-token budget \u2014 body will be heavily elided. Pass strict_budget:true to elide truths too.
2
- `),t.strictBudget&&r>o*.5&&(m=(a??"").slice(0,o*2),k=d.count(m));const l=[],c=h.findBest(t.task,t.project.id);if(c){const e=h.formatForContext(c),s=c.scaffold.id;l.push({item:{kind:"scaffold",id:s,title:c.scaffold.problem_type,body:e},key:`scaffold:${s}`,inlineCost:d.count(e),stubCost:20,score:p({confidence:.9,relevance:.9,updatedAt:new Date().toISOString()},f)})}const B=b.recall(t.project.id,t.task,{limit:20,minConfidence:t.minConfidence??.2});for(const e of B){const s=e.artifact;if(t.kinds&&t.kinds.length>0&&!t.kinds.includes(s.kind))continue;const _=[`**${s.kind.toUpperCase()}** \xB7 ${s.problem}`,s.constraints?`Constraints: ${s.constraints}`:"",s.validated_fix?`Fix: ${s.validated_fix}`:"",s.why_it_worked?`Why: ${s.why_it_worked}`:""].filter(Boolean).join(`
3
- `);l.push({item:{kind:"memory",id:s.id,title:s.problem.slice(0,60),body:_},key:`memory:${s.id}`,inlineCost:d.count(_),stubCost:25,score:p({confidence:s.confidence,relevance:e.relevance_score,updatedAt:s.updated_at,sourcePenalty:T(s.problem)},f)})}const i=w(l,{budget:o,alreadySeen:x,reserved:t.strictBudget?0:k});t.sessionId&&(u().markBulk(t.sessionId,i.inline.map(e=>({id:e.id,kind:e.kind,mode:"inline"}))),u().markBulk(t.sessionId,i.elided.map(e=>({id:e.item.id,kind:e.item.kind,mode:"stub"}))));const n=[];n.push(`\u{F115D} **Context Brief** \u2014 "${t.task}"`),n.push(""),n.push("## Ground truths (stable preamble)"),n.push(""),n.push(m||"_no ground truths set for this project yet_"),n.push(""),n.push("## Task-relevant memory"),n.push("");for(const e of i.inline)n.push(`### [${e.kind}:${e.id}] ${e.title}`),n.push(e.body),n.push("");if(i.elided.length>0){n.push("## Elided to stubs"),n.push(""),n.push("_Below the budget cutoff or already seen this session. Recall with `wyrm_recall(id)`:_"),n.push("");for(const e of i.elided){const s=e.reason==="seen"?"shown earlier in session":`~${e.stubCost} tokens`;n.push(`- [${e.item.kind}:${e.item.id}] ${e.item.title} \xB7 ${s}`)}n.push("")}n.push("---"),n.push(`_Budget: ${i.tokensInline}/${o} tokens inline \xB7 ${i.elided.length} stub${i.elided.length===1?"":"s"} \xB7 estimator: ${d.source}_`);const C=n.join(`
4
- `);try{$.log({tool_name:"wyrm_context_build",project_id:t.project.id,args:{budget:o,items_total:l.length,items_inline:i.inline.length,items_elided:i.elided.length,tokens_inline:i.tokensInline,tokens_stubs:i.tokensStubs},success:!0,latency_ms:0})}catch{}return{content:[{type:"text",text:C}]}}}export{E as makeRunBudgetedContextBuild};
1
+ import{applyBudget as I,resolveBudget as S}from"./token-budget.js";import{autoSummaryPenalty as j,score as g}from"./context-ranking.js";function F(y){const{groundTruths:b,scaffoldLib:f,memory:$,toolAnalytics:x,sessionSeen:a,tokenEstimator:d,rankWeights:k,threadText:B}=y;return function(t){const o=S({callArg:t.maxTokens,envValue:process.env.WYRM_CONTEXT_TOKEN_BUDGET,clientName:null}),C=t.sessionId?a().getSeen(t.sessionId):new Set,r=(()=>{try{return B(t.project.id)}catch{return""}})(),w=r?d.count(r):0,h=b.formatForContext(t.project.id),l=d.count(h??"");let m=h??"",p=l;l>o*.5&&!t.strictBudget&&process.stderr.write(`[wyrm_context_build] ground truths consume ${l} of ${o}-token budget \u2014 body will be heavily elided. Pass strict_budget:true to elide truths too.
2
+ `),t.strictBudget&&l>o*.5&&(m=(h??"").slice(0,o*2),p=d.count(m));const u=[],c=f.findBest(t.task,t.project.id);if(c){const n=f.formatForContext(c),s=c.scaffold.id;u.push({item:{kind:"scaffold",id:s,title:c.scaffold.problem_type,body:n},key:`scaffold:${s}`,inlineCost:d.count(n),stubCost:20,score:g({confidence:.9,relevance:.9,updatedAt:new Date().toISOString()},k)})}const T=$.recall(t.project.id,t.task,{limit:20,minConfidence:t.minConfidence??.2,runId:t.runId??null});for(const n of T){const s=n.artifact;if(t.kinds&&t.kinds.length>0&&!t.kinds.includes(s.kind))continue;const _=[`**${s.kind.toUpperCase()}** \xB7 ${s.problem}`,s.constraints?`Constraints: ${s.constraints}`:"",s.validated_fix?`Fix: ${s.validated_fix}`:"",s.why_it_worked?`Why: ${s.why_it_worked}`:""].filter(Boolean).join(`
3
+ `);u.push({item:{kind:"memory",id:s.id,title:s.problem.slice(0,60),body:_},key:`memory:${s.id}`,inlineCost:d.count(_),stubCost:25,score:g({confidence:s.confidence,relevance:n.relevance_score,updatedAt:s.updated_at,sourcePenalty:j(s.problem)},k)})}const i=I(u,{budget:o,alreadySeen:C,reserved:(t.strictBudget?0:p)+w});t.sessionId&&(a().markBulk(t.sessionId,i.inline.map(n=>({id:n.id,kind:n.kind,mode:"inline"}))),a().markBulk(t.sessionId,i.elided.map(n=>({id:n.item.id,kind:n.item.kind,mode:"stub"}))));const e=[];e.push(`\u{F115D} **Context Brief** \u2014 "${t.task}"`),e.push(""),r&&(e.push("## Working thread"),e.push(""),e.push(r),e.push("")),e.push("## Ground truths (stable preamble)"),e.push(""),e.push(m||"_no ground truths set for this project yet_"),e.push(""),e.push("## Task-relevant memory"),e.push("");for(const n of i.inline)e.push(`### [${n.kind}:${n.id}] ${n.title}`),e.push(n.body),e.push("");if(i.elided.length>0){e.push("## Elided to stubs"),e.push(""),e.push("_Below the budget cutoff or already seen this session. Recall with `wyrm_recall(id)`:_"),e.push("");for(const n of i.elided){const s=n.reason==="seen"?"shown earlier in session":`~${n.stubCost} tokens`;e.push(`- [${n.item.kind}:${n.item.id}] ${n.item.title} \xB7 ${s}`)}e.push("")}e.push("---"),e.push(`_Budget: ${i.tokensInline}/${o} tokens inline \xB7 ${i.elided.length} stub${i.elided.length===1?"":"s"} \xB7 estimator: ${d.source}_`);const v=e.join(`
4
+ `);try{x.log({tool_name:"wyrm_context_build",project_id:t.project.id,args:{budget:o,items_total:u.length,items_inline:i.inline.length,items_elided:i.elided.length,tokens_inline:i.tokensInline,tokens_stubs:i.tokensStubs},success:!0,latency_ms:0})}catch{}return{content:[{type:"text",text:v}]}}}export{F as makeRunBudgetedContextBuild};
package/dist/cors.js ADDED
@@ -0,0 +1 @@
1
+ const t={allowedOrigins:["http://localhost:3333","http://127.0.0.1:3333","http://localhost:3000"]};function i(l){t.allowedOrigins.includes(l)||t.allowedOrigins.push(l)}function o(){return t.allowedOrigins}export{t as CORS_CONFIG,i as addOrigin,o as getAllowedOrigins};
@@ -1,21 +1,21 @@
1
- import{readFileSync as L,statSync as m}from"node:fs";import{isAbsolute as j,relative as D,resolve as b,sep as A}from"node:path";import{sanitizeFtsQuery as M}from"./security.js";import{WyrmCrypto as w}from"./crypto.js";import{emitEvent as O,isLiveMemoryEnabled as U}from"./events.js";import{getActor as S,hasExplicitAttribution as k}from"./handlers/boundary.js";import{readActor as H,resolveAttribution as W}from"./attribution.js";import{normalizeContentSignature as I,containsFailedSignature as F}from"./content-signature.js";const $=new Set(["a","an","the","this","that","these","those","and","or","but","if","then","than","so","to","of","in","on","at","by","for","from","with","without","no","not","as","is","are","was","were","be","been","being","will","would","can","could","should","it","its","i","we","you","my","our","your","again","just","now","please","let","lets","do","does","did","into","over","about"]),C={run:0,project:1,global:2},B=8,Z="source changed since this failure was recorded \u2014 re-verify",v=200,q=5;function K(c){const e=n=>Object.entries(n).filter(([,r])=>r>0).map(([r,i])=>`${r} ${i}`).join(" \xB7 ")||"none",t=n=>n.map(r=>`${"who"in r?r.who:r.run_id} \xD7${r.count}`).join(" \xB7 ")||"none",o=c.blocked.this_run.run_id===null?"- This run: (no run identity \u2014 export WYRM_RUN_ID or pass run_id)":`- This run (${c.blocked.this_run.run_id}): ${c.blocked.this_run.blocked} repeat(s) blocked`;return`\u{F115D} **Failure Analytics** (${c.project_id===null?"all projects":`project #${c.project_id}`})
1
+ import{readFileSync as A,statSync as j}from"node:fs";import{isAbsolute as U,relative as k,resolve as b,sep as C}from"node:path";import{sanitizeFtsQuery as W}from"./security.js";import{WyrmCrypto as H}from"./crypto.js";import{emitEvent as O,isLiveMemoryEnabled as F}from"./events.js";import{getActor as R,hasExplicitAttribution as $}from"./handlers/boundary.js";import{readActor as B,resolveAttribution as v}from"./attribution.js";import{normalizeContentSignature as D,containsFailedSignature as q}from"./content-signature.js";const x=new Set(["a","an","the","this","that","these","those","and","or","but","if","then","than","so","to","of","in","on","at","by","for","from","with","without","no","not","as","is","are","was","were","be","been","being","will","would","can","could","should","it","its","i","we","you","my","our","your","again","just","now","please","let","lets","do","does","did","into","over","about"]),y={run:0,project:1,global:2},Y=8,ee="source changed since this failure was recorded \u2014 re-verify",N=200,T=5;function te(s){const e=r=>Object.entries(r).filter(([,n])=>n>0).map(([n,i])=>`${n} ${i}`).join(" \xB7 ")||"none",t=r=>r.map(n=>`${"who"in n?n.who:n.run_id} \xD7${n.count}`).join(" \xB7 ")||"none",o=s.blocked.this_run.run_id===null?"- This run: (no run identity \u2014 export WYRM_RUN_ID or pass run_id)":`- This run (${s.blocked.this_run.run_id}): ${s.blocked.this_run.blocked} repeat(s) blocked`;return`\u{F115D} **Failure Analytics** (${s.project_id===null?"all projects":`project #${s.project_id}`})
2
2
 
3
- **Recorded:** ${c.recorded.total} failure(s), ${c.recorded.unresolved} unresolved
4
- - By quarantine: ${e(c.recorded.by_quarantine_scope)}
5
- - By scope: ${e(c.recorded.by_scope)}
6
- - By agent: ${t(c.recorded.by_agent)}
7
- - By run: ${t(c.recorded.by_run)}
3
+ **Recorded:** ${s.recorded.total} failure(s), ${s.recorded.unresolved} unresolved
4
+ - By quarantine: ${e(s.recorded.by_quarantine_scope)}
5
+ - By scope: ${e(s.recorded.by_scope)}
6
+ - By agent: ${t(s.recorded.by_agent)}
7
+ - By run: ${t(s.recorded.by_run)}
8
8
 
9
- **Confirmations:** ${c.confirmations.total} from ${c.confirmations.distinct_agents} distinct agent(s)
9
+ **Confirmations:** ${s.confirmations.total} from ${s.confirmations.distinct_agents} distinct agent(s)
10
10
 
11
- **Repeats blocked:** ${c.blocked.total} total
11
+ **Repeats blocked:** ${s.blocked.total} total
12
12
  ${o}
13
- - By agent: ${t(c.blocked.by_agent)}
14
- - By run: ${t(c.blocked.by_run)}
15
- - Top blockers: ${c.blocked.top_blocked.map(n=>`#${n.failure_id} ${n.scope}:${n.target} \xD7${n.blocks}`).join(" \xB7 ")||"none"}`}function x(c,e){if(c==="exact")return 1;if(c==="target")return .95;const t=Math.max(0,-(e??0));return Number((.05+.85*(t/(t+2))).toFixed(4))}function N(c){return c.toLowerCase().replace(/\s+/g," ").trim()}function y(c){return N(c).slice(0,200)}class g{db;constructor(e){this.db=e}static signature(e,t,o){return`${e}:${y(t)}:${y(o).slice(0,80)}`}record(e){const t=g.signature(e.scope,e.target,e.description),o=e.project_id??null,n=e.content&&I(e.content)||null,r=S(),a=this.db.transaction(()=>{const s=this.db.prepare(`
13
+ - By agent: ${t(s.blocked.by_agent)}
14
+ - By run: ${t(s.blocked.by_run)}
15
+ - Top blockers: ${s.blocked.top_blocked.map(r=>`#${r.failure_id} ${r.scope}:${r.target} \xD7${r.blocks}`).join(" \xB7 ")||"none"}`}function z(s,e){if(s==="exact")return 1;if(s==="target")return .95;if(s==="canonical")return .9;if(s==="related")return .4;const t=Math.max(0,-(e??0));return Number((.05+.85*(t/(t+2))).toFixed(4))}function g(s){return s.toLowerCase().replace(/\s+/g," ").trim()}function M(s){return g(s).slice(0,200)}function L(s){const e=g(s).split(" ").filter(Boolean);let t=0;const o=[];for(;t<e.length&&!e[t].startsWith("-");)o.push(e[t]),t++;const r=[],n=[];for(;t<e.length;t++){const i=e[t];i.startsWith("-")?!i.includes("=")&&t+1<e.length&&!e[t+1].startsWith("-")?(n.push(`${i}=${e[t+1]}`),t++):n.push(i):r.push(i)}return n.sort(),[...o,...r,...n].join(" ")}function w(s){const e=g(s).split(" ").filter(Boolean),t=[];for(const o of e){if(o.startsWith("-"))break;t.push(o)}return t.length>=2?t.join(" "):""}class m{db;constructor(e){this.db=e}static signature(e,t,o){return`${e}:${M(t)}:${M(o).slice(0,80)}`}record(e){const t=m.signature(e.scope,e.target,e.description),o=e.project_id??null,r=e.content&&D(e.content)||null,n=e.scope==="command"&&L(e.target)||null,i=e.scope==="command"&&w(e.target)||null,a=R(),d=this.db.transaction(()=>{const u=this.db.prepare(`
16
16
  SELECT * FROM failure_patterns
17
17
  WHERE signature = ? AND (project_id IS ? OR project_id = ?)
18
- `).get(t,o,o);if(s)return this.db.prepare(`
18
+ `).get(t,o,o);if(u)return this.db.prepare(`
19
19
  UPDATE failure_patterns
20
20
  SET occurrences = occurrences + 1,
21
21
  last_seen = datetime('now'),
@@ -24,29 +24,29 @@ ${o}
24
24
  content_sig = COALESCE(?, content_sig),
25
25
  resolved = 0
26
26
  WHERE id = ?
27
- `).run(e.why_failed??null,e.severity??s.severity,n,s.id),this.noteConfirmation(s.id,r),this.get(s.id);const l=e.quarantine_scope??(r.run_id!==null?"run":o===null?"global":"project"),p=this.db.prepare(`
27
+ `).run(e.why_failed??null,e.severity??u.severity,r,u.id),this.noteConfirmation(u.id,a),this.get(u.id);const l=e.quarantine_scope??(a.run_id!==null?"run":o===null?"global":"project"),_=this.db.prepare(`
28
28
  INSERT INTO failure_patterns
29
- (project_id, signature, scope, target, description, why_failed, severity, agent_id, run_id, quarantine_scope, content_sig)
30
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
31
- `).run(o,t,e.scope,e.target,e.description,e.why_failed??null,e.severity??"medium",r.agent_id,r.run_id,l,n),u=this.get(p.lastInsertRowid);return this.noteConfirmation(u.id,r),u}).immediate();return O(this.db,{projectId:a.project_id??0,kind:"failure",refTable:"failure_patterns",refId:a.id}),a}contentMatch(e,t,o){const n=this.db.prepare(`
29
+ (project_id, signature, scope, target, description, why_failed, severity, agent_id, run_id, quarantine_scope, content_sig, canonical_target, command_head)
30
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
31
+ `).run(o,t,e.scope,e.target,e.description,e.why_failed??null,e.severity??"medium",a.agent_id,a.run_id,l,r,n,i),p=this.get(_.lastInsertRowid);return this.noteConfirmation(p.id,a),p}).immediate();return O(this.db,{projectId:d.project_id??0,kind:"failure",refTable:"failure_patterns",refId:d.id}),d}contentMatch(e,t,o){const r=this.db.prepare(`
32
32
  SELECT * FROM failure_patterns
33
33
  WHERE content_sig IS NOT NULL AND scope = ? AND resolved = 0
34
34
  AND (project_id IS ? OR project_id = ?)
35
35
  ORDER BY occurrences DESC, last_seen DESC
36
- `).all(t,o,o);for(const r of n)if(r.content_sig&&F(e,r.content_sig))return r;return null}get(e){return this.db.prepare("SELECT * FROM failure_patterns WHERE id = ?").get(e)??null}static anchorSha(e){return w.hash(I(e))}recordAnchors(e,t,o,n=!0){try{const r=b(t),i=new Set(this.db.prepare("SELECT DISTINCT rel_path FROM failure_anchors WHERE failure_id = ?").all(e).map(_=>_.rel_path));let a=B-i.size;const s=this.db.prepare("DELETE FROM failure_anchors WHERE failure_id = ? AND rel_path = ?"),l=this.db.prepare(`
36
+ `).all(t,o,o);for(const n of r)if(n.content_sig&&q(e,n.content_sig))return n;return null}get(e){return this.db.prepare("SELECT * FROM failure_patterns WHERE id = ?").get(e)??null}static anchorSha(e){return H.hash(D(e))}recordAnchors(e,t,o,r=!0){try{const n=b(t),i=new Set(this.db.prepare("SELECT DISTINCT rel_path FROM failure_anchors WHERE failure_id = ?").all(e).map(_=>_.rel_path));let a=Y-i.size;const c=this.db.prepare("DELETE FROM failure_anchors WHERE failure_id = ? AND rel_path = ?"),d=this.db.prepare(`
37
37
  INSERT INTO failure_anchors (failure_id, rel_path, sha, size, mtime_ns)
38
38
  VALUES (?, ?, ?, ?, ?)
39
- `),p=new Set;let u=0;for(const _ of o){if(typeof _!="string"||_.length===0)continue;const f=j(_)?b(_):b(r,_);if(!f.startsWith(r+A)||p.has(f))continue;p.add(f);const h=D(r,f),R=i.has(h);if(!(!R&&(!n||a<=0)))try{const d=m(f,{bigint:!0});if(!d.isFile())continue;const E=g.anchorSha(L(f,"utf-8"));s.run(e,h),l.run(e,h,E,d.size,d.mtimeNs),u++,R||a--}catch{}}return u}catch{return 0}}getAnchors(e){try{const t=this.db.prepare("SELECT rel_path, sha, size, mtime_ns, recorded_at FROM failure_anchors WHERE failure_id = ?");return t.safeIntegers(!0),t.all(e)}catch{return[]}}anchorFreshness(e,t){try{if(!t)return"unverifiable";const o=this.getAnchors(e);if(o.length===0)return"unanchored";const n=b(t);let r=0;for(const i of o)try{const a=b(n,i.rel_path);if(!a.startsWith(n+A))continue;const s=m(a,{bigint:!0});if(!s.isFile())continue;if(s.size===i.size&&s.mtimeNs===i.mtime_ns){r++;continue}if(g.anchorSha(L(a,"utf-8"))===i.sha){r++;continue}return"stale"}catch{}return r>0?"fresh":"unverifiable"}catch{return"unverifiable"}}staleAnchorIds(e,t){const o=new Set,n=new Map;for(const r of e)try{if(r.match==="exact"||r.scope!=="file"&&r.scope!=="symbol"&&r.scope!=="edit")continue;let i=n.get(r.id);i===void 0&&(i=t?this.anchorFreshness(r.id,t):this.getAnchors(r.id).length===0?"unanchored":"unverifiable",n.set(r.id,i)),(i==="unanchored"||i==="stale")&&o.add(r.id)}catch{}return o}noteConfirmation(e,t){if(t.agent_id===null)return;this.db.prepare(`
39
+ `),u=new Set;let l=0;for(const _ of o){if(typeof _!="string"||_.length===0)continue;const p=U(_)?b(_):b(n,_);if(!p.startsWith(n+C)||u.has(p))continue;u.add(p);const h=k(n,p),S=i.has(h);if(!(!S&&(!r||a<=0)))try{const f=j(p,{bigint:!0});if(!f.isFile())continue;const E=m.anchorSha(A(p,"utf-8"));c.run(e,h),d.run(e,h,E,f.size,f.mtimeNs),l++,S||a--}catch{}}return l}catch{return 0}}getAnchors(e){try{const t=this.db.prepare("SELECT rel_path, sha, size, mtime_ns, recorded_at FROM failure_anchors WHERE failure_id = ?");return t.safeIntegers(!0),t.all(e)}catch{return[]}}anchorFreshness(e,t){try{if(!t)return"unverifiable";const o=this.getAnchors(e);if(o.length===0)return"unanchored";const r=b(t);let n=0;for(const i of o)try{const a=b(r,i.rel_path);if(!a.startsWith(r+C))continue;const c=j(a,{bigint:!0});if(!c.isFile())continue;if(c.size===i.size&&c.mtimeNs===i.mtime_ns){n++;continue}if(m.anchorSha(A(a,"utf-8"))===i.sha){n++;continue}return"stale"}catch{}return n>0?"fresh":"unverifiable"}catch{return"unverifiable"}}staleAnchorIds(e,t){const o=new Set,r=new Map;for(const n of e)try{if(n.match==="exact"||n.scope!=="file"&&n.scope!=="symbol"&&n.scope!=="edit")continue;let i=r.get(n.id);i===void 0&&(i=t?this.anchorFreshness(n.id,t):this.getAnchors(n.id).length===0?"unanchored":"unverifiable",r.set(n.id,i)),(i==="unanchored"||i==="stale")&&o.add(n.id)}catch{}return o}noteConfirmation(e,t){if(t.agent_id===null)return;this.db.prepare(`
40
40
  INSERT OR IGNORE INTO failure_confirmations (failure_id, agent_id, run_id)
41
41
  VALUES (?, ?, ?)
42
- `).run(e,t.agent_id,t.run_id);const o=this.get(e);if(!o||o.quarantine_scope!=="run")return;const{n}=this.db.prepare("SELECT COUNT(*) AS n FROM failure_confirmations WHERE failure_id = ?").get(e);n>=2&&this.applyPromotion(e,"project")}applyPromotion(e,t){const o=this.get(e);if(!o)return!1;const n=t==="project"&&o.project_id===null?"global":t;return C[n]<=C[o.quarantine_scope]?!1:(this.db.prepare("UPDATE failure_patterns SET quarantine_scope = ? WHERE id = ?").run(n,e),O(this.db,{projectId:o.project_id??0,kind:"failure",refTable:"failure_patterns",refId:e}),!0)}promote(e,t){if(!k(S()))return{row:this.get(e),authorized:!1,changed:!1};const o=this.applyPromotion(e,t);return{row:this.get(e),authorized:!0,changed:o}}sweepRunQuarantine(e){const t=Math.max(1,Math.floor(e?.runInactiveHours??24)),o=`-${t} hours`,n=Date.now()-t*36e5,r=U(),i=this.db.transaction(()=>{const a=this.db.prepare(`
42
+ `).run(e,t.agent_id,t.run_id);const o=this.get(e);if(!o||o.quarantine_scope!=="run")return;const{n:r}=this.db.prepare("SELECT COUNT(*) AS n FROM failure_confirmations WHERE failure_id = ?").get(e);r>=2&&this.applyPromotion(e,"project")}applyPromotion(e,t){const o=this.get(e);if(!o)return!1;const r=t==="project"&&o.project_id===null?"global":t;return y[r]<=y[o.quarantine_scope]?!1:(this.db.prepare("UPDATE failure_patterns SET quarantine_scope = ? WHERE id = ?").run(r,e),O(this.db,{projectId:o.project_id??0,kind:"failure",refTable:"failure_patterns",refId:e}),!0)}promote(e,t){if(!$(R()))return{row:this.get(e),authorized:!1,changed:!1};const o=this.applyPromotion(e,t);return{row:this.get(e),authorized:!0,changed:o}}sweepRunQuarantine(e){const t=Math.max(1,Math.floor(e?.runInactiveHours??24)),o=`-${t} hours`,r=Date.now()-t*36e5,n=F(),i=this.db.transaction(()=>{const a=this.db.prepare(`
43
43
  UPDATE failure_patterns
44
44
  SET resolved = 1,
45
45
  resolution_note = COALESCE(resolution_note || ' \xB7 ', '')
46
46
  || 'auto-expired by run-quarantine sweep: run ' || run_id || ' was abandoned'
47
47
  WHERE resolved = 0 AND quarantine_scope = 'run' AND run_id IS NOT NULL
48
48
  AND run_id IN (SELECT run_id FROM runs WHERE status = 'abandoned')
49
- `).run().changes,s=this.db.prepare(`
49
+ `).run().changes,c=this.db.prepare(`
50
50
  SELECT fp.id FROM failure_patterns fp
51
51
  WHERE fp.resolved = 0 AND fp.quarantine_scope = 'run' AND fp.run_id IS NOT NULL
52
52
  AND (
@@ -72,18 +72,18 @@ ${o}
72
72
  )
73
73
  )
74
74
  )
75
- `).all({cut:o,cutMs:n,ttl:r?1:0}).map(u=>u.id),l=this.db.prepare(`
75
+ `).all({cut:o,cutMs:r,ttl:n?1:0}).map(l=>l.id),d=this.db.prepare(`
76
76
  UPDATE failure_patterns
77
77
  SET quarantine_scope = CASE WHEN project_id IS NULL THEN 'global' ELSE 'project' END
78
78
  WHERE id = ?
79
- `);for(const u of s)l.run(u);const p=r?this.db.prepare(`
79
+ `);for(const l of c)d.run(l);const u=n?this.db.prepare(`
80
80
  UPDATE runs SET status = 'abandoned', updated_at = datetime('now')
81
81
  WHERE status = 'running' AND updated_at < datetime('now', @cut)
82
82
  AND NOT EXISTS (
83
83
  SELECT 1 FROM events e
84
84
  WHERE e.run_id = runs.run_id AND e.created_at >= @cutMs
85
85
  )
86
- `).run({cut:o,cutMs:n}).changes:0;return{promotedIds:s,expired:a,abandoned:p}})();for(const a of i.promotedIds){const s=this.get(a);O(this.db,{projectId:s?.project_id??0,kind:"failure",refTable:"failure_patterns",refId:a,agentId:null,runId:null})}return{promoted:i.promotedIds.length,expired:i.expired,runs_abandoned:i.abandoned,...r?{}:{degraded:"live memory off (WYRM_LIVE_MEMORY) \u2014 run-tagged events do not exist, so the run-inactivity TTL paths were skipped; only explicit run verdicts acted (completed/failed promote, abandoned expires)"}}}check(e,t,o,n,r){return this.query(e,t,o,n??null,r).map(({_match:i,_rank:a,...s})=>s)}checkVerdict(e,t,o,n,r){const a=this.query(e,t,o,n??null,r).map(s=>this.toVerdictMatch(s,s._match,s._rank));return{blocked:a.length>0,matches:a,recorded_by_agent:a[0]?.recorded_by_agent??null,run_id:a[0]?.run_id??null,confidence:a.reduce((s,l)=>Math.max(s,l.confidence),0)}}toVerdictMatch(e,t,o=null){const n=W(e);return{id:e.id,pattern:e.signature,scope:e.scope,quarantine_scope:e.quarantine_scope,target:e.target,description:e.description,why_failed:e.why_failed,severity:e.severity,occurrences:e.occurrences,last_seen:e.last_seen,recorded_by_agent:n.actor,run_id:n.run_id,match:t,confidence:x(t,o)}}targetIdentityMatches(e,t,o,n){const r=N(t),i=r.slice(0,200);if(i.length===0)return[];const a=n?.callerRunId!==void 0?n.callerRunId:S().run_id,s=`${e}:${i}:`,l=`${e}:${i};`;return this.db.prepare(`
86
+ `).run({cut:o,cutMs:r}).changes:0;return{promotedIds:c,expired:a,abandoned:u}})();for(const a of i.promotedIds){const c=this.get(a);O(this.db,{projectId:c?.project_id??0,kind:"failure",refTable:"failure_patterns",refId:a,agentId:null,runId:null})}return{promoted:i.promotedIds.length,expired:i.expired,runs_abandoned:i.abandoned,...n?{}:{degraded:"live memory off (WYRM_LIVE_MEMORY) \u2014 run-tagged events do not exist, so the run-inactivity TTL paths were skipped; only explicit run verdicts acted (completed/failed promote, abandoned expires)"}}}check(e,t,o,r,n){return this.query(e,t,o,r??null,n).map(({_match:i,_rank:a,...c})=>c)}checkVerdict(e,t,o,r,n){const a=this.query(e,t,o,r??null,n).map(c=>this.toVerdictMatch(c,c._match,c._rank));return{blocked:a.length>0,matches:a,recorded_by_agent:a[0]?.recorded_by_agent??null,run_id:a[0]?.run_id??null,confidence:a.reduce((c,d)=>Math.max(c,d.confidence),0)}}toVerdictMatch(e,t,o=null){const r=v(e);return{id:e.id,pattern:e.signature,scope:e.scope,quarantine_scope:e.quarantine_scope,target:e.target,description:e.description,why_failed:e.why_failed,severity:e.severity,occurrences:e.occurrences,last_seen:e.last_seen,recorded_by_agent:r.actor,run_id:r.run_id,match:t,confidence:z(t,o)}}targetIdentityMatches(e,t,o,r){const n=g(t),i=n.slice(0,200);if(i.length===0)return[];const a=r?.callerRunId!==void 0?r.callerRunId:R().run_id,c=`${e}:${i}:`,d=`${e}:${i};`;return this.db.prepare(`
87
87
  SELECT * FROM failure_patterns
88
88
  WHERE resolved = 0
89
89
  AND signature >= @lo AND signature < @hi
@@ -91,51 +91,65 @@ ${o}
91
91
  AND (quarantine_scope <> 'run' OR run_id = @run)
92
92
  ORDER BY occurrences DESC, last_seen DESC
93
93
  LIMIT @cap
94
- `).all({lo:s,hi:l,project:o??null,run:a,cap:v}).filter(u=>N(u.target)===r).slice(0,q)}recordBlock(e,t){if(!(!e.blocked||e.matches.length===0))try{const o=S(),n=e.matches.find(r=>!r.stale_anchor)??e.matches[0];this.db.prepare(`
94
+ `).all({lo:c,hi:d,project:o??null,run:a,cap:N}).filter(l=>g(l.target)===n).slice(0,T)}canonicalMatches(e,t,o,r){if(e!=="command")return[];const n=L(t);if(n.length===0)return[];const i=r?.callerRunId!==void 0?r.callerRunId:R().run_id;return this.db.prepare(`
95
+ SELECT * FROM failure_patterns
96
+ WHERE resolved = 0 AND scope = 'command' AND canonical_target = @canon
97
+ AND (project_id IS @project OR project_id = @project OR project_id IS NULL)
98
+ AND (quarantine_scope <> 'run' OR run_id = @run)
99
+ ORDER BY occurrences DESC, last_seen DESC
100
+ LIMIT @cap
101
+ `).all({canon:n,project:o??null,run:i,cap:N}).filter(c=>L(c.target)===n).slice(0,T)}commandHeadFamily(e,t,o,r){if(e!=="command")return[];const n=w(t);if(n.length===0)return[];const i=r?.callerRunId!==void 0?r.callerRunId:R().run_id;return this.db.prepare(`
102
+ SELECT * FROM failure_patterns
103
+ WHERE resolved = 0 AND scope = 'command' AND command_head = @head
104
+ AND (project_id IS @project OR project_id = @project OR project_id IS NULL)
105
+ AND (quarantine_scope <> 'run' OR run_id = @run)
106
+ ORDER BY occurrences DESC, last_seen DESC
107
+ LIMIT @cap
108
+ `).all({head:n,project:o??null,run:i,cap:N}).slice(0,T)}recordBlock(e,t){if(!(!e.blocked||e.matches.length===0))try{const o=R(),r=e.matches.find(n=>!n.stale_anchor)??e.matches[0];this.db.prepare(`
95
109
  INSERT INTO failure_blocks (failure_id, project_id, agent_id, run_id)
96
110
  VALUES (?, ?, ?, ?)
97
- `).run(n.id,t??null,o.agent_id,o.run_id)}catch{}}pruneBlocks(e){const t=Math.max(1,Math.floor(e));try{return this.db.prepare("DELETE FROM failure_blocks WHERE blocked_at < datetime('now', @cut)").run({cut:`-${t} days`}).changes}catch{return 0}}failureStats(e){const t=e?.projectId??null,o=e?.callerRunId!==void 0?e.callerRunId:S().run_id,n={project:t},r=this.db.prepare(`
111
+ `).run(r.id,t??null,o.agent_id,o.run_id)}catch{}}pruneBlocks(e){const t=Math.max(1,Math.floor(e));try{return this.db.prepare("DELETE FROM failure_blocks WHERE blocked_at < datetime('now', @cut)").run({cut:`-${t} days`}).changes}catch{return 0}}failureStats(e){const t=e?.projectId??null,o=e?.callerRunId!==void 0?e.callerRunId:R().run_id,r={project:t},n=this.db.prepare(`
98
112
  SELECT COUNT(*) AS total, COALESCE(SUM(resolved = 0), 0) AS unresolved
99
113
  FROM failure_patterns WHERE (@project IS NULL OR project_id = @project)
100
- `).get(n),i={run:0,project:0,global:0};for(const E of this.db.prepare(`
114
+ `).get(r),i={run:0,project:0,global:0};for(const E of this.db.prepare(`
101
115
  SELECT quarantine_scope AS k, COUNT(*) AS n FROM failure_patterns
102
116
  WHERE (@project IS NULL OR project_id = @project) GROUP BY quarantine_scope
103
- `).all(n))i[E.k]=E.n;const a={file:0,symbol:0,command:0,prompt:0,edit:0};for(const E of this.db.prepare(`
117
+ `).all(r))i[E.k]=E.n;const a={file:0,symbol:0,command:0,prompt:0,edit:0};for(const E of this.db.prepare(`
104
118
  SELECT scope AS k, COUNT(*) AS n FROM failure_patterns
105
119
  WHERE (@project IS NULL OR project_id = @project) GROUP BY scope
106
- `).all(n))a[E.k]=E.n;const s=E=>E.map(T=>({who:H(T.agent_id),count:T.count})),l=s(this.db.prepare(`
120
+ `).all(r))a[E.k]=E.n;const c=E=>E.map(I=>({who:B(I.agent_id),count:I.count})),d=c(this.db.prepare(`
107
121
  SELECT agent_id, COUNT(*) AS count FROM failure_patterns
108
122
  WHERE (@project IS NULL OR project_id = @project)
109
123
  GROUP BY agent_id ORDER BY count DESC, agent_id ASC LIMIT 10
110
- `).all(n)),p=this.db.prepare(`
124
+ `).all(r)),u=this.db.prepare(`
111
125
  SELECT run_id, COUNT(*) AS count FROM failure_patterns
112
126
  WHERE run_id IS NOT NULL AND (@project IS NULL OR project_id = @project)
113
127
  GROUP BY run_id ORDER BY count DESC, run_id ASC LIMIT 10
114
- `).all(n),u=s(this.db.prepare(`
128
+ `).all(r),l=c(this.db.prepare(`
115
129
  SELECT agent_id, COUNT(*) AS count FROM failure_blocks
116
130
  WHERE (@project IS NULL OR project_id = @project)
117
131
  GROUP BY agent_id ORDER BY count DESC, agent_id ASC LIMIT 10
118
- `).all(n)),_=this.db.prepare(`
132
+ `).all(r)),_=this.db.prepare(`
119
133
  SELECT run_id, COUNT(*) AS count FROM failure_blocks
120
134
  WHERE run_id IS NOT NULL AND (@project IS NULL OR project_id = @project)
121
135
  GROUP BY run_id ORDER BY count DESC, run_id ASC LIMIT 10
122
- `).all(n),f=this.db.prepare(`
136
+ `).all(r),p=this.db.prepare(`
123
137
  SELECT COUNT(*) AS total, COUNT(DISTINCT fc.agent_id) AS distinct_agents
124
138
  FROM failure_confirmations fc
125
139
  JOIN failure_patterns fp ON fp.id = fc.failure_id
126
140
  WHERE (@project IS NULL OR fp.project_id = @project)
127
- `).get(n),h=this.db.prepare(`
141
+ `).get(r),h=this.db.prepare(`
128
142
  SELECT COUNT(*) AS n FROM failure_blocks WHERE (@project IS NULL OR project_id = @project)
129
- `).get(n).n,R=this.db.prepare(`
143
+ `).get(r).n,S=this.db.prepare(`
130
144
  SELECT COUNT(*) AS n FROM failure_blocks
131
145
  WHERE run_id = @run AND (@project IS NULL OR project_id = @project)
132
- `).get({...n,run:o}).n,d=this.db.prepare(`
146
+ `).get({...r,run:o}).n,f=this.db.prepare(`
133
147
  SELECT fb.failure_id, fp.scope, fp.target, COUNT(*) AS blocks
134
148
  FROM failure_blocks fb
135
149
  JOIN failure_patterns fp ON fp.id = fb.failure_id
136
150
  WHERE (@project IS NULL OR fb.project_id = @project)
137
151
  GROUP BY fb.failure_id ORDER BY blocks DESC, fb.failure_id ASC LIMIT 5
138
- `).all(n);return{view:"failures",project_id:t,recorded:{total:r.total,unresolved:r.unresolved,by_quarantine_scope:i,by_scope:a,by_agent:l,by_run:p},confirmations:{total:f.total,distinct_agents:f.distinct_agents},blocked:{total:h,by_agent:u,by_run:_,this_run:{run_id:o??null,blocked:R},top_blocked:d}}}query(e,t,o,n,r){const i=r?.callerRunId!==void 0?r.callerRunId:S().run_id,a=r?.runScope??"any",s={project:n,run:i,tier:a==="any"?null:a},l=g.signature(e,t,o),p=this.db.prepare(`
152
+ `).all(r);return{view:"failures",project_id:t,recorded:{total:n.total,unresolved:n.unresolved,by_quarantine_scope:i,by_scope:a,by_agent:d,by_run:u},confirmations:{total:p.total,distinct_agents:p.distinct_agents},blocked:{total:h,by_agent:l,by_run:_,this_run:{run_id:o??null,blocked:S},top_blocked:f}}}query(e,t,o,r,n){const i=n?.callerRunId!==void 0?n.callerRunId:R().run_id,a=n?.runScope??"any",c={project:r,run:i,tier:a==="any"?null:a},d=m.signature(e,t,o),u=this.db.prepare(`
139
153
  SELECT *, NULL AS _rank FROM failure_patterns
140
154
  WHERE resolved = 0 AND signature = @sig
141
155
  AND (project_id IS @project OR project_id = @project OR project_id IS NULL)
@@ -143,7 +157,7 @@ ${o}
143
157
  AND (@tier IS NULL OR quarantine_scope = @tier)
144
158
  ORDER BY occurrences DESC, last_seen DESC
145
159
  LIMIT 5
146
- `).all({...s,sig:l});if(p.length>0)return p.map(d=>({...d,_match:"exact",_rank:null}));const u=M(`${t} ${o}`.slice(0,100));if(!u)return[];const _=u.split(" ").filter(d=>/[\p{L}\p{N}]/u.test(d)),f=_.filter(d=>!$.has(d.toLowerCase())),h=f.length?f:_;if(h.length===0)return[];const R=h.map(d=>`"${d.replace(/"/g,"")}"`).join(" ");try{return this.db.prepare(`
160
+ `).all({...c,sig:d});if(u.length>0)return u.map(f=>({...f,_match:"exact",_rank:null}));const l=W(`${t} ${o}`.slice(0,100));if(!l)return[];const _=l.split(" ").filter(f=>/[\p{L}\p{N}]/u.test(f)),p=_.filter(f=>!x.has(f.toLowerCase())),h=p.length?p:_;if(h.length===0)return[];const S=h.map(f=>`"${f.replace(/"/g,"")}"`).join(" ");try{return this.db.prepare(`
147
161
  SELECT fp.*, bm25(failure_patterns_fts) AS _rank FROM failure_patterns fp
148
162
  JOIN failure_patterns_fts fts ON fts.rowid = fp.id
149
163
  WHERE failure_patterns_fts MATCH @q
@@ -154,11 +168,11 @@ ${o}
154
168
  AND (@tier IS NULL OR fp.quarantine_scope = @tier)
155
169
  ORDER BY fp.occurrences DESC, fp.last_seen DESC
156
170
  LIMIT 5
157
- `).all({...s,q:R,scope:e}).map(E=>({...E,_match:"fuzzy"}))}catch{return[]}}list(e,t=20){return e==null?this.db.prepare(`SELECT * FROM failure_patterns WHERE resolved = 0
171
+ `).all({...c,q:S,scope:e}).map(E=>({...E,_match:"fuzzy"}))}catch{return[]}}list(e,t=20){return e==null?this.db.prepare(`SELECT * FROM failure_patterns WHERE resolved = 0
158
172
  ORDER BY last_seen DESC LIMIT ?`).all(t):this.db.prepare(`SELECT * FROM failure_patterns
159
173
  WHERE resolved = 0 AND project_id = ?
160
174
  ORDER BY last_seen DESC LIMIT ?`).all(e,t)}resolve(e,t){return this.db.prepare(`
161
175
  UPDATE failure_patterns
162
176
  SET resolved = 1, resolution_note = ?
163
177
  WHERE id = ?
164
- `).run(t??null,e),this.get(e)}delete(e){try{this.db.prepare("DELETE FROM failure_anchors WHERE failure_id = ?").run(e)}catch{}return this.db.prepare("DELETE FROM failure_patterns WHERE id = ?").run(e).changes>0}}export{B as ANCHOR_CAP,g as FailurePatterns,Z as STALE_ANCHOR_FLAG,x as matchConfidence,N as normalizeIdentity,y as normalizeSignal,K as renderFailureStats};
178
+ `).run(t??null,e),this.get(e)}delete(e){try{this.db.prepare("DELETE FROM failure_anchors WHERE failure_id = ?").run(e)}catch{}return this.db.prepare("DELETE FROM failure_patterns WHERE id = ?").run(e).changes>0}}export{Y as ANCHOR_CAP,m as FailurePatterns,ee as STALE_ANCHOR_FLAG,L as canonicalizeCommand,w as commandHead,z as matchConfidence,g as normalizeIdentity,M as normalizeSignal,te as renderFailureStats};
@@ -1 +1 @@
1
- import{CLI_EXILE_TOOLS as y}from"../deprecations.js";import{ALIAS_ROUTE_OVERRIDES as m}from"./alias-adapters.js";const s=["wyrm_activate","wyrm_agent_init","wyrm_agent_restart","wyrm_agent_status","wyrm_agent_stop","wyrm_all_quests","wyrm_analytics_dashboard","wyrm_ask","wyrm_audit_export","wyrm_audit_log","wyrm_audit_verify","wyrm_auto_capture","wyrm_buddy","wyrm_capture_trace","wyrm_check_update","wyrm_cloud_backup","wyrm_cloud_sync","wyrm_constellation","wyrm_cost_report","wyrm_data_batch_insert","wyrm_data_categories","wyrm_data_insert","wyrm_data_query","wyrm_decision_downstream","wyrm_decision_invalidate","wyrm_decision_upstream","wyrm_digest","wyrm_distill","wyrm_embed","wyrm_encrypt_setup","wyrm_entity_add","wyrm_entity_graph","wyrm_entity_link","wyrm_entity_merge","wyrm_entity_path","wyrm_entity_search","wyrm_events_publish","wyrm_events_replicate","wyrm_events_since","wyrm_events_subscribe","wyrm_failure_list","wyrm_failure_resolve","wyrm_feedback","wyrm_global_context","wyrm_goal_abandon","wyrm_goal_complete","wyrm_goal_iterations","wyrm_goal_list","wyrm_goal_pause","wyrm_goal_resume","wyrm_goal_set","wyrm_harvest","wyrm_hours_report","wyrm_import_git","wyrm_import_pr","wyrm_import_rules","wyrm_inject_prompt","wyrm_intro","wyrm_invoice_generate","wyrm_license","wyrm_list_projects","wyrm_mcp_disable","wyrm_mcp_list","wyrm_mcp_register","wyrm_mcp_tools","wyrm_migrate_prompt","wyrm_orchestrate_task","wyrm_orchestration_config","wyrm_orchestration_stats","wyrm_presence_announce","wyrm_presence_list","wyrm_presence_release","wyrm_project_context","wyrm_prune","wyrm_quest_add","wyrm_quest_claim","wyrm_quest_complete","wyrm_quest_release","wyrm_reference_add","wyrm_reference_list","wyrm_reference_search","wyrm_reindex","wyrm_remember","wyrm_scaffold_get","wyrm_scaffold_save","wyrm_scan_projects","wyrm_self_update","wyrm_session_rehydrate","wyrm_session_start","wyrm_session_update","wyrm_set_global","wyrm_setup","wyrm_skill_activate","wyrm_skill_create","wyrm_skill_deactivate","wyrm_skill_delete","wyrm_skill_get","wyrm_skill_graph","wyrm_skill_list","wyrm_skill_register","wyrm_skill_search","wyrm_skill_stats","wyrm_spec_register","wyrm_symbol_callers","wyrm_symbol_index","wyrm_symbol_search","wyrm_symbol_stats","wyrm_sync","wyrm_sync_conflicts","wyrm_sync_export","wyrm_sync_import","wyrm_sync_resolve","wyrm_token_delete","wyrm_token_get","wyrm_token_set","wyrm_tool_analytics","wyrm_unshare","wyrm_usage","wyrm_vector_setup"],w=_=>_,a=new Map(s.map(_=>{const e=m[_],r=y[_],t={name:_,target:e?.target??_,kind:r?"cli-exile":"route",...r?{cli:r.cli}:{},adapt:e?.adapt??w};return[_,t]}));function l(_,e){const r=a.get(_);return r?{tool:r.target,args:r.adapt(e),via:r}:{tool:_,args:e,via:null}}export{s as ALIAS_NAMES,a as ALIAS_SPINE,l as resolveAliasCall};
1
+ import{CLI_EXILE_TOOLS as y}from"../deprecations.js";import{ALIAS_ROUTE_OVERRIDES as m}from"./alias-adapters.js";const s=["wyrm_activate","wyrm_agent_init","wyrm_agent_restart","wyrm_agent_status","wyrm_agent_stop","wyrm_all_quests","wyrm_analytics_dashboard","wyrm_ask","wyrm_audit_export","wyrm_audit_log","wyrm_audit_verify","wyrm_auto_capture","wyrm_buddy","wyrm_capture_trace","wyrm_check_update","wyrm_cloud_backup","wyrm_cloud_sync","wyrm_constellation","wyrm_cost_report","wyrm_data_batch_insert","wyrm_data_categories","wyrm_data_insert","wyrm_data_query","wyrm_decision_downstream","wyrm_decision_invalidate","wyrm_decision_upstream","wyrm_digest","wyrm_distill","wyrm_embed","wyrm_encrypt_setup","wyrm_entity_add","wyrm_entity_graph","wyrm_entity_link","wyrm_entity_merge","wyrm_entity_path","wyrm_entity_search","wyrm_events_publish","wyrm_events_replicate","wyrm_events_since","wyrm_events_subscribe","wyrm_failure_list","wyrm_failure_resolve","wyrm_feedback","wyrm_global_context","wyrm_goal_abandon","wyrm_goal_complete","wyrm_goal_iterations","wyrm_goal_list","wyrm_goal_pause","wyrm_goal_resume","wyrm_goal_set","wyrm_harvest","wyrm_hours_report","wyrm_import_git","wyrm_import_pr","wyrm_import_rules","wyrm_inject_prompt","wyrm_intro","wyrm_invoice_generate","wyrm_license","wyrm_list_projects","wyrm_mcp_disable","wyrm_mcp_list","wyrm_mcp_register","wyrm_mcp_tools","wyrm_migrate_prompt","wyrm_orchestrate_task","wyrm_orchestration_config","wyrm_orchestration_stats","wyrm_presence_announce","wyrm_presence_list","wyrm_presence_release","wyrm_project_context","wyrm_prune","wyrm_quest_add","wyrm_quest_claim","wyrm_quest_complete","wyrm_quest_release","wyrm_recall_propose","wyrm_recall_set","wyrm_reference_add","wyrm_reference_list","wyrm_reference_search","wyrm_reindex","wyrm_remember","wyrm_scaffold_get","wyrm_scaffold_save","wyrm_scan_projects","wyrm_self_update","wyrm_session_rehydrate","wyrm_session_start","wyrm_session_update","wyrm_set_global","wyrm_setup","wyrm_skill_activate","wyrm_skill_create","wyrm_skill_deactivate","wyrm_skill_delete","wyrm_skill_get","wyrm_skill_graph","wyrm_skill_list","wyrm_skill_register","wyrm_skill_search","wyrm_skill_stats","wyrm_spec_register","wyrm_symbol_callers","wyrm_symbol_index","wyrm_symbol_search","wyrm_symbol_stats","wyrm_sync","wyrm_sync_conflicts","wyrm_sync_export","wyrm_sync_import","wyrm_sync_resolve","wyrm_token_delete","wyrm_token_get","wyrm_token_set","wyrm_tool_analytics","wyrm_unshare","wyrm_usage","wyrm_vector_setup"],w=r=>r,a=new Map(s.map(r=>{const e=m[r],_=y[r],t={name:r,target:e?.target??r,kind:_?"cli-exile":"route",..._?{cli:_.cli}:{},adapt:e?.adapt??w};return[r,t]}));function o(r,e){const _=a.get(r);return _?{tool:_.target,args:_.adapt(e),via:_}:{tool:r,args:e,via:null}}export{s as ALIAS_NAMES,a as ALIAS_SPINE,o as resolveAliasCall};
@@ -1,9 +1,9 @@
1
- import{TOOL_ANNOTATIONS as u}from"../tool-annotations.js";import{staleFoundationWarning as f}from"../causality.js";const $=[{name:"wyrm_decided_because",description:"Use to link a choice or decision to the assumption or evidence it was based on - records a causal edge (truth/quest/artifact/session) so stale foundations invalidate downstream.",inputSchema:{type:"object",properties:{projectPath:{type:"string"},from_kind:{type:"string",enum:["truth","artifact","quest","session","data"]},from_id:{type:"number"},to_kind:{type:"string",enum:["truth","artifact","quest","session","data"]},to_id:{type:"number"},relation:{type:"string",enum:["because_of","supersedes","refutes","verifies"],description:"Default because_of"},rationale:{type:"string",description:"Why"},confidence:{type:"number",description:"0-1, default 1.0"}},required:["projectPath","from_kind","from_id","to_kind","to_id"]},annotations:u.wyrm_decided_because,aliases:[],handler:async(a,d)=>{const{causality:r,db:o}=d,{projectPath:i,from_kind:e,from_id:s,to_kind:t,to_id:c,relation:n,rationale:m,confidence:y}=a,p=o.getProject(i);if(!p)return{content:[{type:"text",text:"Project not found"}],isError:!0};const l=r.link({project_id:p.id,from_kind:e,from_id:s,to_kind:t,to_id:c,relation:n,rationale:m,confidence:y});return{content:[{type:"text",text:`\u{F115D} Edge #${l.id} \u2014 ${e}#${s} ${l.relation} ${t}#${c}`}]}}},{name:"wyrm_decision_downstream",description:"List all decisions that depend on the given source. Use before invalidating a truth to see the blast radius.",inputSchema:{type:"object",properties:{kind:{type:"string",enum:["truth","artifact","quest","session","data"]},id:{type:"number"}},required:["kind","id"]},annotations:u.wyrm_decision_downstream,aliases:[],handler:async(a,d)=>{const{causality:r}=d,{kind:o,id:i}=a,e=r.downstreamOf(o,i);if(e.length===0)return{content:[{type:"text",text:`\u{F115D} No active dependents on ${o}#${i}.`}]};const s=e.map(t=>`\u2022 ${t.from_kind}#${t.from_id} (${t.relation}, conf ${t.confidence})${t.rationale?` \u2014 ${t.rationale}`:""}`).join(`
1
+ import{TOOL_ANNOTATIONS as u}from"../tool-annotations.js";import{staleFoundationWarning as y}from"../causality.js";import{refreshThread as h}from"../thread-assemble.js";const b=[{name:"wyrm_decided_because",description:"Use to link a choice or decision to the assumption or evidence it was based on - records a causal edge (truth/quest/artifact/session) so stale foundations invalidate downstream.",inputSchema:{type:"object",properties:{projectPath:{type:"string"},from_kind:{type:"string",enum:["truth","artifact","quest","session","data"]},from_id:{type:"number"},to_kind:{type:"string",enum:["truth","artifact","quest","session","data"]},to_id:{type:"number"},relation:{type:"string",enum:["because_of","supersedes","refutes","verifies"],description:"Default because_of"},rationale:{type:"string",description:"Why"},confidence:{type:"number",description:"0-1, default 1.0"}},required:["projectPath","from_kind","from_id","to_kind","to_id"]},annotations:u.wyrm_decided_because,aliases:[],handler:async(a,d)=>{const{causality:r,db:o}=d,{projectPath:i,from_kind:e,from_id:s,to_kind:t,to_id:c,relation:n,rationale:m,confidence:f}=a,p=o.getProject(i);if(!p)return{content:[{type:"text",text:"Project not found"}],isError:!0};const l=r.link({project_id:p.id,from_kind:e,from_id:s,to_kind:t,to_id:c,relation:n,rationale:m,confidence:f});return h(o.getDatabase(),p.id),{content:[{type:"text",text:`\u{F115D} Edge #${l.id} \u2014 ${e}#${s} ${l.relation} ${t}#${c}`}]}}},{name:"wyrm_decision_downstream",description:"List all decisions that depend on the given source. Use before invalidating a truth to see the blast radius.",inputSchema:{type:"object",properties:{kind:{type:"string",enum:["truth","artifact","quest","session","data"]},id:{type:"number"}},required:["kind","id"]},annotations:u.wyrm_decision_downstream,aliases:[],handler:async(a,d)=>{const{causality:r}=d,{kind:o,id:i}=a,e=r.downstreamOf(o,i);if(e.length===0)return{content:[{type:"text",text:`\u{F115D} No active dependents on ${o}#${i}.`}]};const s=e.map(t=>`\u2022 ${t.from_kind}#${t.from_id} (${t.relation}, conf ${t.confidence})${t.rationale?` \u2014 ${t.rationale}`:""}`).join(`
2
2
  `);return{content:[{type:"text",text:`\u{F115D} ${e.length} dependent(s):
3
- ${s}`}]}}},{name:"wyrm_decision_upstream",description:"List all sources a decision was based on (incoming edges). Walks the 'why did we choose this?' chain.",inputSchema:{type:"object",properties:{kind:{type:"string",enum:["truth","artifact","quest","session","data"]},id:{type:"number"}},required:["kind","id"]},annotations:u.wyrm_decision_upstream,aliases:[],handler:async(a,d)=>{const{causality:r}=d,{kind:o,id:i}=a,e=r.upstreamOf(o,i),s=f(r.staleFoundations(o,i)),t=s?`${s}
3
+ ${s}`}]}}},{name:"wyrm_decision_upstream",description:"List all sources a decision was based on (incoming edges). Walks the 'why did we choose this?' chain.",inputSchema:{type:"object",properties:{kind:{type:"string",enum:["truth","artifact","quest","session","data"]},id:{type:"number"}},required:["kind","id"]},annotations:u.wyrm_decision_upstream,aliases:[],handler:async(a,d)=>{const{causality:r}=d,{kind:o,id:i}=a,e=r.upstreamOf(o,i),s=y(r.staleFoundations(o,i)),t=s?`${s}
4
4
 
5
5
  `:"";if(e.length===0)return{content:[{type:"text",text:`${t}\u{F115D} No recorded basis for ${o}#${i}.`}]};const c=e.map(n=>`\u2022 ${n.to_kind}#${n.to_id} (${n.relation}, conf ${n.confidence})${n.rationale?` \u2014 ${n.rationale}`:""}`).join(`
6
6
  `);return{content:[{type:"text",text:`${t}\u{F115D} ${e.length} basis edge(s):
7
7
  ${c}`}]}}},{name:"wyrm_decision_invalidate",description:"Cascade-invalidate all decisions downstream of a source (recursive). Use when a foundational truth turns out to be wrong. Returns the set of affected (kind, id) pairs.",inputSchema:{type:"object",properties:{kind:{type:"string",enum:["truth","artifact","quest","session","data"]},id:{type:"number"},reason:{type:"string",description:"Why the source was invalidated"}},required:["kind","id"]},annotations:u.wyrm_decision_invalidate,aliases:[],handler:async(a,d)=>{const{causality:r}=d,o=a||{},{kind:i,id:e,reason:s}=a,t=r.invalidateDownstream(i,e,s);if(t.invalidated===0)return{content:[{type:"text",text:`\u{F115D} No dependents to invalidate from ${i}#${e}.`}]};const c=t.affected.map(n=>`\u2022 ${n.kind}#${n.id} (edge #${n.edge_id})`).join(`
8
8
  `);return{content:[{type:"text",text:`\u{F115D} Invalidated ${t.invalidated} downstream decision(s):
9
- ${c}`}]}}}];export{$ as causalityToolSpecs};
9
+ ${c}`}]}}}];export{b as causalityToolSpecs};
@@ -1,8 +1,8 @@
1
- import{TOOL_ANNOTATIONS as $}from"../tool-annotations.js";import{currentReadCacheKey as I}from"./boundary.js";import{autoConfigureAll as U,findWyrmServerPath as W,getDefaultDbPath as B,getStatusSummary as q,removeFromAll as V}from"../autoconfig.js";import{daemonOr as H}from"../daemon-writer.js";import{renderFailureStats as K}from"../failure-patterns.js";import{computeStaleness as z}from"../intelligence.js";import{logger as Y}from"../logger.js";import{runMaintenance as G}from"../maintenance.js";import{cache as w}from"../performance.js";import{createProvider as Q}from"../providers/embedding-provider.js";import{reindexProjects as Z}from"../reindex.js";import{requireString as J}from"../validate.js";import{createVectorStore as X}from"../vectors.js";import{recordWrite as E,buildWriteDigest as ee}from"../receipts.js";const ye=[{name:"wyrm_feedback",description:"Record whether a recalled knowledge artifact was useful. Adjusts confidence over time \u2014 successful reuse boosts it, failure lowers it. Call after applying a recalled pattern or lesson.",inputSchema:{type:"object",properties:{artifactId:{type:"number",description:"ID of the memory artifact (from wyrm_recall results)"},success:{type:"boolean",description:"Was this artifact helpful for the task?"}},required:["artifactId","success"]},annotations:$.wyrm_feedback,aliases:[],handler:async(p,f)=>{const{memory:c}=f,{artifactId:i,success:l}=p,a=c.get(i);if(!a)return{content:[{type:"text",text:`Artifact #${i} not found.`}],isError:!0};c.recordFeedback(i,l);const t=c.get(i);return{content:[{type:"text",text:`\u{F115D} Feedback recorded ${l?"\u2705":"\u274C"}
1
+ import{TOOL_ANNOTATIONS as _}from"../tool-annotations.js";import{currentReadCacheKey as D}from"./boundary.js";import{resolvePolicy as H,policyHash as V}from"../recall-policy.js";import{autoConfigureAll as K,findWyrmServerPath as z,getDefaultDbPath as Y,getStatusSummary as G,removeFromAll as Q}from"../autoconfig.js";import{daemonOr as Z}from"../daemon-writer.js";import{renderFailureStats as J}from"../failure-patterns.js";import{computeStaleness as X}from"../intelligence.js";import{logger as ee}from"../logger.js";import{runMaintenance as te}from"../maintenance.js";import{cache as w}from"../performance.js";import{createProvider as ne}from"../providers/embedding-provider.js";import{reindexProjects as oe}from"../reindex.js";import{requireString as re}from"../validate.js";import{createVectorStore as se}from"../vectors.js";import{recordWrite as U,buildWriteDigest as ae}from"../receipts.js";import{getActor as ie}from"./boundary.js";const Se=[{name:"wyrm_feedback",description:"Record whether a recalled knowledge artifact was useful. Adjusts confidence over time \u2014 successful reuse boosts it, failure lowers it. Call after applying a recalled pattern or lesson.",inputSchema:{type:"object",properties:{artifactId:{type:"number",description:"ID of the memory artifact (from wyrm_recall results)"},success:{type:"boolean",description:"Was this artifact helpful for the task?"}},required:["artifactId","success"]},annotations:_.wyrm_feedback,aliases:[],handler:async(p,f)=>{const{memory:c}=f,{artifactId:a,success:l}=p,i=c.get(a);if(!i)return{content:[{type:"text",text:`Artifact #${a} not found.`}],isError:!0};c.recordFeedback(a,l);const t=c.get(a);return{content:[{type:"text",text:`\u{F115D} Feedback recorded ${l?"\u2705":"\u274C"}
2
2
 
3
- - Artifact #${i}: "${a.problem.slice(0,60)}"
3
+ - Artifact #${a}: "${i.problem.slice(0,60)}"
4
4
  - New confidence: ${(t.confidence*100).toFixed(0)}%
5
- - Total uses: ${t.reuse_count} (\u2705 ${t.reuse_success_count} / \u274C ${t.reuse_failure_count})`}]}}},{name:"wyrm_context_build",description:"Use to build a compact context brief for the current task under a token budget - relevant patterns, lessons, and truths in one formatted block; max_tokens elides low-score items to recallable stubs.",inputSchema:{type:"object",properties:{projectPath:{type:"string"},task:{type:"string",description:"The current task"},maxItems:{type:"number",description:"Default 10, max 20"},kinds:{type:"array",items:{type:"string"},description:"Artifact kinds (see wyrm_recall)"},minConfidence:{type:"number",description:"Default 0.3"},max_tokens:{type:"number",description:"Token budget; low-score items elide to stubs"},session_id:{type:"number",description:"Already-seen dedup"},strict_budget:{type:"boolean",description:"Also elide truths over budget"}},required:["projectPath","task"]},annotations:$.wyrm_context_build,aliases:[],handler:async(p,f)=>{const{cachedResponse:c,db:i,groundTruths:l,memory:a,runBudgetedContextBuild:t,scaffoldLib:o}=f,r=p||{},s=I(),{projectPath:e,task:n,maxItems:m,kinds:u,minConfidence:d,max_tokens:g,session_id:b,strict_budget:S}=p,y=i.getProject(e);if(!y)return{content:[{type:"text",text:`Project not found: ${e}`}],isError:!0};if(!n||typeof n!="string"||!n.trim())return{content:[{type:"text",text:"wyrm_context_build: 'task' is required \u2014 pass a short description of the current task (not 'query')."}],isError:!0};if(g!=null&&!process.env.WYRM_DISABLE_TOKEN_BUDGET)return t({project:y,task:n,maxTokens:g,sessionId:b,strictBudget:S===!0,kinds:u,minConfidence:d});const h=[],v=l.formatForContext(y.id);v&&h.push(v.slice(0,1200));const _=o.findBest(n,y.id);if(_){const k=o.formatForContext(_);h.push(k.slice(0,1500))}const x=a.buildContextBrief(y.id,n,{maxItems:Math.min(m??10,20),kinds:u,minConfidence:d});if(x.sections.length>0){const k=x.text.slice(0,2e3);h.push(k)}if(h.length===0)return{content:[{type:"text",text:`\u{F115D} **Context Brief**
5
+ - Total uses: ${t.reuse_count} (\u2705 ${t.reuse_success_count} / \u274C ${t.reuse_failure_count})`}]}}},{name:"wyrm_context_build",description:"Use to build a compact context brief for the current task under a token budget - relevant patterns, lessons, and truths in one formatted block; max_tokens elides low-score items to recallable stubs.",inputSchema:{type:"object",properties:{projectPath:{type:"string"},task:{type:"string",description:"The current task"},maxItems:{type:"number",description:"Default 10, max 20"},kinds:{type:"array",items:{type:"string"},description:"Artifact kinds (see wyrm_recall)"},minConfidence:{type:"number",description:"Default 0.3"},max_tokens:{type:"number",description:"Token budget; low-score items elide to stubs"},session_id:{type:"number",description:"Already-seen dedup"},strict_budget:{type:"boolean",description:"Also elide truths over budget"}},required:["projectPath","task"]},annotations:_.wyrm_context_build,aliases:[],handler:async(p,f)=>{const{cachedResponse:c,db:a,groundTruths:l,memory:i,runBudgetedContextBuild:t,scaffoldLib:n}=f,o=p||{},s=D(),e=ie().run_id,r=H(a.getDatabase(),e),m=r.mode==="full"&&r.mutedIds.length===0&&r.challengedTruthIds.length===0,u=s&&!m?`${s}::${V(r)}`:s,{projectPath:d,task:y,maxItems:v,kinds:$,minConfidence:b,max_tokens:j,session_id:h,strict_budget:x}=p,g=a.getProject(d);if(!g)return{content:[{type:"text",text:`Project not found: ${d}`}],isError:!0};if(!y||typeof y!="string"||!y.trim())return{content:[{type:"text",text:"wyrm_context_build: 'task' is required \u2014 pass a short description of the current task (not 'query')."}],isError:!0};if(j!=null&&!process.env.WYRM_DISABLE_TOKEN_BUDGET)return t({project:g,task:y,maxTokens:j,sessionId:h,strictBudget:x===!0,kinds:$,minConfidence:b,runId:e});const P=[],T=l.formatForContext(g.id);T&&P.push(T.slice(0,1200));const S=n.findBest(y,g.id);if(S){const I=n.formatForContext(S);P.push(I.slice(0,1500))}const C=i.buildContextBrief(g.id,y,{maxItems:Math.min(v??10,20),kinds:$,minConfidence:b,runId:e});if(C.sections.length>0){const I=C.text.slice(0,2e3);P.push(I)}if(P.length===0)return{content:[{type:"text",text:`\u{F115D} **Context Brief**
6
6
 
7
7
  No relevant memory found for this task yet.
8
8
 
@@ -12,10 +12,10 @@ As you work, use \`wyrm_remember\` to store:
12
12
  - \u{1F4A1} Heuristics and shortcuts
13
13
  - \u{1F9E0} Reasoning traces from complex problems
14
14
 
15
- Future context briefs will become richer over time.`}]};const T=a.getStats(y.id),P=l.getStats(y.id),A=`\u{F115D} **Context Brief** \u2014 "${n}"
15
+ Future context briefs will become richer over time.`}]};const O=i.getStats(g.id),F=l.getStats(g.id),W=`\u{F115D} **Context Brief** \u2014 "${y}"
16
16
 
17
- `,C=[];v&&C.push(v.slice(0,1200)),_&&C.push(o.formatForContext(_).slice(0,1500));const O=C.length>0?`<!-- cache-stable -->
18
- ${C.join(`
17
+ `,R=[];T&&R.push(T.slice(0,1200)),S&&R.push(n.formatForContext(S).slice(0,1500));const M=R.length>0?`<!-- cache-stable -->
18
+ ${R.join(`
19
19
 
20
20
  ---
21
21
 
@@ -24,41 +24,41 @@ ${C.join(`
24
24
 
25
25
  ---
26
26
 
27
- `:"",L=x.sections.length>0?x.text.slice(0,2e3):"";let R=`${A}${O}${L}`;R+=`
27
+ `:"",B=C.sections.length>0?C.text.slice(0,2e3):"";let A=`${W}${M}${B}`;A+=`
28
28
 
29
- _Brief: ${P.current} ground truth${P.current!==1?"s":""}, scaffold: ${_?_.scaffold.problem_type:"none"}, ${T.total} memory artifact${T.total!==1?"s":""}.`,x.sourceIds.length>0?R+=` Memory IDs: [${x.sourceIds.join(", ")}] \u2014 use \`wyrm_feedback\` to rate._`:R+="_";try{const{logSavings:k}=await import("../statusline.js"),F=i.getDatabase(),N=F.prepare("SELECT id FROM sessions WHERE project_id = ? ORDER BY created_at DESC LIMIT 1").get(y.id),M=Math.round(O.length/4);M>0&&k(F,"wyrm_context_build","cached_preamble",Math.round(M*.9),N?.id)}catch{}const D=c(R);return s&&w.set(s,D,1e4),D}},{name:"wyrm_truth_set",description:"Use to lock in a confirmed fact or constraint as project ground truth - architecture, conventions, key decisions. Injected first into every brief; re-setting the same category+key supersedes (history kept).",inputSchema:{type:"object",properties:{projectPath:{type:"string"},category:{type:"string",description:"e.g. architecture, conventions"},key:{type:"string",description:"snake_case key"},value:{type:"string",description:"The statement"},rationale:{type:"string",description:"Why this is true"},source:{type:"string",description:"'user'|'derived'|'observed'|'confirmed'"},confidence:{type:"number",description:"0-1 (default 1.0)"},ttl_days:{type:"number",description:"Stale after N days"}},required:["projectPath","category","key","value"]},annotations:$.wyrm_truth_set,aliases:[],handler:async(p,f)=>{const{db:c,groundTruths:i,presence:l}=f,{projectPath:a,category:t,key:o,value:r,rationale:s,source:e,confidence:n,ttl_days:m}=p,u=J("category",t,{maxLen:200}),d=c.getProject(a);if(!d)return{content:[{type:"text",text:`Project not found: ${a}`}],isError:!0};const{isConfigShapedTruth:g}=await import("../metabolize.js");if(process.env.WYRM_NO_TRUTH_LINT!=="1"&&g(o,r)){const h=(await import("../memory-artifacts.js")).MemoryArtifacts,_=new h(c.getDatabase()).add(d.id,{kind:"pattern",problem:`TRUTH-SHAPE LINT: "${o}" looks like a config assignment, not a ground truth: ${r.slice(0,120)}`,validatedFix:"If this really is a durable truth, re-set it as a full statement with a subject (or bypass once with WYRM_NO_TRUTH_LINT=1). If it is scan/tool config, it belongs in the data lake, not ground truths.",tags:["metabolize","truth-lint"],confidence:.5,needsReview:1}),x=E(c.getDatabase(),{tool:"wyrm_truth_set",outcome:"queued",refTable:"mem",refId:_.id,reason:"truth-shape lint \u2014 config-assignment shape queued for review instead of stored as a bare truth",source:e,projectId:d.id});return{content:[{type:"text",text:`\u{F115D} **Truth-shape lint** \u2014 "${o}" looks like a config assignment (\`ident = value\`), not a ground truth. Queued for review as mem:${_.id} instead of storing (receipt: ${x.outcome}). Re-phrase as a full statement, or set WYRM_NO_TRUTH_LINT=1 to bypass once.`}]}}const b={category:u,key:o,value:r,rationale:s,source:e,confidence:n??1,ttl_days:m};i.lastCascade=null;const S=await H("truth_set",d.id,b,()=>i.set(d.id,b));w.invalidate("wyrm_truth_get"),w.invalidate("wyrm_context_build");const y=i.lastCascade,j=y&&y.invalidated>0?`
30
- - **Auto-cascade:** ${y.invalidated} downstream decision edge(s) invalidated (rested on the superseded value \u2014 review with \`wyrm_decision_downstream\`)`:"";return E(c.getDatabase(),{tool:"wyrm_truth_set",outcome:"stored",refTable:"truth",refId:S.id,reason:y&&y.invalidated>0?`supersede cascaded \u2014 ${y.invalidated} downstream decision edge(s) invalidated`:void 0,source:e,projectId:d.id}),{content:[{type:"text",text:`\u{F115D} **Ground Truth Set** \u2705
29
+ _Brief: ${F.current} ground truth${F.current!==1?"s":""}, scaffold: ${S?S.scaffold.problem_type:"none"}, ${O.total} memory artifact${O.total!==1?"s":""}.`,C.sourceIds.length>0?A+=` Memory IDs: [${C.sourceIds.join(", ")}] \u2014 use \`wyrm_feedback\` to rate._`:A+="_";try{const{logSavings:I}=await import("../statusline.js"),L=a.getDatabase(),q=L.prepare("SELECT id FROM sessions WHERE project_id = ? ORDER BY created_at DESC LIMIT 1").get(g.id),N=Math.round(M.length/4);N>0&&I(L,"wyrm_context_build","cached_preamble",Math.round(N*.9),q?.id)}catch{}const E=c(A);return u&&w.set(u,E,1e4),E}},{name:"wyrm_truth_set",description:"Use to lock in a confirmed fact or constraint as project ground truth - architecture, conventions, key decisions. Injected first into every brief; re-setting the same category+key supersedes (history kept).",inputSchema:{type:"object",properties:{projectPath:{type:"string"},category:{type:"string",description:"e.g. architecture, conventions"},key:{type:"string",description:"snake_case key"},value:{type:"string",description:"The statement"},rationale:{type:"string",description:"Why this is true"},source:{type:"string",description:"'user'|'derived'|'observed'|'confirmed'"},confidence:{type:"number",description:"0-1 (default 1.0)"},ttl_days:{type:"number",description:"Stale after N days"}},required:["projectPath","category","key","value"]},annotations:_.wyrm_truth_set,aliases:[],handler:async(p,f)=>{const{db:c,groundTruths:a,presence:l}=f,{projectPath:i,category:t,key:n,value:o,rationale:s,source:e,confidence:r,ttl_days:m}=p,u=re("category",t,{maxLen:200}),d=c.getProject(i);if(!d)return{content:[{type:"text",text:`Project not found: ${i}`}],isError:!0};const{isConfigShapedTruth:y}=await import("../metabolize.js");if(process.env.WYRM_NO_TRUTH_LINT!=="1"&&y(n,o)){const h=(await import("../memory-artifacts.js")).MemoryArtifacts,g=new h(c.getDatabase()).add(d.id,{kind:"pattern",problem:`TRUTH-SHAPE LINT: "${n}" looks like a config assignment, not a ground truth: ${o.slice(0,120)}`,validatedFix:"If this really is a durable truth, re-set it as a full statement with a subject (or bypass once with WYRM_NO_TRUTH_LINT=1). If it is scan/tool config, it belongs in the data lake, not ground truths.",tags:["metabolize","truth-lint"],confidence:.5,needsReview:1}),k=U(c.getDatabase(),{tool:"wyrm_truth_set",outcome:"queued",refTable:"mem",refId:g.id,reason:"truth-shape lint \u2014 config-assignment shape queued for review instead of stored as a bare truth",source:e,projectId:d.id});return{content:[{type:"text",text:`\u{F115D} **Truth-shape lint** \u2014 "${n}" looks like a config assignment (\`ident = value\`), not a ground truth. Queued for review as mem:${g.id} instead of storing (receipt: ${k.outcome}). Re-phrase as a full statement, or set WYRM_NO_TRUTH_LINT=1 to bypass once.`}]}}const v={category:u,key:n,value:o,rationale:s,source:e,confidence:r??1,ttl_days:m};a.lastCascade=null;const $=await Z("truth_set",d.id,v,()=>a.set(d.id,v));w.invalidate("wyrm_truth_get"),w.invalidate("wyrm_context_build");const b=a.lastCascade,j=b&&b.invalidated>0?`
30
+ - **Auto-cascade:** ${b.invalidated} downstream decision edge(s) invalidated (rested on the superseded value \u2014 review with \`wyrm_decision_downstream\`)`:"";return U(c.getDatabase(),{tool:"wyrm_truth_set",outcome:"stored",refTable:"truth",refId:$.id,reason:b&&b.invalidated>0?`supersede cascaded \u2014 ${b.invalidated} downstream decision edge(s) invalidated`:void 0,source:e,projectId:d.id}),{content:[{type:"text",text:`\u{F115D} **Ground Truth Set** \u2705
31
31
 
32
32
  - **Category:** ${t}
33
- - **Key:** ${o}
34
- - **Value:** ${r}${s?`
33
+ - **Key:** ${n}
34
+ - **Value:** ${o}${s?`
35
35
  - **Rationale:** ${s}`:""}${m?`
36
36
  - **TTL:** ${m} days`:""}
37
- - **ID:** ${S.id}${j}
37
+ - **ID:** ${$.id}${j}
38
38
 
39
- This truth will be injected at the top of every \`wyrm_context_build\` response for this project.`}]}}},{name:"wyrm_truth_get",description:"Use to read the established facts and ground rules for a codebase - validated truths the AI should treat as baseline, optionally filtered by category.",inputSchema:{type:"object",properties:{projectPath:{type:"string"},category:{type:"string",description:"Category filter"}},required:["projectPath"]},annotations:$.wyrm_truth_get,aliases:[],handler:async(p,f)=>{const{cachedResponse:c,db:i,groundTruths:l}=f,a=I(),{projectPath:t,category:o}=p,r=i.getProject(t);if(!r)return{content:[{type:"text",text:`Project not found: ${t}`}],isError:!0};const s=l.getCurrent(r.id,o);if(s.length===0)return{content:[{type:"text",text:`\u{F115D} **Ground Truths**
39
+ This truth will be injected at the top of every \`wyrm_context_build\` response for this project.`}]}}},{name:"wyrm_truth_get",description:"Use to read the established facts and ground rules for a codebase - validated truths the AI should treat as baseline, optionally filtered by category.",inputSchema:{type:"object",properties:{projectPath:{type:"string"},category:{type:"string",description:"Category filter"}},required:["projectPath"]},annotations:_.wyrm_truth_get,aliases:[],handler:async(p,f)=>{const{cachedResponse:c,db:a,groundTruths:l}=f,i=D(),{projectPath:t,category:n}=p,o=a.getProject(t);if(!o)return{content:[{type:"text",text:`Project not found: ${t}`}],isError:!0};const s=l.getCurrent(o.id,n);if(s.length===0)return{content:[{type:"text",text:`\u{F115D} **Ground Truths**
40
40
 
41
- ${o?`No ground truths in category "${o}" for this project.`:"No ground truths stored yet. Use `wyrm_truth_set` to add validated facts."}`}]};const e=new Map;for(const u of s)e.has(u.category)||e.set(u.category,[]),e.get(u.category).push(u);let n=`\u{F115D} **Ground Truths** \u2014 ${s.length} active
41
+ ${n?`No ground truths in category "${n}" for this project.`:"No ground truths stored yet. Use `wyrm_truth_set` to add validated facts."}`}]};const e=new Map;for(const u of s)e.has(u.category)||e.set(u.category,[]),e.get(u.category).push(u);let r=`\u{F115D} **Ground Truths** \u2014 ${s.length} active
42
42
 
43
- `;for(const[u,d]of e){n+=`### ${u}
44
- `;for(const g of d){const b=z(g),y=b!==null&&b>.7?"[\u26A0\uFE0F STALE] ":"";n+=`- ${y}**${g.key}:** ${g.value}`,g.confidence<1&&(n+=` _(confidence: ${(g.confidence*100).toFixed(0)}%)_`),g.rationale&&(n+=`
45
- _${g.rationale}_`),b!==null&&(n+=`
46
- _staleness: ${(b*100).toFixed(0)}% (TTL: ${g.ttl_days}d)_`),n+=`
47
- `}n+=`
48
- `}const m=c(n);return a&&w.set(a,m,15e3),m}},{name:"wyrm_scaffold_get",description:"Find the best reasoning scaffold for a task description. Returns the most relevant structured checklist, or null if no match meets the confidence threshold.",inputSchema:{type:"object",properties:{projectPath:{type:"string",description:"Project path (searches project + global)"},task:{type:"string",description:"Task description to match against scaffolds"},minConfidence:{type:"number",description:"Minimum match confidence 0-1 (default: 0.3)"}},required:["task"]},annotations:$.wyrm_scaffold_get,aliases:[],handler:async(p,f)=>{const{cachedResponse:c,db:i,scaffoldLib:l}=f,a=I(),{projectPath:t,task:o,minConfidence:r}=p,s=t?i.getProject(t)?.id??void 0:void 0,e=l.findBest(o,s,r);if(!e)return{content:[{type:"text",text:`\u{F115D} **Reasoning Scaffold**
43
+ `;for(const[u,d]of e){r+=`### ${u}
44
+ `;for(const y of d){const v=X(y),b=v!==null&&v>.7?"[\u26A0\uFE0F STALE] ":"";r+=`- ${b}**${y.key}:** ${y.value}`,y.confidence<1&&(r+=` _(confidence: ${(y.confidence*100).toFixed(0)}%)_`),y.rationale&&(r+=`
45
+ _${y.rationale}_`),v!==null&&(r+=`
46
+ _staleness: ${(v*100).toFixed(0)}% (TTL: ${y.ttl_days}d)_`),r+=`
47
+ `}r+=`
48
+ `}const m=c(r);return i&&w.set(i,m,15e3),m}},{name:"wyrm_scaffold_get",description:"Find the best reasoning scaffold for a task description. Returns the most relevant structured checklist, or null if no match meets the confidence threshold.",inputSchema:{type:"object",properties:{projectPath:{type:"string",description:"Project path (searches project + global)"},task:{type:"string",description:"Task description to match against scaffolds"},minConfidence:{type:"number",description:"Minimum match confidence 0-1 (default: 0.3)"}},required:["task"]},annotations:_.wyrm_scaffold_get,aliases:[],handler:async(p,f)=>{const{cachedResponse:c,db:a,scaffoldLib:l}=f,i=D(),{projectPath:t,task:n,minConfidence:o}=p,s=t?a.getProject(t)?.id??void 0:void 0,e=l.findBest(n,s,o);if(!e)return{content:[{type:"text",text:`\u{F115D} **Reasoning Scaffold**
49
49
 
50
- No scaffold matched for: "${o}"
50
+ No scaffold matched for: "${n}"
51
51
 
52
- Use \`wyrm_scaffold_save\` to add scaffolds for this problem type.`}]};const n=l.formatForContext(e),m=c(`\u{F115D} **Reasoning Scaffold Match** (${(e.matchScore*100).toFixed(0)}% confidence)
52
+ Use \`wyrm_scaffold_save\` to add scaffolds for this problem type.`}]};const r=l.formatForContext(e),m=c(`\u{F115D} **Reasoning Scaffold Match** (${(e.matchScore*100).toFixed(0)}% confidence)
53
53
 
54
- ${n}`);return a&&w.set(a,m,15e3),m}},{name:"wyrm_sync",description:"Sync database with .wyrm folders in all projects",inputSchema:{type:"object",properties:{projectPath:{type:"string",description:"Sync specific project, or all if not specified"},direction:{type:"string",enum:["import","export","both"],description:"Sync direction"}}},annotations:$.wyrm_sync,aliases:[],handler:async(p,f)=>{const{db:c,sync:i}=f,{projectPath:l,direction:a}=p,t=a||"both";let o=0;if(l)c.getProject(l)&&((t==="import"||t==="both")&&i.importFromFolder(l),(t==="export"||t==="both")&&i.exportToFolder(l),o=1);else{const r=c.getAllProjects(1e3);for(const s of r)try{(t==="import"||t==="both")&&i.importFromFolder(s.path),(t==="export"||t==="both")&&i.exportToFolder(s.path),o++}catch{}}return{content:[{type:"text",text:`\u{F115D} Synced ${o} project(s)`}]}}},{name:"wyrm_stats",description:"Use for a health snapshot of the memory database - row counts, vector index coverage, usage.",inputSchema:{type:"object",properties:{view:{type:"string",enum:["failures"],description:"'failures' = prevented-repeat analytics"},projectPath:{type:"string",description:"failures view scope"}}},annotations:$.wyrm_stats,aliases:[],handler:async(p,f)=>{const{WRITE_TOOLS:c,analytics:i,cachedResponse:l,db:a,failures:t,getUsageStats:o,orchestrator:r,vectorStore:s}=f,e=p||{},n=I(),{view:m,projectPath:u}=p;if(m==="failures"){const h=u?a.getProject(u):null,v=t.failureStats({projectId:h?.id??null});return{content:[{type:"text",text:K(v)}],structuredContent:v}}const d=a.getStats(),g=w.stats(),b=o();let S="";if(s){const h=s.getStats(),v=h.byType||{},_=(v.artifact||0)+(v.quest||0)+(v.session||0),x=d.artifacts+d.quests+d.sessions,T=x>0?Math.min(100,_/x*100).toFixed(1):"0";S=`
54
+ ${r}`);return i&&w.set(i,m,15e3),m}},{name:"wyrm_sync",description:"Sync database with .wyrm folders in all projects",inputSchema:{type:"object",properties:{projectPath:{type:"string",description:"Sync specific project, or all if not specified"},direction:{type:"string",enum:["import","export","both"],description:"Sync direction"}}},annotations:_.wyrm_sync,aliases:[],handler:async(p,f)=>{const{db:c,sync:a}=f,{projectPath:l,direction:i}=p,t=i||"both";let n=0;if(l)c.getProject(l)&&((t==="import"||t==="both")&&a.importFromFolder(l),(t==="export"||t==="both")&&a.exportToFolder(l),n=1);else{const o=c.getAllProjects(1e3);for(const s of o)try{(t==="import"||t==="both")&&a.importFromFolder(s.path),(t==="export"||t==="both")&&a.exportToFolder(s.path),n++}catch{}}return{content:[{type:"text",text:`\u{F115D} Synced ${n} project(s)`}]}}},{name:"wyrm_stats",description:"Use for a health snapshot of the memory database - row counts, vector index coverage, usage.",inputSchema:{type:"object",properties:{view:{type:"string",enum:["failures"],description:"'failures' = prevented-repeat analytics"},projectPath:{type:"string",description:"failures view scope"}}},annotations:_.wyrm_stats,aliases:[],handler:async(p,f)=>{const{WRITE_TOOLS:c,analytics:a,cachedResponse:l,db:i,failures:t,getUsageStats:n,orchestrator:o,vectorStore:s}=f,e=p||{},r=D(),{view:m,projectPath:u}=p;if(m==="failures"){const h=u?i.getProject(u):null,x=t.failureStats({projectId:h?.id??null});return{content:[{type:"text",text:J(x)}],structuredContent:x}}const d=i.getStats(),y=w.stats(),v=n();let $="";if(s){const h=s.getStats(),x=h.byType||{},g=(x.artifact||0)+(x.quest||0)+(x.session||0),k=d.artifacts+d.quests+d.sessions,P=k>0?Math.min(100,g/k*100).toFixed(1):"0";$=`
55
55
  **Vectors:**
56
56
  - **Provider:** ${h.provider} (${h.model})
57
57
  - **Embeddings:** ${h.total} vectors
58
- - **Coverage:** ${T}% of embeddable content
59
- - **By Type:** ${Object.entries(h.byType).map(([P,A])=>`${P}: ${A}`).join(", ")}
60
- `}let y="";try{const h=ee(a.getDatabase(),1);y=`
61
- **Writes (24h):** ${Object.entries(h.byOutcome).map(([_,x])=>`${_}: ${x}`).join(", ")||"none"}
58
+ - **Coverage:** ${P}% of embeddable content
59
+ - **By Type:** ${Object.entries(h.byType).map(([T,S])=>`${T}: ${S}`).join(", ")}
60
+ `}let b="";try{const h=ae(i.getDatabase(),1);b=`
61
+ **Writes (24h):** ${Object.entries(h.byOutcome).map(([g,k])=>`${g}: ${k}`).join(", ")||"none"}
62
62
  **Review queue:** ${h.reviewQueueDepth} awaiting wyrm_review${h.reviewQueueDepth>0?" (invisible to recall until approved)":""}
63
63
  `}catch{}const j=l(`\u{F115D} **Wyrm Statistics**
64
64
 
@@ -68,11 +68,11 @@ ${n}`);return a&&w.set(a,m,15e3),m}},{name:"wyrm_sync",description:"Sync databas
68
68
  - **Data Points:** ${d.dataPoints}
69
69
  - **Active Tokens:** ~${d.totalTokens.toLocaleString()}
70
70
  - **Database Size:** ${d.dbSize}
71
- `+S+y+`
72
- **Cache:** ${g.size} entries | Hit rate: ${b.cacheHitRate}
73
- **Usage:** ${b.totalCalls} calls | ~${b.tokensSaved.toLocaleString()} tokens saved by cache`);return n&&w.set(n,j,15e3),j}},{name:"wyrm_vector_setup",description:"Configure embedding provider and download models. Supports local, OpenAI, and Ollama.",inputSchema:{type:"object",properties:{provider:{type:"string",enum:["auto","local","openai","ollama","none"],description:"Provider: auto-detect, local hash, OpenAI API, Ollama, or none"},model:{type:"string",description:"Model name (e.g., 'text-embedding-3-small' for OpenAI, 'nomic-embed-text' for Ollama)"},apiKey:{type:"string",description:"OpenAI API key (if using openai provider)"},ollamaUrl:{type:"string",description:"Ollama URL (default: http://localhost:11434)"}}},annotations:$.wyrm_vector_setup,aliases:[],handler:async(p,f)=>{const{db:c,indexingPipeline:i,memory:l,setVectorStore:a,vectorStore:t}=f,{provider:o,model:r,apiKey:s,ollamaUrl:e}=p,n={provider:o||"auto",model:r,apiKey:s,ollamaUrl:e};try{const m=Q(n),u=await m.isReady();if(!u&&n.provider!=="none")return{content:[{type:"text",text:`\u274C **Provider Not Ready**
71
+ `+$+b+`
72
+ **Cache:** ${y.size} entries | Hit rate: ${v.cacheHitRate}
73
+ **Usage:** ${v.totalCalls} calls | ~${v.tokensSaved.toLocaleString()} tokens saved by cache`);return r&&w.set(r,j,15e3),j}},{name:"wyrm_vector_setup",description:"Configure embedding provider and download models. Supports local, OpenAI, and Ollama.",inputSchema:{type:"object",properties:{provider:{type:"string",enum:["auto","local","openai","ollama","none"],description:"Provider: auto-detect, local hash, OpenAI API, Ollama, or none"},model:{type:"string",description:"Model name (e.g., 'text-embedding-3-small' for OpenAI, 'nomic-embed-text' for Ollama)"},apiKey:{type:"string",description:"OpenAI API key (if using openai provider)"},ollamaUrl:{type:"string",description:"Ollama URL (default: http://localhost:11434)"}}},annotations:_.wyrm_vector_setup,aliases:[],handler:async(p,f)=>{const{db:c,indexingPipeline:a,memory:l,setVectorStore:i,vectorStore:t}=f,{provider:n,model:o,apiKey:s,ollamaUrl:e}=p,r={provider:n||"auto",model:o,apiKey:s,ollamaUrl:e};try{const m=ne(r),u=await m.isReady();if(!u&&r.provider!=="none")return{content:[{type:"text",text:`\u274C **Provider Not Ready**
74
74
 
75
- Couldn't connect to ${m.name}. Check your configuration and try again.`}],isError:!0};const d=X(n,c.getDatabase());a(d),l.setVectorStore(d),i&&i.updateStore(d);const g=d.getStats();return{content:[{type:"text",text:`\u2705 **Vector Setup Complete**
75
+ Couldn't connect to ${m.name}. Check your configuration and try again.`}],isError:!0};const d=se(r,c.getDatabase());i(d),l.setVectorStore(d),a&&a.updateStore(d);const y=d.getStats();return{content:[{type:"text",text:`\u2705 **Vector Setup Complete**
76
76
 
77
77
  - **Provider:** ${m.name}
78
78
  - **Model:** ${m.model}
@@ -81,50 +81,50 @@ Couldn't connect to ${m.name}. Check your configuration and try again.`}],isErro
81
81
 
82
82
  _Reindex your projects with wyrm_reindex to generate embeddings._`}]}}catch(m){return{content:[{type:"text",text:`\u274C **Vector Setup Failed**
83
83
 
84
- ${String(m)}`}],isError:!0}}}},{name:"wyrm_reindex",description:"Rebuild embeddings for a project or all projects. Regenerates vectors for sessions, quests, data, and memory artifacts (the latter power hybrid recall).",inputSchema:{type:"object",properties:{projectPath:{type:"string",description:"Project to reindex, or leave empty for all projects"},dryRun:{type:"boolean",description:"Show what would be indexed without making changes"}}},annotations:$.wyrm_reindex,aliases:[],handler:async(p,f)=>{const{db:c,failures:i,vectorStore:l}=f,{projectPath:a,dryRun:t}=p;if(!l)return{content:[{type:"text",text:`\u274C **Vector Indexing Disabled**
84
+ ${String(m)}`}],isError:!0}}}},{name:"wyrm_reindex",description:"Rebuild embeddings for a project or all projects. Regenerates vectors for sessions, quests, data, and memory artifacts (the latter power hybrid recall).",inputSchema:{type:"object",properties:{projectPath:{type:"string",description:"Project to reindex, or leave empty for all projects"},dryRun:{type:"boolean",description:"Show what would be indexed without making changes"}}},annotations:_.wyrm_reindex,aliases:[],handler:async(p,f)=>{const{db:c,failures:a,vectorStore:l}=f,{projectPath:i,dryRun:t}=p;if(!l)return{content:[{type:"text",text:`\u274C **Vector Indexing Disabled**
85
85
 
86
- Run wyrm_vector_setup first to enable vector search.`}],isError:!0};let o=[];if(a){const e=c.getProject(a);if(!e)return{content:[{type:"text",text:`\u274C **Project Not Found:** ${a}`}],isError:!0};o=[e.id]}else o=c.getAllProjects(1e3).map(n=>n.id);const{indexed:r,skipped:s}=await Z(c.getDatabase(),l,o,{dryRun:t,onError:(e,n)=>Y.error(e,n)});return{content:[{type:"text",text:`\u{F115D} **Reindexing ${t?"(Dry Run)":"Complete"}**
86
+ Run wyrm_vector_setup first to enable vector search.`}],isError:!0};let n=[];if(i){const e=c.getProject(i);if(!e)return{content:[{type:"text",text:`\u274C **Project Not Found:** ${i}`}],isError:!0};n=[e.id]}else n=c.getAllProjects(1e3).map(r=>r.id);const{indexed:o,skipped:s}=await oe(c.getDatabase(),l,n,{dryRun:t,onError:(e,r)=>ee.error(e,r)});return{content:[{type:"text",text:`\u{F115D} **Reindexing ${t?"(Dry Run)":"Complete"}**
87
87
 
88
- - **Projects:** ${o.length}
89
- - **Indexed:** ${r}
88
+ - **Projects:** ${n.length}
89
+ - **Indexed:** ${o}
90
90
  - **Skipped:** ${s}
91
91
 
92
- `+(t?"_Run without dryRun to actually index._":"_Vectors are now up to date._")}]}}},{name:"wyrm_maintenance",description:"Use for periodic upkeep of the memory store - archive old sessions, vacuum, prune stale events, sweep run quarantine, rebuild vector embeddings (reindex). Admin-gated, destructive; fleets run it between waves.",inputSchema:{type:"object",properties:{vacuum:{type:"boolean",description:"Reclaim space"},archiveDays:{type:"number",description:"Archive sessions > N days"}}},annotations:$.wyrm_maintenance,aliases:[],handler:async(p,f)=>{const{db:c,failures:i,presence:l,sessionSeen:a}=f,t=p||{},{vacuum:o,archiveDays:r}=p,s=G({db:c,sessionSeen:a(),failures:i,presence:l},{vacuum:o,archiveDays:r});return{content:[{type:"text",text:`\u{F115D} **Maintenance Complete**
92
+ `+(t?"_Run without dryRun to actually index._":"_Vectors are now up to date._")}]}}},{name:"wyrm_maintenance",description:"Use for periodic upkeep of the memory store - archive old sessions, vacuum, prune stale events, sweep run quarantine, rebuild vector embeddings (reindex). Admin-gated, destructive; fleets run it between waves.",inputSchema:{type:"object",properties:{vacuum:{type:"boolean",description:"Reclaim space"},archiveDays:{type:"number",description:"Archive sessions > N days"}}},annotations:_.wyrm_maintenance,aliases:[],handler:async(p,f)=>{const{db:c,failures:a,presence:l,sessionSeen:i}=f,t=p||{},{vacuum:n,archiveDays:o}=p,s=te({db:c,sessionSeen:i(),failures:a,presence:l},{vacuum:n,archiveDays:o});return{content:[{type:"text",text:`\u{F115D} **Maintenance Complete**
93
93
 
94
- `+s.lines.map(n=>`- ${n}
94
+ `+s.lines.map(r=>`- ${r}
95
95
  `).join("")+`
96
- **New Database Size:** ${s.dbSize}`}]}}},{name:"wyrm_setup",description:"Auto-detect installed AI clients (VS Code, Claude Desktop, Cursor, Windsurf, Zed) and configure Wyrm's MCP server in all of them. Run this to connect Wyrm to a new AI or after switching providers.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["configure","check","remove"],description:"Action: configure (default), check status, or remove from all"},serverPath:{type:"string",description:"Override Wyrm server path (auto-detected if empty)"},dbPath:{type:"string",description:"Override database path (default: ~/.wyrm/wyrm.db)"}}},annotations:$.wyrm_setup,aliases:[],handler:async(p,f)=>{const{action:c,serverPath:i,dbPath:l}=p,a=c||"configure";if(a==="check")return{content:[{type:"text",text:q()}]};if(a==="remove"){const e=V();return{content:[{type:"text",text:`\u{F115D} **Wyrm Removed**
96
+ **New Database Size:** ${s.dbSize}`}]}}},{name:"wyrm_setup",description:"Auto-detect installed AI clients (VS Code, Claude Desktop, Cursor, Windsurf, Zed) and configure Wyrm's MCP server in all of them. Run this to connect Wyrm to a new AI or after switching providers.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["configure","check","remove"],description:"Action: configure (default), check status, or remove from all"},serverPath:{type:"string",description:"Override Wyrm server path (auto-detected if empty)"},dbPath:{type:"string",description:"Override database path (default: ~/.wyrm/wyrm.db)"}}},annotations:_.wyrm_setup,aliases:[],handler:async(p,f)=>{const{action:c,serverPath:a,dbPath:l}=p,i=c||"configure";if(i==="check")return{content:[{type:"text",text:G()}]};if(i==="remove"){const e=Q();return{content:[{type:"text",text:`\u{F115D} **Wyrm Removed**
97
97
 
98
98
  Removed from ${e.filter(u=>u.action==="configured").length} AI client(s):
99
99
  `+e.map(u=>`- ${u.client.icon} ${u.client.name}: ${u.message}`).join(`
100
100
  `)+`
101
101
 
102
- Run wyrm_setup again to reconnect.`}]}}const t=U({serverPath:i||void 0,dbPath:l||void 0}),o=t.filter(e=>e.action==="configured"||e.action==="updated"),r=t.filter(e=>e.action==="failed");let s=`\u{F115D} **Wyrm Auto-Configure Complete**
102
+ Run wyrm_setup again to reconnect.`}]}}const t=K({serverPath:a||void 0,dbPath:l||void 0}),n=t.filter(e=>e.action==="configured"||e.action==="updated"),o=t.filter(e=>e.action==="failed");let s=`\u{F115D} **Wyrm Auto-Configure Complete**
103
103
 
104
- `;s+=`Connected to ${o.length} AI client(s):
105
- `;for(const e of t){const n=e.action==="configured"?"\u2705":e.action==="updated"?"\u{1F504}":e.action==="skipped"?"\u25CB":"\u274C";s+=`- ${n} ${e.client.icon} ${e.client.name}: ${e.message}
106
- `}return r.length>0&&(s+=`
107
- \u26A0\uFE0F ${r.length} client(s) failed. Check errors above.`),s+=`
104
+ `;s+=`Connected to ${n.length} AI client(s):
105
+ `;for(const e of t){const r=e.action==="configured"?"\u2705":e.action==="updated"?"\u{1F504}":e.action==="skipped"?"\u25CB":"\u274C";s+=`- ${r} ${e.client.icon} ${e.client.name}: ${e.message}
106
+ `}return o.length>0&&(s+=`
107
+ \u26A0\uFE0F ${o.length} client(s) failed. Check errors above.`),s+=`
108
108
 
109
- Server: ${W()}
110
- DB: ${B()}`,s+=`
109
+ Server: ${z()}
110
+ DB: ${Y()}`,s+=`
111
111
 
112
- _Switch AIs anytime \u2014 run wyrm_setup again to reconnect._`,{content:[{type:"text",text:s}]}}},{name:"wyrm_usage",description:"View token usage stats, cache hit rates, and estimated cost savings. Helps monitor and optimize AI credit consumption.",inputSchema:{type:"object",properties:{last:{type:"number",description:"Show stats for last N calls (default: all)"},reset:{type:"boolean",description:"Reset usage counters"}}},annotations:$.wyrm_usage,aliases:[],handler:async(p,f)=>{const{cachedResponse:c,getUsageStats:i,responseFingerprints:l,usageLog:a}=f,{last:t,reset:o}=p;if(o)return a.length=0,l.clear(),w.invalidate(),{content:[{type:"text",text:"\u{F115D} Usage counters reset, caches cleared."}]};const r=i(t),s=w.stats();let e=`\u{F115D} **Wyrm Usage Report**
112
+ _Switch AIs anytime \u2014 run wyrm_setup again to reconnect._`,{content:[{type:"text",text:s}]}}},{name:"wyrm_usage",description:"View token usage stats, cache hit rates, and estimated cost savings. Helps monitor and optimize AI credit consumption.",inputSchema:{type:"object",properties:{last:{type:"number",description:"Show stats for last N calls (default: all)"},reset:{type:"boolean",description:"Reset usage counters"}}},annotations:_.wyrm_usage,aliases:[],handler:async(p,f)=>{const{cachedResponse:c,getUsageStats:a,responseFingerprints:l,usageLog:i}=f,{last:t,reset:n}=p;if(n)return i.length=0,l.clear(),w.invalidate(),{content:[{type:"text",text:"\u{F115D} Usage counters reset, caches cleared."}]};const o=a(t),s=w.stats();let e=`\u{F115D} **Wyrm Usage Report**
113
113
 
114
114
  `;if(e+=`## Overview${t?` (last ${t} calls)`:""}
115
- `,e+=`- **Total Calls:** ${r.totalCalls}
116
- `,e+=`- **Cache Hits:** ${r.cachedCalls} (${r.cacheHitRate})
117
- `,e+=`- **Tokens In:** ~${r.totalTokensIn.toLocaleString()}
118
- `,e+=`- **Tokens Out:** ~${r.totalTokensOut.toLocaleString()}
119
- `,e+=`- **Tokens Saved (cache):** ~${r.tokensSaved.toLocaleString()}
120
- `,e+=`- **Avg Response:** ${r.avgResponseMs}ms
115
+ `,e+=`- **Total Calls:** ${o.totalCalls}
116
+ `,e+=`- **Cache Hits:** ${o.cachedCalls} (${o.cacheHitRate})
117
+ `,e+=`- **Tokens In:** ~${o.totalTokensIn.toLocaleString()}
118
+ `,e+=`- **Tokens Out:** ~${o.totalTokensOut.toLocaleString()}
119
+ `,e+=`- **Tokens Saved (cache):** ~${o.tokensSaved.toLocaleString()}
120
+ `,e+=`- **Avg Response:** ${o.avgResponseMs}ms
121
121
  `,e+=`- **Active Cache Entries:** ${s.size}
122
122
 
123
- `,r.topTools.length>0){e+=`## Top Tools by Token Usage
124
- `;for(const d of r.topTools)e+=`- **${d.tool}:** ${d.calls} calls, ~${d.tokens.toLocaleString()} tokens
123
+ `,o.topTools.length>0){e+=`## Top Tools by Token Usage
124
+ `;for(const d of o.topTools)e+=`- **${d.tool}:** ${d.calls} calls, ~${d.tokens.toLocaleString()} tokens
125
125
  `;e+=`
126
- `}const n=r.totalTokensIn/1e6*15,m=r.totalTokensOut/1e6*75,u=r.tokensSaved/1e6*75;return e+=`## Estimated Cost (Claude Opus rates)
127
- `,e+=`- **Input:** $${n.toFixed(4)}
126
+ `}const r=o.totalTokensIn/1e6*15,m=o.totalTokensOut/1e6*75,u=o.tokensSaved/1e6*75;return e+=`## Estimated Cost (Claude Opus rates)
127
+ `,e+=`- **Input:** $${r.toFixed(4)}
128
128
  `,e+=`- **Output:** $${m.toFixed(4)}
129
129
  `,e+=`- **Saved by cache:** $${u.toFixed(4)}
130
- `,e+=`- **Net cost:** $${(n+m-u).toFixed(4)}`,c(e,!0)}}];export{ye as intelligenceToolSpecs};
130
+ `,e+=`- **Net cost:** $${(r+m-u).toFixed(4)}`,c(e,!0)}}];export{Se as intelligenceToolSpecs};