wyrm-mcp 8.5.8 → 8.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- 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
package/README.md
CHANGED
|
@@ -108,6 +108,16 @@ Claude (Code, desktop, web) · Cursor · GitHub Copilot · Windsurf · Codex, an
|
|
|
108
108
|
|
|
109
109
|
Node.js 22 or newer. Optional: a local Ollama with `nomic-embed-text` for semantic recall without any hosted call.
|
|
110
110
|
|
|
111
|
+
## Pricing
|
|
112
|
+
|
|
113
|
+
Wyrm is **free to use forever** — the local memory, the firewall, the recall, all of it. Paid plans add cloud sync across devices, encrypted snapshots, shared team memory, and support:
|
|
114
|
+
|
|
115
|
+
- **Pro** — $29/mo · cloud sync, encrypted snapshots, analytics, priority support
|
|
116
|
+
- **Team** — $199/mo · shared team memory, up to 25 seats, admin dashboard
|
|
117
|
+
- **Enterprise** — $499/mo · unlimited seats, SSO/SAML, custom SLA, on-premise option
|
|
118
|
+
|
|
119
|
+
Plans and self-serve checkout: **[account.ghosts.lk/pricing](https://account.ghosts.lk/pricing)**. Custom or on-premise, email [ryan@ghosts.lk](mailto:ryan@ghosts.lk).
|
|
120
|
+
|
|
111
121
|
## Community and feedback
|
|
112
122
|
|
|
113
123
|
Wyrm sends no telemetry, so the way we learn what is working is you telling us.
|
|
@@ -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};
|