wyrm-mcp 8.5.8 → 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.
- package/dist/context-build-budgeted.js +4 -4
- package/dist/cors.js +1 -0
- package/dist/failure-patterns.js +53 -39
- package/dist/handlers/aliases.js +1 -1
- package/dist/handlers/causality.js +3 -3
- package/dist/handlers/intelligence.js +57 -57
- package/dist/handlers/quest.js +3 -3
- package/dist/handlers/recall.js +29 -10
- package/dist/handlers/registry.js +1 -1
- package/dist/handlers/session.js +24 -24
- package/dist/handlers/survivors.js +1 -1
- package/dist/handlers/thread.js +2 -0
- package/dist/index.js +2 -2
- package/dist/memory-artifacts.js +29 -26
- package/dist/migrations.js +32 -6
- package/dist/recall-policy.js +1 -0
- package/dist/setup-wizard.js +5 -0
- package/dist/setup.js +3 -3
- package/dist/thread-assemble.js +1 -0
- package/dist/thread-polish.js +9 -0
- package/dist/thread-signals.js +35 -0
- package/dist/thread-snapshot.js +4 -0
- package/dist/thread-store.js +16 -0
- package/dist/tool-annotations.js +1 -1
- package/dist/tool-manifest-v2.json +6 -2
- package/dist/tool-manifest.json +1 -1
- package/dist/wyrm-cli.js +122 -119
- package/dist/wyrm-guard.js +13 -13
- package/dist/wyrm-manifest.json +30 -2
- package/package.json +3 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{applyBudget as
|
|
2
|
-
`),t.strictBudget&&
|
|
3
|
-
`);
|
|
4
|
-
`);try{
|
|
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};
|
package/dist/failure-patterns.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import{readFileSync as
|
|
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:** ${
|
|
4
|
-
- By quarantine: ${e(
|
|
5
|
-
- By scope: ${e(
|
|
6
|
-
- By agent: ${t(
|
|
7
|
-
- By run: ${t(
|
|
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:** ${
|
|
9
|
+
**Confirmations:** ${s.confirmations.total} from ${s.confirmations.distinct_agents} distinct agent(s)
|
|
10
10
|
|
|
11
|
-
**Repeats blocked:** ${
|
|
11
|
+
**Repeats blocked:** ${s.blocked.total} total
|
|
12
12
|
${o}
|
|
13
|
-
- By agent: ${t(
|
|
14
|
-
- By run: ${t(
|
|
15
|
-
- Top blockers: ${
|
|
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(
|
|
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??
|
|
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",
|
|
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
|
|
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
|
-
`),
|
|
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);
|
|
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,
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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({...
|
|
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(
|
|
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({...
|
|
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({...
|
|
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{
|
|
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};
|
package/dist/handlers/aliases.js
CHANGED
|
@@ -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=
|
|
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
|
|
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=
|
|
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{
|
|
9
|
+
${c}`}]}}}];export{b as causalityToolSpecs};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{TOOL_ANNOTATIONS as
|
|
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 #${
|
|
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
|
|
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
|
|
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
|
-
`,
|
|
18
|
-
${
|
|
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
|
-
`:"",
|
|
27
|
+
`:"",B=C.sections.length>0?C.text.slice(0,2e3):"";let A=`${W}${M}${B}`;A+=`
|
|
28
28
|
|
|
29
|
-
_Brief: ${
|
|
30
|
-
- **Auto-cascade:** ${
|
|
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:** ${
|
|
34
|
-
- **Value:** ${
|
|
33
|
+
- **Key:** ${n}
|
|
34
|
+
- **Value:** ${o}${s?`
|
|
35
35
|
- **Rationale:** ${s}`:""}${m?`
|
|
36
36
|
- **TTL:** ${m} days`:""}
|
|
37
|
-
- **ID:** ${
|
|
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
|
|
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
|
-
${
|
|
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){
|
|
44
|
-
`;for(const
|
|
45
|
-
_${
|
|
46
|
-
_staleness: ${(
|
|
47
|
-
`}
|
|
48
|
-
`}const m=c(
|
|
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: "${
|
|
50
|
+
No scaffold matched for: "${n}"
|
|
51
51
|
|
|
52
|
-
Use \`wyrm_scaffold_save\` to add scaffolds for this problem type.`}]};const
|
|
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
|
-
${
|
|
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:** ${
|
|
59
|
-
- **By Type:** ${Object.entries(h.byType).map(([
|
|
60
|
-
`}let
|
|
61
|
-
**Writes (24h):** ${Object.entries(h.byOutcome).map(([
|
|
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
|
-
|
|
72
|
-
**Cache:** ${
|
|
73
|
-
**Usage:** ${
|
|
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=
|
|
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
|
|
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
|
|
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:** ${
|
|
89
|
-
- **Indexed:** ${
|
|
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
|
|
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(
|
|
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
|
|
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=
|
|
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 ${
|
|
105
|
-
`;for(const e of t){const
|
|
106
|
-
`}return
|
|
107
|
-
\u26A0\uFE0F ${
|
|
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: ${
|
|
110
|
-
DB: ${
|
|
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
|
|
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:** ${
|
|
116
|
-
`,e+=`- **Cache Hits:** ${
|
|
117
|
-
`,e+=`- **Tokens In:** ~${
|
|
118
|
-
`,e+=`- **Tokens Out:** ~${
|
|
119
|
-
`,e+=`- **Tokens Saved (cache):** ~${
|
|
120
|
-
`,e+=`- **Avg Response:** ${
|
|
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
|
-
`,
|
|
124
|
-
`;for(const d of
|
|
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
|
|
127
|
-
`,e+=`- **Input:** $${
|
|
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:** $${(
|
|
130
|
+
`,e+=`- **Net cost:** $${(r+m-u).toFixed(4)}`,c(e,!0)}}];export{Se as intelligenceToolSpecs};
|