wyrm-mcp 9.2.0 → 9.2.2

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.
Files changed (66) hide show
  1. package/README.md +2 -0
  2. package/dist/auto-runs.js +1 -0
  3. package/dist/autoconfig.js +3 -3
  4. package/dist/capabilities.js +3 -3
  5. package/dist/causality.js +13 -8
  6. package/dist/cli.js +25 -22
  7. package/dist/cloud/cli.js +3 -3
  8. package/dist/cloud/sync-daemon-entrypoint.js +2 -2
  9. package/dist/cloud/sync-daemon.js +1 -1
  10. package/dist/color.js +1 -0
  11. package/dist/database.js +3 -3
  12. package/dist/deprecations.js +2 -2
  13. package/dist/events.js +6 -6
  14. package/dist/federation.js +10 -10
  15. package/dist/handlers/arg-keys.js +1 -0
  16. package/dist/handlers/capture.js +58 -58
  17. package/dist/handlers/causality.js +8 -8
  18. package/dist/handlers/cloud.js +85 -83
  19. package/dist/handlers/companion.js +10 -10
  20. package/dist/handlers/entity.js +1 -1
  21. package/dist/handlers/events.js +12 -12
  22. package/dist/handlers/failure.js +12 -12
  23. package/dist/handlers/goals.js +4 -4
  24. package/dist/handlers/intelligence.js +63 -63
  25. package/dist/handlers/mcpclient.js +1 -1
  26. package/dist/handlers/presence.js +3 -3
  27. package/dist/handlers/project-arg.js +1 -0
  28. package/dist/handlers/project.js +1 -1
  29. package/dist/handlers/quest.js +5 -3
  30. package/dist/handlers/recall.js +18 -18
  31. package/dist/handlers/registry.js +1 -1
  32. package/dist/handlers/resources.js +1 -1
  33. package/dist/handlers/review.js +3 -3
  34. package/dist/handlers/run.js +3 -3
  35. package/dist/handlers/search.js +3 -3
  36. package/dist/handlers/session.js +24 -24
  37. package/dist/handlers/share.js +5 -5
  38. package/dist/handlers/shims.js +1 -1
  39. package/dist/handlers/thread.js +2 -2
  40. package/dist/http-auth.js +1 -1
  41. package/dist/http-fast.js +15 -15
  42. package/dist/index.js +2 -2
  43. package/dist/logger.js +2 -2
  44. package/dist/receipt.js +1 -1
  45. package/dist/rehydration.js +24 -9
  46. package/dist/render.js +3 -3
  47. package/dist/setup.js +2 -3
  48. package/dist/sqlite-busy.js +1 -1
  49. package/dist/stale-servers.js +2 -0
  50. package/dist/stdio-lifecycle.js +1 -0
  51. package/dist/storage/index.js +3 -3
  52. package/dist/tool-manifest-v2.json +1 -1
  53. package/dist/tool-manifest.json +1 -1
  54. package/dist/ui-dashboard.js +9 -8
  55. package/dist/validate.js +1 -1
  56. package/dist/vault-exec.js +4 -0
  57. package/dist/vault.js +1 -1
  58. package/dist/wyrm-cli.js +105 -142
  59. package/dist/wyrm-manifest.json +3 -3
  60. package/dist/wyrm-ui.js +14 -7
  61. package/dist/wyrm.js +2 -0
  62. package/package.json +6 -4
  63. package/scripts/hooks/wyrm-citation-audit.mjs +155 -46
  64. package/scripts/hooks/wyrm-prompt-context.mjs +300 -0
  65. package/scripts/hooks/wyrm-run-auto.mjs +148 -37
  66. package/scripts/hooks/wyrm-session-rehydrate.mjs +142 -24
package/dist/http-fast.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import z from"http";import{WyrmDB as W}from"./database.js";import{cache as h,estimateTokens as Z,truncateToTokens as ee,timed as G}from"./performance.js";import{authMiddleware as te,getAuthStatus as I,getSecurityHeaders as j,getUiNonce as re}from"./http-auth.js";import{WyrmLogger as ne}from"./logger.js";import{sanitizeFtsQuery as U,validateProjectPath as se}from"./security.js";import{readFileSync as R,existsSync as y,readdirSync as oe,realpathSync as x}from"fs";import{homedir as ae}from"os";import{dirname as q,join as S}from"path";import{fileURLToPath as ie}from"url";const $=S(q(ie(import.meta.url)),"..","ui","dragon-mark.svg");let v=null;import{getUIDashboardHTML as ce}from"./ui-dashboard.js";import{resolveBranding as k}from"./branding.js";import{verifyLicense as B,getLicenseInfo as le}from"./license.js";import{loadRevocations as de,refreshRevocations as ue}from"./revocations.js";import{rerankConfigured as pe,rerankEgressHost as me}from"./rerank.js";import{MemoryArtifacts as fe}from"./memory-artifacts.js";import{createVectorStore as Ee}from"./vectors.js";import{GroundTruths as he,computeStaleness as _e}from"./intelligence.js";import{Causality as Se}from"./causality.js";import{wireTruthAutoCascade as ye}from"./truth-cascade.js";import{FailurePatterns as ge}from"./failure-patterns.js";import{handleDaemonWrite as Te}from"./daemon-write-endpoint.js";import{retryableWriteCause as Y,busyErrorBody as J}from"./sqlite-busy.js";import{sseFrame as Oe,resolveStartCursor as K,SSE_KEEPALIVE as Re}from"./events-sse.js";import{readonlyBlocks as ve}from"./readonly-gate.js";import{resolveActorEnvelope as Ce,runWithActor as Le}from"./handlers/boundary.js";const M=parseInt(process.env.WYRM_PORT||"3333")||3333,g=process.env.WYRM_UI_READONLY==="1",be=512*1024,N=500,je=parseInt(process.env.WYRM_MAX_SSE_STREAMS||"64",10)||64,Me=parseInt(process.env.WYRM_MAX_SSE_PER_IP||"8",10)||8;let w=0;const T=new Map;let O=null,C=null,L=null,A=null;function a(){return O||(O=new W(process.env.WYRM_DB_PATH)),O}function b(){if(!C){C=new fe(a().getDatabase());try{const e=process.env.WYRM_VECTOR_PROVIDER||"auto";e!=="none"&&C.setVectorStore(Ee({provider:e},a().getDatabase()))}catch{}}return C}function Ne(){return L||(L=new he(a().getDatabase()),ye(L,new Se(a().getDatabase()))),L}function Ae(){return A||(A=new ge(a().getDatabase())),A}function De(e){const t=O;O=e,C=null,L=null,A=null;try{t?.close()}catch{}}async function Ie(e={}){de(e.publicKeyPem),await ue(e).catch(()=>{})}function Q(){const e=[],t=ae(),r=new Set;let n=[];try{n=oe(t)}catch{return e}n.sort((s,o)=>o.localeCompare(s));for(const s of n){if(s!==".wyrm"&&!s.startsWith(".wyrm-"))continue;let o;try{o=x(S(t,s))}catch{continue}if(r.has(o))continue;const d=S(o,"wyrm.db");if(!y(d))continue;r.add(o);let i="Local",l="free";try{const c=S(o,"license.json");if(y(c)){const u=JSON.parse(R(c,"utf-8")),m=B(u);i=u.license&&u.license.issued_to||i,l=m.valid?m.tier:"free"}else{const u=S(o,"cloud.json");y(u)&&(i=JSON.parse(R(u,"utf-8")).email||i)}}catch{}const p=s.replace(/^\.wyrm-?/,"")||"default";e.push({name:p,dbPath:d,account:i,tier:l})}return e}const D=new ne({level:"info"});function _(e,t,r){const n=Number.parseInt(String(e??""),10);return!Number.isFinite(n)||n<1?t:Math.min(n,r)}function P(e){const t=e==null?"":String(e);if(t)return a().getProject(t)||a().getProjectByName(t)}function E(e,t,r,n=200){const s=JSON.stringify(r),o=j(t);e.writeHead(n,{"Content-Type":"application/json","Content-Length":Buffer.byteLength(s),"X-Tokens":String(Z(r)),...o}),e.end(s)}function ke(e,t,r){const n=j(t);e.writeHead(200,{...n,"Content-Type":"text/html; charset=utf-8","Content-Length":Buffer.byteLength(r),"Cache-Control":"no-store"}),e.end(r)}function we(e){return new Promise((t,r)=>{if(e.method==="GET"){t({});return}let n="",s=0;e.on("data",o=>{if(s+=o.length,s>be){e.destroy(),r(new Error("Request body too large"));return}n+=o}),e.on("end",()=>{try{t(n?JSON.parse(n):{})}catch{r(new Error("Invalid JSON"))}}),e.on("error",r)})}const X={"GET /c":e=>{const t=`ctx:${e.p||"global"}`,r=h.get(t);if(r)return r;const n=e.p;let s;if(n){const o=a().getProject(n);if(!o)return{e:"not found"};const d=a().getPendingQuests(o.id),i=a().getRecentSessions(o.id,3);s={n:o.name,s:o.stack,q:d.length,qt:d.slice(0,5).map(l=>l.title),r:i[0]?.summary||i[0]?.notes?.slice(0,200)||null}}else{const o=a().getAllProjects(20),d=a().getAllPendingQuests();s={p:o.map(i=>({n:i.name,s:i.stack,q:a().getPendingQuests(i.id).length})),tq:d.length}}return h.set(t,s),s},"GET /p":()=>{const e=h.get("projects");if(e)return e;const r=a().getAllProjects(50).map(n=>({i:n.id,n:n.name,p:n.path,s:n.stack}));return h.set("projects",r),r},"POST /scan":e=>{const t=e.d||e.directory||process.env.HOME+"/Git Projects",r=se(t);return r?(h.invalidate(),{found:a().scanForProjects(r,!0).length}):{e:"path not allowed"}},"GET /q":e=>{const t=e.p;if(t){const r=a().getProject(t);return r?a().getPendingQuests(r.id).map(n=>({i:n.id,t:n.title,p:n.priority[0]})):{e:"not found"}}return a().getAllPendingQuests().slice(0,20).map(r=>({i:r.id,t:r.title,p:r.priority[0]}))},"POST /q":e=>{const t=e.p,r=a().getProject(t);return r?(h.invalidate("ctx"),{i:a().addQuest(r.id,e.t,e.d,e.pr||"medium").id}):{e:"not found"}},"POST /qc":e=>{const t=typeof e.i=="number"?e.i:parseInt(String(e.i),10);return!t||t<1?{e:"id required"}:(h.invalidate("ctx"),a().updateQuest(t,"completed"),{ok:1})},"POST /s":e=>{const t=e.p;let r=a().getProject(t);if(r||(a().scanForProjects(t,!1),r=a().getProject(t)),!r)return{e:"not found"};let n=a().getTodaySession(r.id);return n||(n=a().createSession(r.id,{objectives:e.o||"",notes:""})),h.invalidate("ctx"),{i:n.id,d:n.date}},"POST /su":e=>{const t=e.i;return h.invalidate("ctx"),a().updateSession(t,{notes:e.n,summary:e.s,completed:e.c}),{ok:1}},"POST /x":e=>{const t=e.p,r=a().getProject(t);return r?(a().setContext(r.id,e.k,e.v),h.invalidate("ctx"),{ok:1}):{e:"not found"}},"GET /x":e=>{const t=e.p,r=a().getProject(t);return r?a().getAllContext(r.id):{e:"not found"}},"POST /g":e=>{const t=e.k,r=e.v;return!t||typeof t!="string"?{e:"k (key) required"}:r==null?{e:"v (value) required"}:(a().setGlobalContext(t,String(r)),h.invalidate(),{ok:1})},"GET /g":()=>a().getAllGlobalContext(),"GET /s":e=>{const t=e.q;if(!t)return{e:"query required"};const r=U(t);return{q:a().searchQuests(r).slice(0,5).map(s=>({i:s.id,t:s.title})),s:a().searchSessions(r).slice(0,3).map(s=>({i:s.id,d:s.date})),p:a().searchProjects(r).slice(0,3).map(s=>({n:s.name,p:s.path}))}},"POST /d":e=>{const t=e.p,r=a().getProject(t);return r?{i:a().insertData(r.id,e.c,e.k,e.v,e.m).id}:{e:"not found"}},"GET /d":e=>{const t=e.p,r=a().getProject(t);if(!r)return{e:"not found"};const n=_(e.l,20,100);return a().queryData(r.id,e.c,n).map(s=>({k:s.key,v:ee(s.value,100)}))},"GET /d/search":e=>{const t=e.p,r=a().getProject(t);if(!r)return{e:"not found"};const n=e.q;if(!n)return{e:"q (query) required"};const s=e.c,o=_(e.l,10,100);let d=a().searchData(n,r.id);return s&&(d=d.filter(i=>i.category===s)),d.slice(0,o).map(i=>({k:i.key,v:i.value,c:i.category,m:i.metadata}))},"GET /d/agg":e=>{const t=e.p,r=a().getProject(t);if(!r)return{e:"not found"};const n=e.c;if(!n)return{e:"c (category) required"};const s=e.stack_key,o=e.scanner,d=_(e.l,1e3,1e4),i={};for(const l of a().queryData(r.id,n,d)){let p;try{p=JSON.parse(l.value)}catch{continue}if(s&&p.stack_key!==s||o&&p.scanner!==o)continue;const c=String(p.scanner??""),u=String(p.payload_hash??"");if(!c||!u)continue;const m=`${c}:${u}`,f=i[m]??{s:c,ph:u,sk:String(p.stack_key??""),h:0,t:0};f.t+=1,p.hit&&(f.h+=1),i[m]=f}return Object.values(i).map(l=>({...l,r:l.t>0?l.h/l.t:0})).sort((l,p)=>p.r-l.r||p.h-l.h)},"POST /batch":e=>{const t=e.ops;if(!t||!Array.isArray(t))return{e:"ops required"};if(t.length>N)return{e:`max ${N} ops per batch`};const r=performance.now();return{r:t.map(s=>{const o=`${s.m} ${s.r}`,d=X[o];if(!d)return{e:"unknown"};try{return{d:d(s.a||{})}}catch{return{e:"op failed"}}}),ms:Math.round(performance.now()-r)}},"POST /write":e=>Te({db:a(),artifacts:b(),truths:Ne(),failures:Ae()},e),"GET /syms":e=>{const t=String(e.q??"").slice(0,200);if(!t)return[];const r=_(e.limit,20,200),n=a().getDatabase();try{return n.prepare(`
2
+ import V from"http";import{WyrmDB as W}from"./database.js";import{cache as h,estimateTokens as z,truncateToTokens as Z,timed as U}from"./performance.js";import{authMiddleware as ee,getAuthStatus as A,getSecurityHeaders as k,getUiNonce as te}from"./http-auth.js";import{WyrmLogger as re}from"./logger.js";import{sanitizeFtsQuery as G,validateProjectPath as ne}from"./security.js";import{readFileSync as R,existsSync as y,readdirSync as se,realpathSync as x}from"fs";import{homedir as oe}from"os";import{dirname as q,join as S}from"path";import{fileURLToPath as ae}from"url";let v=null;function ie(){if(v!==null)return v;v="unknown";try{const e=q(ae(import.meta.url));for(const t of[S(e,"..","package.json"),S(e,"..","..","package.json")]){if(!y(t))continue;const r=JSON.parse(R(t,"utf-8")).version;if(typeof r=="string"){v=r;break}}}catch{}return v}import{getUIDashboardHTML as ce}from"./ui-dashboard.js";import{resolveBranding as I}from"./branding.js";import{verifyLicense as $,getLicenseInfo as le}from"./license.js";import{loadRevocations as ue,refreshRevocations as de}from"./revocations.js";import{rerankConfigured as pe,rerankEgressHost as me}from"./rerank.js";import{MemoryArtifacts as fe}from"./memory-artifacts.js";import{createVectorStore as Ee}from"./vectors.js";import{GroundTruths as he,computeStaleness as _e}from"./intelligence.js";import{Causality as Se}from"./causality.js";import{wireTruthAutoCascade as ye}from"./truth-cascade.js";import{FailurePatterns as ge}from"./failure-patterns.js";import{handleDaemonWrite as Te}from"./daemon-write-endpoint.js";import{retryableWriteCause as Y,busyErrorBody as B}from"./sqlite-busy.js";import{sseFrame as Oe,resolveStartCursor as J,SSE_KEEPALIVE as Re}from"./events-sse.js";import{readonlyBlocks as ve}from"./readonly-gate.js";import{resolveActorEnvelope as Ce,runWithActor as Le}from"./handlers/boundary.js";function be(e=process.env){for(const t of[e.WYRM_PORT,e.WYRM_HTTP_PORT]){if(t===void 0||t.trim()==="")continue;const r=Number(t);if(Number.isInteger(r)&&r>=1&&r<=65535)return r}return 3333}const je=/^(?:(?:0+\.){3}0+|::)$/;function Me(e,t){const r=e===""||je.test(e)?"127.0.0.1":e;return`http://${r.includes(":")?`[${r}]`:r}:${t}/ui`}const C=be(),g=process.env.WYRM_UI_READONLY==="1",Ne=512*1024,M=500,De=parseInt(process.env.WYRM_MAX_SSE_STREAMS||"64",10)||64,Ae=parseInt(process.env.WYRM_MAX_SSE_PER_IP||"8",10)||8;let w=0;const T=new Map;let O=null,L=null,b=null,N=null;function a(){return O||(O=new W(process.env.WYRM_DB_PATH)),O}function j(){if(!L){L=new fe(a().getDatabase());try{const e=process.env.WYRM_VECTOR_PROVIDER||"auto";e!=="none"&&L.setVectorStore(Ee({provider:e},a().getDatabase()))}catch{}}return L}function ke(){return b||(b=new he(a().getDatabase()),ye(b,new Se(a().getDatabase()))),b}function Ie(){return N||(N=new ge(a().getDatabase())),N}function we(e){const t=O;O=e,L=null,b=null,N=null;try{t?.close()}catch{}}async function Pe(e={}){ue(e.publicKeyPem),await de(e).catch(()=>{})}function K(){const e=[],t=oe(),r=new Set;let n=[];try{n=se(t)}catch{return e}n.sort((s,o)=>o.localeCompare(s));for(const s of n){if(s!==".wyrm"&&!s.startsWith(".wyrm-"))continue;let o;try{o=x(S(t,s))}catch{continue}if(r.has(o))continue;const u=S(o,"wyrm.db");if(!y(u))continue;r.add(o);let i="Local",l="free";try{const c=S(o,"license.json");if(y(c)){const d=JSON.parse(R(c,"utf-8")),m=$(d);i=d.license&&d.license.issued_to||i,l=m.valid?m.tier:"free"}else{const d=S(o,"cloud.json");y(d)&&(i=JSON.parse(R(d,"utf-8")).email||i)}}catch{}const p=s.replace(/^\.wyrm-?/,"")||"default";e.push({name:p,dbPath:u,account:i,tier:l})}return e}const D=new re({level:"info"});function _(e,t,r){const n=Number.parseInt(String(e??""),10);return!Number.isFinite(n)||n<1?t:Math.min(n,r)}function P(e){const t=e==null?"":String(e);if(t)return a().getProject(t)||a().getProjectByName(t)}function E(e,t,r,n=200){const s=JSON.stringify(r),o=k(t);e.writeHead(n,{"Content-Type":"application/json","Content-Length":Buffer.byteLength(s),"X-Tokens":String(z(r)),...o}),e.end(s)}function Fe(e,t,r){const n=k(t);e.writeHead(200,{...n,"Content-Type":"text/html; charset=utf-8","Content-Length":Buffer.byteLength(r),"Cache-Control":"no-store"}),e.end(r)}function He(e){return new Promise((t,r)=>{if(e.method==="GET"){t({});return}let n="",s=0;e.on("data",o=>{if(s+=o.length,s>Ne){e.destroy(),r(new Error("Request body too large"));return}n+=o}),e.on("end",()=>{try{t(n?JSON.parse(n):{})}catch{r(new Error("Invalid JSON"))}}),e.on("error",r)})}const Q={"GET /c":e=>{const t=`ctx:${e.p||"global"}`,r=h.get(t);if(r)return r;const n=e.p;let s;if(n){const o=a().getProject(n);if(!o)return{e:"not found"};const u=a().getPendingQuests(o.id),i=a().getRecentSessions(o.id,3);s={n:o.name,s:o.stack,q:u.length,qt:u.slice(0,5).map(l=>l.title),r:i[0]?.summary||i[0]?.notes?.slice(0,200)||null}}else{const o=a().getAllProjects(20),u=a().getAllPendingQuests();s={p:o.map(i=>({n:i.name,s:i.stack,q:a().getPendingQuests(i.id).length})),tq:u.length}}return h.set(t,s),s},"GET /p":()=>{const e=h.get("projects");if(e)return e;const r=a().getAllProjects(50).map(n=>({i:n.id,n:n.name,p:n.path,s:n.stack}));return h.set("projects",r),r},"POST /scan":e=>{const t=e.d||e.directory||process.env.HOME+"/Git Projects",r=ne(t);return r?(h.invalidate(),{found:a().scanForProjects(r,!0).length}):{e:"path not allowed"}},"GET /q":e=>{const t=e.p;if(t){const r=a().getProject(t);return r?a().getPendingQuests(r.id).map(n=>({i:n.id,t:n.title,p:n.priority[0]})):{e:"not found"}}return a().getAllPendingQuests().slice(0,20).map(r=>({i:r.id,t:r.title,p:r.priority[0]}))},"POST /q":e=>{const t=e.p,r=a().getProject(t);return r?(h.invalidate("ctx"),{i:a().addQuest(r.id,e.t,e.d,e.pr||"medium").id}):{e:"not found"}},"POST /qc":e=>{const t=typeof e.i=="number"?e.i:parseInt(String(e.i),10);return!t||t<1?{e:"id required"}:(h.invalidate("ctx"),a().updateQuest(t,"completed"),{ok:1})},"POST /s":e=>{const t=e.p;let r=a().getProject(t);if(r||(a().scanForProjects(t,!1),r=a().getProject(t)),!r)return{e:"not found"};let n=a().getTodaySession(r.id);return n||(n=a().createSession(r.id,{objectives:e.o||"",notes:""})),h.invalidate("ctx"),{i:n.id,d:n.date}},"POST /su":e=>{const t=e.i;return h.invalidate("ctx"),a().updateSession(t,{notes:e.n,summary:e.s,completed:e.c}),{ok:1}},"POST /x":e=>{const t=e.p,r=a().getProject(t);return r?(a().setContext(r.id,e.k,e.v),h.invalidate("ctx"),{ok:1}):{e:"not found"}},"GET /x":e=>{const t=e.p,r=a().getProject(t);return r?a().getAllContext(r.id):{e:"not found"}},"POST /g":e=>{const t=e.k,r=e.v;return!t||typeof t!="string"?{e:"k (key) required"}:r==null?{e:"v (value) required"}:(a().setGlobalContext(t,String(r)),h.invalidate(),{ok:1})},"GET /g":()=>a().getAllGlobalContext(),"GET /s":e=>{const t=e.q;if(!t)return{e:"query required"};const r=G(t);return{q:a().searchQuests(r).slice(0,5).map(s=>({i:s.id,t:s.title})),s:a().searchSessions(r).slice(0,3).map(s=>({i:s.id,d:s.date})),p:a().searchProjects(r).slice(0,3).map(s=>({n:s.name,p:s.path}))}},"POST /d":e=>{const t=e.p,r=a().getProject(t);return r?{i:a().insertData(r.id,e.c,e.k,e.v,e.m).id}:{e:"not found"}},"GET /d":e=>{const t=e.p,r=a().getProject(t);if(!r)return{e:"not found"};const n=_(e.l,20,100);return a().queryData(r.id,e.c,n).map(s=>({k:s.key,v:Z(s.value,100)}))},"GET /d/search":e=>{const t=e.p,r=a().getProject(t);if(!r)return{e:"not found"};const n=e.q;if(!n)return{e:"q (query) required"};const s=e.c,o=_(e.l,10,100);let u=a().searchData(n,r.id);return s&&(u=u.filter(i=>i.category===s)),u.slice(0,o).map(i=>({k:i.key,v:i.value,c:i.category,m:i.metadata}))},"GET /d/agg":e=>{const t=e.p,r=a().getProject(t);if(!r)return{e:"not found"};const n=e.c;if(!n)return{e:"c (category) required"};const s=e.stack_key,o=e.scanner,u=_(e.l,1e3,1e4),i={};for(const l of a().queryData(r.id,n,u)){let p;try{p=JSON.parse(l.value)}catch{continue}if(s&&p.stack_key!==s||o&&p.scanner!==o)continue;const c=String(p.scanner??""),d=String(p.payload_hash??"");if(!c||!d)continue;const m=`${c}:${d}`,f=i[m]??{s:c,ph:d,sk:String(p.stack_key??""),h:0,t:0};f.t+=1,p.hit&&(f.h+=1),i[m]=f}return Object.values(i).map(l=>({...l,r:l.t>0?l.h/l.t:0})).sort((l,p)=>p.r-l.r||p.h-l.h)},"POST /batch":e=>{const t=e.ops;if(!t||!Array.isArray(t))return{e:"ops required"};if(t.length>M)return{e:`max ${M} ops per batch`};const r=performance.now();return{r:t.map(s=>{const o=`${s.m} ${s.r}`,u=Q[o];if(!u)return{e:"unknown"};try{return{d:u(s.a||{})}}catch{return{e:"op failed"}}}),ms:Math.round(performance.now()-r)}},"POST /write":e=>Te({db:a(),artifacts:j(),truths:ke(),failures:Ie()},e),"GET /syms":e=>{const t=String(e.q??"").slice(0,200);if(!t)return[];const r=_(e.limit,20,200),n=a().getDatabase();try{return n.prepare(`
3
3
  SELECT symbol, kind, language, file_path, line, signature, project_id
4
4
  FROM symbol_index
5
5
  WHERE symbol LIKE ?
@@ -19,13 +19,13 @@ import z from"http";import{WyrmDB as W}from"./database.js";import{cache as h,est
19
19
  AND (key LIKE ? OR value LIKE ? OR rationale LIKE ?)
20
20
  ORDER BY confidence DESC
21
21
  LIMIT ?
22
- `).all(`%${t}%`,`%${t}%`,`%${t}%`,r)}catch{return[]}},"GET /routing":e=>{const t=String(e.task_type??e.t??"").slice(0,200).trim();if(!t)return{e:"task_type required"};const r=_(e.limit,10,100);let n;const s=e.p;if(s){const i=a().getProject(s);if(!i)return{e:"not found"};n=i.id}const o=e.since_days!=null?Number(e.since_days):void 0;return a().recallRouting(t,{projectId:n,limit:r,sinceDays:Number.isFinite(o)?o:void 0}).map(i=>({m:i.model_id,tools:i.tool_names,runs:i.runs,ok:i.successes,fail:i.failures,rate:Math.round(i.success_rate*1e3)/1e3,ms:i.avg_latency_ms,last:i.last_ts}))},"POST /routing":e=>{const t=String(e.task_type??"").slice(0,200).trim(),r=String(e.model_id??"").slice(0,200).trim();if(!t)return{e:"task_type required"};if(!r)return{e:"model_id required"};if(e.success===void 0||e.success===null)return{e:"success required"};let n;const s=e.p;if(s){const l=a().getProject(s);l&&(n=l.id)}const o=Array.isArray(e.tool_names)?e.tool_names.map(l=>String(l)):e.tool_names!=null?String(e.tool_names):null,d=e.latency_ms!=null?Number(e.latency_ms):null,i=e.success===!0||e.success===1||e.success==="1"||e.success==="true";try{return{i:a().recordRouting({projectId:n,taskType:t,modelId:r,toolNames:o,success:i,latencyMs:Number.isFinite(d)?d:null})}}catch(l){return{e:l.message}}},"GET /audit":e=>{const t=_(e.limit,50,500),r=e.kind,n=a().getDatabase();try{return r?n.prepare("SELECT * FROM audit_log WHERE event_kind = ? ORDER BY id DESC LIMIT ?").all(r,t):n.prepare("SELECT * FROM audit_log ORDER BY id DESC LIMIT ?").all(t)}catch{return[]}},"GET /sync/push":e=>{const t=e.since,r=_(e.limit,500,5e3),n=a().getDatabase(),s=[],o=t??"1970-01-01",d=[["session","sessions","created_at"],["quest","quests","created_at"],["truth","ground_truths","updated_at"],["artifact","memory_artifacts","last_accessed_at"],["edge","decision_edges","created_at"]],i=(()=>{try{return n.prepare("PRAGMA table_info(projects)").all().some(p=>p.name==="sync_policy")?"AND (project_id IS NULL OR project_id IN (SELECT id FROM projects WHERE sync_policy = 'team'))":""}catch{return""}})();for(const[l,p,c]of d){if(s.length>=r)break;try{const u=n.prepare(`SELECT * FROM ${p}
22
+ `).all(`%${t}%`,`%${t}%`,`%${t}%`,r)}catch{return[]}},"GET /routing":e=>{const t=String(e.task_type??e.t??"").slice(0,200).trim();if(!t)return{e:"task_type required"};const r=_(e.limit,10,100);let n;const s=e.p;if(s){const i=a().getProject(s);if(!i)return{e:"not found"};n=i.id}const o=e.since_days!=null?Number(e.since_days):void 0;return a().recallRouting(t,{projectId:n,limit:r,sinceDays:Number.isFinite(o)?o:void 0}).map(i=>({m:i.model_id,tools:i.tool_names,runs:i.runs,ok:i.successes,fail:i.failures,rate:Math.round(i.success_rate*1e3)/1e3,ms:i.avg_latency_ms,last:i.last_ts}))},"POST /routing":e=>{const t=String(e.task_type??"").slice(0,200).trim(),r=String(e.model_id??"").slice(0,200).trim();if(!t)return{e:"task_type required"};if(!r)return{e:"model_id required"};if(e.success===void 0||e.success===null)return{e:"success required"};let n;const s=e.p;if(s){const l=a().getProject(s);l&&(n=l.id)}const o=Array.isArray(e.tool_names)?e.tool_names.map(l=>String(l)):e.tool_names!=null?String(e.tool_names):null,u=e.latency_ms!=null?Number(e.latency_ms):null,i=e.success===!0||e.success===1||e.success==="1"||e.success==="true";try{return{i:a().recordRouting({projectId:n,taskType:t,modelId:r,toolNames:o,success:i,latencyMs:Number.isFinite(u)?u:null})}}catch(l){return{e:l.message}}},"GET /audit":e=>{const t=_(e.limit,50,500),r=e.kind,n=a().getDatabase();try{return r?n.prepare("SELECT * FROM audit_log WHERE event_kind = ? ORDER BY id DESC LIMIT ?").all(r,t):n.prepare("SELECT * FROM audit_log ORDER BY id DESC LIMIT ?").all(t)}catch{return[]}},"GET /sync/push":e=>{const t=e.since,r=_(e.limit,500,5e3),n=a().getDatabase(),s=[],o=t??"1970-01-01",u=[["session","sessions","created_at"],["quest","quests","created_at"],["truth","ground_truths","updated_at"],["artifact","memory_artifacts","last_accessed_at"],["edge","decision_edges","created_at"]],i=(()=>{try{return n.prepare("PRAGMA table_info(projects)").all().some(p=>p.name==="sync_policy")?"AND (project_id IS NULL OR project_id IN (SELECT id FROM projects WHERE sync_policy = 'team'))":""}catch{return""}})();for(const[l,p,c]of u){if(s.length>=r)break;try{const d=n.prepare(`SELECT * FROM ${p}
23
23
  WHERE is_shared = 1 ${i} AND ${c} > ?
24
24
  ORDER BY ${c} ASC
25
- LIMIT ?`).all(o,Math.max(1,r-s.length));for(const m of u)s.push({kind:l,id:m.id,project_id:m.project_id??null,updated_at:m[c]??null,payload:m})}catch{}}return{rows:s,count:s.length,cursor:new Date().toISOString()}},"GET /events":e=>{if(!a().liveMemoryEnabled())return{e:"live memory disabled",disabled:1};const t=P(e.project??e.p);if(!t)return{e:"not found"};const r=K(void 0,e.since),n=_(e.limit??e.l,100,1e3),o=e.shared==="1"||e.shared==="true"?a().eventsForPush(t.id,r,n):a().eventsSince(t.id,r,n),d=o.length?o[o.length-1].cursor:r;return{project:t.name,cursor:d,count:o.length,events:o}},"POST /events":e=>{if(!a().liveMemoryEnabled())return{e:"live memory disabled",disabled:1};const t=P(e.project??e.p);if(!t)return{e:"not found"};const r=Array.isArray(e.events)?e.events:e.event?[e.event]:[];if(r.length===0)return{e:"events[] required"};if(r.length>N)return{e:`max ${N} events per request`};let n=0,s=0,o=0;for(const d of r){const i=a().ingestRemoteEvent(t.id,d);i==="inserted"?n++:i==="echo"?o++:s++}return n>0&&h.invalidate("ctx"),{project:t.name,inserted:n,duplicate:s,echo:o}},"GET /stats":()=>{const{result:e,ms:t}=G(()=>a().getStats());return{...e,ms:t,cache:h.stats()}},"GET /health":async e=>{const t={ok:1,ts:Date.now()};if(!/^(1|true|yes)$/i.test(String(e.check_dependencies??"")))return t;const r={...t};try{const s=a().getDatabase().prepare("SELECT MAX(version) v FROM schema_versions").get().v;r.db={ok:1,migration:s}}catch{r.ok=0,r.db={ok:0}}try{const n=b().getVectorStore();if(n){const s=n.getProvider(),o=n.indexCoverage();r.vectors={provider:s.name,model:s.model,ready:await s.isReady(),indexed:o.activeCount,stale:o.stale?1:0,...o.stale?{indexed_under:Object.keys(o.otherModels),hint:"run wyrm_reindex"}:{},egress:s.remoteHost??"none"}}else r.vectors={provider:"none",ready:!1}}catch{r.vectors={ok:0}}return r.rerank={configured:pe()?1:0,provider:(process.env.WYRM_RERANK_PROVIDER||"llamacpp").trim()||"llamacpp",egress:me()??"none"},r},"GET /auth/status":()=>{const e=I();return{auth:e.requireAuth?1:0,origins:e.allowedOrigins.length}},"GET /ui/stats":()=>{const e=a().getDatabase(),t=e.prepare("SELECT COUNT(*) as c FROM projects").get().c,r=e.prepare("SELECT COUNT(*) as c FROM sessions").get().c,n=e.prepare("SELECT COUNT(*) as c FROM quests WHERE status IN ('pending','in_progress')").get().c,s=e.prepare("SELECT COUNT(*) as c FROM data_lake").get().c,o=e.prepare("SELECT COUNT(*) as c FROM memory_artifacts WHERE needs_review = 0").get().c,d=e.prepare("SELECT COUNT(*) as c FROM memory_artifacts WHERE needs_review = 1").get().c,i=e.prepare("SELECT COUNT(*) as c FROM ground_truths WHERE is_current = 1").get().c,l=e.prepare(`
25
+ LIMIT ?`).all(o,Math.max(1,r-s.length));for(const m of d)s.push({kind:l,id:m.id,project_id:m.project_id??null,updated_at:m[c]??null,payload:m})}catch{}}return{rows:s,count:s.length,cursor:new Date().toISOString()}},"GET /events":e=>{if(!a().liveMemoryEnabled())return{e:"live memory disabled",disabled:1};const t=P(e.project??e.p);if(!t)return{e:"not found"};const r=J(void 0,e.since),n=_(e.limit??e.l,100,1e3),o=e.shared==="1"||e.shared==="true"?a().eventsForPush(t.id,r,n):a().eventsSince(t.id,r,n),u=o.length?o[o.length-1].cursor:r;return{project:t.name,cursor:u,count:o.length,events:o}},"POST /events":e=>{if(!a().liveMemoryEnabled())return{e:"live memory disabled",disabled:1};const t=P(e.project??e.p);if(!t)return{e:"not found"};const r=Array.isArray(e.events)?e.events:e.event?[e.event]:[];if(r.length===0)return{e:"events[] required"};if(r.length>M)return{e:`max ${M} events per request`};let n=0,s=0,o=0;for(const u of r){const i=a().ingestRemoteEvent(t.id,u);i==="inserted"?n++:i==="echo"?o++:s++}return n>0&&h.invalidate("ctx"),{project:t.name,inserted:n,duplicate:s,echo:o}},"GET /stats":()=>{const{result:e,ms:t}=U(()=>a().getStats());return{...e,ms:t,cache:h.stats()}},"GET /health":async e=>{const t={ok:1,ts:Date.now()};if(!/^(1|true|yes)$/i.test(String(e.check_dependencies??"")))return t;const r={...t};try{const s=a().getDatabase().prepare("SELECT MAX(version) v FROM schema_versions").get().v;r.db={ok:1,migration:s}}catch{r.ok=0,r.db={ok:0}}try{const n=j().getVectorStore();if(n){const s=n.getProvider(),o=n.indexCoverage();r.vectors={provider:s.name,model:s.model,ready:await s.isReady(),indexed:o.activeCount,stale:o.stale?1:0,...o.stale?{indexed_under:Object.keys(o.otherModels),hint:"run wyrm_reindex"}:{},egress:s.remoteHost??"none"}}else r.vectors={provider:"none",ready:!1}}catch{r.vectors={ok:0}}return r.rerank={configured:pe()?1:0,provider:(process.env.WYRM_RERANK_PROVIDER||"llamacpp").trim()||"llamacpp",egress:me()??"none"},r},"GET /auth/status":()=>{const e=A();return{auth:e.requireAuth?1:0,origins:e.allowedOrigins.length}},"GET /ui/stats":()=>{const e=a().getDatabase(),t=e.prepare("SELECT COUNT(*) as c FROM projects").get().c,r=e.prepare("SELECT COUNT(*) as c FROM sessions").get().c,n=e.prepare("SELECT COUNT(*) as c FROM quests WHERE status IN ('pending','in_progress')").get().c,s=e.prepare("SELECT COUNT(*) as c FROM data_lake").get().c,o=e.prepare("SELECT COUNT(*) as c FROM memory_artifacts WHERE needs_review = 0").get().c,u=e.prepare("SELECT COUNT(*) as c FROM memory_artifacts WHERE needs_review = 1").get().c,i=e.prepare("SELECT COUNT(*) as c FROM ground_truths WHERE is_current = 1").get().c,l=e.prepare(`
26
26
  SELECT date, summary, objectives FROM sessions
27
27
  ORDER BY created_at DESC LIMIT 8
28
- `).all();return{projects:t,sessions:r,active_quests:n,data_points:s,artifacts:o,review_queue:d,truths:i,recent_sessions:l}},"GET /ui/memories":e=>{const t=a().getDatabase(),r=Math.max(1,parseInt(String(e.page||"1"),10)),n=Math.min(100,Math.max(1,parseInt(String(e.limit||"20"),10))),s=e.kind?String(e.kind):"",o=e.search?String(e.search):"",d=(r-1)*n;let i,l,p,c;if(o){const f=U(o);s?(i=`
28
+ `).all();return{projects:t,sessions:r,active_quests:n,data_points:s,artifacts:o,review_queue:u,truths:i,recent_sessions:l}},"GET /ui/memories":e=>{const t=a().getDatabase(),r=Math.max(1,parseInt(String(e.page||"1"),10)),n=Math.min(100,Math.max(1,parseInt(String(e.limit||"20"),10))),s=e.kind?String(e.kind):"",o=e.search?String(e.search):"",u=(r-1)*n;let i,l,p,c;if(o){const f=G(o);s?(i=`
29
29
  SELECT ma.*, p.name AS project_name
30
30
  FROM memory_artifacts ma
31
31
  JOIN memory_artifacts_fts fts ON fts.rowid = ma.id
@@ -36,7 +36,7 @@ import z from"http";import{WyrmDB as W}from"./database.js";import{cache as h,est
36
36
  SELECT COUNT(*) as c FROM memory_artifacts ma
37
37
  JOIN memory_artifacts_fts fts ON fts.rowid = ma.id
38
38
  WHERE memory_artifacts_fts MATCH ? AND ma.kind = ?
39
- AND ma.supersedes_id IS NULL`,p=[f,s,n,d],c=[f,s]):(i=`
39
+ AND ma.supersedes_id IS NULL`,p=[f,s,n,u],c=[f,s]):(i=`
40
40
  SELECT ma.*, p.name AS project_name
41
41
  FROM memory_artifacts ma
42
42
  JOIN memory_artifacts_fts fts ON fts.rowid = ma.id
@@ -45,37 +45,37 @@ import z from"http";import{WyrmDB as W}from"./database.js";import{cache as h,est
45
45
  ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,l=`
46
46
  SELECT COUNT(*) as c FROM memory_artifacts ma
47
47
  JOIN memory_artifacts_fts fts ON fts.rowid = ma.id
48
- WHERE memory_artifacts_fts MATCH ? AND ma.supersedes_id IS NULL`,p=[f,n,d],c=[f])}else s?(i=`
48
+ WHERE memory_artifacts_fts MATCH ? AND ma.supersedes_id IS NULL`,p=[f,n,u],c=[f])}else s?(i=`
49
49
  SELECT ma.*, p.name AS project_name
50
50
  FROM memory_artifacts ma
51
51
  LEFT JOIN projects p ON ma.project_id = p.id
52
52
  WHERE ma.kind = ? AND ma.supersedes_id IS NULL
53
- ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,l="SELECT COUNT(*) as c FROM memory_artifacts WHERE kind = ? AND supersedes_id IS NULL",p=[s,n,d],c=[s]):(i=`
53
+ ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,l="SELECT COUNT(*) as c FROM memory_artifacts WHERE kind = ? AND supersedes_id IS NULL",p=[s,n,u],c=[s]):(i=`
54
54
  SELECT ma.*, p.name AS project_name
55
55
  FROM memory_artifacts ma
56
56
  LEFT JOIN projects p ON ma.project_id = p.id
57
57
  WHERE ma.supersedes_id IS NULL
58
- ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,l="SELECT COUNT(*) as c FROM memory_artifacts WHERE supersedes_id IS NULL",p=[n,d],c=[]);const u=t.prepare(i).all(...p),m=t.prepare(l).get(...c).c;return{items:u,total:m,page:r,limit:n}},"GET /ui/quests":()=>{const t=a().getDatabase().prepare(`
58
+ ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,l="SELECT COUNT(*) as c FROM memory_artifacts WHERE supersedes_id IS NULL",p=[n,u],c=[]);const d=t.prepare(i).all(...p),m=t.prepare(l).get(...c).c;return{items:d,total:m,page:r,limit:n}},"GET /ui/quests":()=>{const t=a().getDatabase().prepare(`
59
59
  SELECT q.id, q.title, q.status, q.priority, p.name AS project_name
60
60
  FROM quests q
61
61
  LEFT JOIN projects p ON q.project_id = p.id
62
62
  ORDER BY q.created_at DESC
63
- `).all(),r={pending:[],in_progress:[],completed:[],abandoned:[]};for(const n of t)r[n.status]&&r[n.status].push(n);return r},"GET /ui/warroom":()=>{const e=a().getDatabase(),t=(c,...u)=>{try{const m=e.prepare(c).get(...u);return m?Object.values(m)[0]??0:0}catch{return 0}},r=(c,...u)=>{try{return e.prepare(c).all(...u)}catch{return[]}},n=k(!1).fleetGrove,o=(()=>{try{return e.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(n)}catch{return}})()?.id??-1,d=r("SELECT agent_id, agent_kind, last_heartbeat, ttl_seconds, role FROM agent_presence ORDER BY last_heartbeat DESC LIMIT 24").map(c=>({agent:c.agent_id,kind:c.agent_kind,role:c.role,last:c.last_heartbeat,alive:(()=>{try{const u=(Date.now()-new Date(c.last_heartbeat.replace(" ","T")+"Z").getTime())/1e3;return u>=0&&u<(c.ttl_seconds||300)}catch{return!1}})()})),i={findings:t("SELECT COUNT(*) n FROM quests WHERE project_id = ? AND status = ?",o,"pending")+t("SELECT COUNT(*) n FROM failure_patterns WHERE project_id = ? AND resolved = 0",o),claimed:t("SELECT COUNT(*) n FROM quests WHERE project_id = ? AND agent_id IS NOT NULL AND status IN ('pending','in_progress')",o),fixed:t("SELECT COUNT(*) n FROM quests WHERE project_id = ? AND status = 'completed'",o)+t("SELECT COUNT(*) n FROM memory_artifacts WHERE project_id = ? AND needs_review = 0 AND tags LIKE '%receipt%'",o),verified:t("SELECT COUNT(*) n FROM memory_artifacts WHERE project_id = ? AND needs_review = 0 AND tags LIKE '%verdict%'",o)},l=[];for(const c of r("SELECT id, title, status, agent_id, COALESCE(updated_at, created_at) AS ts, COALESCE(description, '') AS description FROM quests WHERE project_id = ?",o))l.push({type:"request",id:c.id,title:c.title,status:c.status,agent:c.agent_id,ts:c.ts,detail:String(c.description).slice(0,240)});for(const c of r("SELECT id, COALESCE(problem,'') AS problem, COALESCE(validated_fix,'') AS validated_fix, COALESCE(tags,'') AS tags, created_at FROM memory_artifacts WHERE project_id = ? AND needs_review = 0 AND tags LIKE '%warroom%'",o)){const u=String(c.tags).includes("verdict")?"verdict":String(c.tags).includes("receipt")?"receipt":"note";l.push({type:u,id:c.id,title:String(c.problem).slice(0,120),status:"",agent:null,ts:c.created_at,detail:String(c.validated_fix).slice(0,240)})}for(const c of r("SELECT id, scope, target, COALESCE(description,'') AS description, last_seen, resolved FROM failure_patterns WHERE project_id = ?",o))l.push({type:"finding",id:c.id,title:`[${c.scope}] ${c.target}`,status:c.resolved?"resolved":"open",agent:null,ts:c.last_seen,detail:String(c.description).slice(0,240)});l.sort((c,u)=>String(u.ts).localeCompare(String(c.ts)));const p={failure_blocks:t("SELECT COUNT(*) n FROM failure_blocks"),tokens_saved:t("SELECT COALESCE(SUM(estimated_tokens),0) n FROM token_savings_log"),rows_shared:t("SELECT COUNT(*) n FROM memory_artifacts WHERE project_id = ? AND is_shared = 1",o)+t("SELECT COUNT(*) n FROM quests WHERE project_id = ? AND is_shared = 1",o)};return{grove:n,found:o!==-1,presence:d,loop:i,metrics:p,feed:l.slice(0,40)}},"GET /ui/truths":e=>{const t=a().getDatabase(),r=Math.max(1,parseInt(String(e.page||"1"),10)),n=Math.min(100,Math.max(1,parseInt(String(e.limit||"20"),10))),s=(r-1)*n,o=t.prepare(`
63
+ `).all(),r={pending:[],in_progress:[],completed:[],abandoned:[]};for(const n of t)r[n.status]&&r[n.status].push(n);return r},"GET /ui/warroom":()=>{const e=a().getDatabase(),t=(c,...d)=>{try{const m=e.prepare(c).get(...d);return m?Object.values(m)[0]??0:0}catch{return 0}},r=(c,...d)=>{try{return e.prepare(c).all(...d)}catch{return[]}},n=I(!1).fleetGrove,o=(()=>{try{return e.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(n)}catch{return}})()?.id??-1,u=r("SELECT agent_id, agent_kind, last_heartbeat, ttl_seconds, role FROM agent_presence ORDER BY last_heartbeat DESC LIMIT 24").map(c=>({agent:c.agent_id,kind:c.agent_kind,role:c.role,last:c.last_heartbeat,alive:(()=>{try{const d=(Date.now()-new Date(c.last_heartbeat.replace(" ","T")+"Z").getTime())/1e3;return d>=0&&d<(c.ttl_seconds||300)}catch{return!1}})()})),i={findings:t("SELECT COUNT(*) n FROM quests WHERE project_id = ? AND status = ?",o,"pending")+t("SELECT COUNT(*) n FROM failure_patterns WHERE project_id = ? AND resolved = 0",o),claimed:t("SELECT COUNT(*) n FROM quests WHERE project_id = ? AND agent_id IS NOT NULL AND status IN ('pending','in_progress')",o),fixed:t("SELECT COUNT(*) n FROM quests WHERE project_id = ? AND status = 'completed'",o)+t("SELECT COUNT(*) n FROM memory_artifacts WHERE project_id = ? AND needs_review = 0 AND tags LIKE '%receipt%'",o),verified:t("SELECT COUNT(*) n FROM memory_artifacts WHERE project_id = ? AND needs_review = 0 AND tags LIKE '%verdict%'",o)},l=[];for(const c of r("SELECT id, title, status, agent_id, COALESCE(updated_at, created_at) AS ts, COALESCE(description, '') AS description FROM quests WHERE project_id = ?",o))l.push({type:"request",id:c.id,title:c.title,status:c.status,agent:c.agent_id,ts:c.ts,detail:String(c.description).slice(0,240)});for(const c of r("SELECT id, COALESCE(problem,'') AS problem, COALESCE(validated_fix,'') AS validated_fix, COALESCE(tags,'') AS tags, created_at FROM memory_artifacts WHERE project_id = ? AND needs_review = 0 AND tags LIKE '%warroom%'",o)){const d=String(c.tags).includes("verdict")?"verdict":String(c.tags).includes("receipt")?"receipt":"note";l.push({type:d,id:c.id,title:String(c.problem).slice(0,120),status:"",agent:null,ts:c.created_at,detail:String(c.validated_fix).slice(0,240)})}for(const c of r("SELECT id, scope, target, COALESCE(description,'') AS description, last_seen, resolved FROM failure_patterns WHERE project_id = ?",o))l.push({type:"finding",id:c.id,title:`[${c.scope}] ${c.target}`,status:c.resolved?"resolved":"open",agent:null,ts:c.last_seen,detail:String(c.description).slice(0,240)});l.sort((c,d)=>String(d.ts).localeCompare(String(c.ts)));const p={failure_blocks:t("SELECT COUNT(*) n FROM failure_blocks"),tokens_saved:t("SELECT COALESCE(SUM(estimated_tokens),0) n FROM token_savings_log"),rows_shared:t("SELECT COUNT(*) n FROM memory_artifacts WHERE project_id = ? AND is_shared = 1",o)+t("SELECT COUNT(*) n FROM quests WHERE project_id = ? AND is_shared = 1",o)};return{grove:n,found:o!==-1,presence:u,loop:i,metrics:p,feed:l.slice(0,40)}},"GET /ui/truths":e=>{const t=a().getDatabase(),r=Math.max(1,parseInt(String(e.page||"1"),10)),n=Math.min(100,Math.max(1,parseInt(String(e.limit||"20"),10))),s=(r-1)*n,o=t.prepare(`
64
64
  SELECT gt.*, p.name AS project_name
65
65
  FROM ground_truths gt
66
66
  LEFT JOIN projects p ON gt.project_id = p.id
67
67
  WHERE gt.is_current = 1
68
68
  ORDER BY gt.updated_at DESC LIMIT ? OFFSET ?
69
- `).all(n,s),d=t.prepare("SELECT COUNT(*) as c FROM ground_truths WHERE is_current = 1").get().c;return{items:o.map(l=>({...l,staleness:_e(l)})),total:d,page:r,limit:n}},"GET /ui/review":()=>({items:a().getDatabase().prepare(`
69
+ `).all(n,s),u=t.prepare("SELECT COUNT(*) as c FROM ground_truths WHERE is_current = 1").get().c;return{items:o.map(l=>({...l,staleness:_e(l)})),total:u,page:r,limit:n}},"GET /ui/review":()=>({items:a().getDatabase().prepare(`
70
70
  SELECT ma.*, p.name AS project_name
71
71
  FROM memory_artifacts ma
72
72
  LEFT JOIN projects p ON ma.project_id = p.id
73
73
  WHERE ma.needs_review = 1
74
74
  ORDER BY ma.created_at DESC
75
- `).all()}),"GET /ui/account":()=>{const e=q(a().getDatabasePath());try{const t=S(e,"license.json");if(y(t)){const r=JSON.parse(R(t,"utf-8")),n=B(r);return{account:r.license&&r.license.issued_to||"unknown",tier:n.valid?n.tier:"free",valid:!!n.valid,expires:n.expiresAt||null,readonly:g}}}catch{}try{const t=S(e,"cloud.json");if(y(t))return{account:JSON.parse(R(t,"utf-8")).email||"Local",tier:"free",valid:!1,expires:null,readonly:g}}catch{}return{account:"Local",tier:"free",valid:!1,expires:null,readonly:g}},"GET /ui/impact":()=>{const e=a().getDatabase(),t=r=>{try{return e.prepare(r).get()?.n||0}catch{return 0}};return{failures_blocked:t("SELECT COALESCE(SUM(occurrences),0) AS n FROM failure_patterns"),tokens_saved:t("SELECT COALESCE(SUM(estimated_tokens),0) AS n FROM token_savings_log"),memories:t("SELECT COUNT(*) AS n FROM memory_artifacts WHERE supersedes_id IS NULL"),memories_week:t("SELECT COUNT(*) AS n FROM memory_artifacts WHERE created_at >= datetime('now','-7 days')"),truths:t("SELECT COUNT(*) AS n FROM ground_truths WHERE is_current = 1"),sessions:t("SELECT COUNT(*) AS n FROM sessions"),quests_completed:t("SELECT COUNT(*) AS n FROM quests WHERE status = 'completed'"),skills:t("SELECT COUNT(*) AS n FROM skills"),projects:t("SELECT COUNT(*) AS n FROM projects")}},"GET /ui/memory":e=>{const t=a().getDatabase(),r=parseInt(String(e&&e.id||"0"),10);if(!r)return{item:null};try{return{item:t.prepare(`SELECT ma.*, p.name AS project_name
75
+ `).all()}),"GET /ui/account":()=>{const e=q(a().getDatabasePath());try{const t=S(e,"license.json");if(y(t)){const r=JSON.parse(R(t,"utf-8")),n=$(r);return{account:r.license&&r.license.issued_to||"unknown",tier:n.valid?n.tier:"free",valid:!!n.valid,expires:n.expiresAt||null,readonly:g}}}catch{}try{const t=S(e,"cloud.json");if(y(t))return{account:JSON.parse(R(t,"utf-8")).email||"Local",tier:"free",valid:!1,expires:null,readonly:g}}catch{}return{account:"Local",tier:"free",valid:!1,expires:null,readonly:g}},"GET /ui/impact":()=>{const e=a().getDatabase(),t=r=>{try{return e.prepare(r).get()?.n||0}catch{return 0}};return{failures_blocked:t("SELECT COALESCE(SUM(occurrences),0) AS n FROM failure_patterns"),tokens_saved:t("SELECT COALESCE(SUM(estimated_tokens),0) AS n FROM token_savings_log"),memories:t("SELECT COUNT(*) AS n FROM memory_artifacts WHERE supersedes_id IS NULL"),memories_week:t("SELECT COUNT(*) AS n FROM memory_artifacts WHERE created_at >= datetime('now','-7 days')"),truths:t("SELECT COUNT(*) AS n FROM ground_truths WHERE is_current = 1"),sessions:t("SELECT COUNT(*) AS n FROM sessions"),quests_completed:t("SELECT COUNT(*) AS n FROM quests WHERE status = 'completed'"),skills:t("SELECT COUNT(*) AS n FROM skills"),projects:t("SELECT COUNT(*) AS n FROM projects")}},"GET /ui/memory":e=>{const t=a().getDatabase(),r=parseInt(String(e&&e.id||"0"),10);if(!r)return{item:null};try{return{item:t.prepare(`SELECT ma.*, p.name AS project_name
76
76
  FROM memory_artifacts ma LEFT JOIN projects p ON ma.project_id = p.id
77
- WHERE ma.id = ?`).get(r)||null}}catch{return{item:null}}},"GET /ui/recall":async e=>{const t=e.search?String(e.search):e.q?String(e.q):"";if(!t)return{items:[],total:0};const r=_(e.limit,6,25),n=e.kind?String(e.kind):void 0,o=(await b().recallHybridGlobal(t,{limit:r,kind:n})).map(d=>({...d.artifact,relevance:Math.round(d.relevance_score*1e3)/1e3,match_type:d.match_type}));return{items:o,total:o.length}},"GET /ui/context":async e=>{const t=e.search?String(e.search):e.q?String(e.q):"";if(!t)return{context:"",items:[],total:0,tokens:0};const r=_(e.limit,10,25),n=_(e.budget,900,2400),s=await b().recallHybridGlobal(t,{limit:r}),o=[],d=[];let i=0;for(const l of s){const p=l.artifact,c=String(p.problem??p.title??p.summary??p.key??p.kind??"").trim(),u=String(p.validated_fix??p.content??p.body??p.value??p.problem??"").replace(/\s+/g," ").trim(),m=`- ${c}${u?": "+u.slice(0,320):""}`,f=Math.ceil(m.length/4);i+f<=n?(o.push(m),i+=f):o.push(`- ${c.slice(0,64)} \u2026 (recall for detail)`),d.push({...p,relevance:Math.round(l.relevance_score*1e3)/1e3,match_type:l.match_type})}return{context:o.join(`
78
- `),tokens:i,items:d,total:d.length}},"GET /ui/skills":()=>{const e=a().getDatabase();try{const t=e.prepare(`SELECT name, description, category, tier, usage_count, is_active
79
- FROM skills ORDER BY category COLLATE NOCASE, name COLLATE NOCASE`).all();return{items:t,total:t.length}}catch{return{items:[],total:0}}},"GET /ui/homes":()=>{const e=Q();let t=a().getDatabasePath();try{t=x(t)}catch{}return{homes:e.map(r=>({...r,active:r.dbPath===t}))}},"POST /ui/switch":e=>{const t=String(e&&e.path||""),r=Q().find(n=>n.dbPath===t);if(!r)return{ok:!1,error:"unknown home"};try{return De(new W(r.dbPath)),{ok:!0,account:r.account,tier:r.tier}}catch(n){return{ok:!1,error:n instanceof Error?n.message:String(n)}}}};function Pe(e,t,r){if(!a().liveMemoryEnabled()){E(t,e,{e:"live memory disabled",disabled:1},503);return}const n=P(r.project??r.p);if(!n){E(t,e,{e:"not found"},404);return}const s=e.socket.remoteAddress||"unknown";if(w>=je){E(t,e,{e:"too many concurrent streams",retry_after:5},503);return}if((T.get(s)??0)>=Me){E(t,e,{e:"too many concurrent streams from this client",retry_after:5},503);return}w++,T.set(s,(T.get(s)??0)+1);let o=K(e.headers["last-event-id"],r.since);const i=!(s==="127.0.0.1"||s==="::1"||s==="::ffff:127.0.0.1")||r.shared==="1"||r.shared==="true";t.writeHead(200,{...j(e),"Content-Type":"text/event-stream; charset=utf-8","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),t.write(`retry: 3000
77
+ WHERE ma.id = ?`).get(r)||null}}catch{return{item:null}}},"GET /ui/recall":async e=>{const t=e.search?String(e.search):e.q?String(e.q):"";if(!t)return{items:[],total:0};const r=_(e.limit,6,25),n=e.kind?String(e.kind):void 0,o=(await j().recallHybridGlobal(t,{limit:r,kind:n})).map(u=>({...u.artifact,relevance:Math.round(u.relevance_score*1e3)/1e3,match_type:u.match_type}));return{items:o,total:o.length}},"GET /ui/context":async e=>{const t=e.search?String(e.search):e.q?String(e.q):"";if(!t)return{context:"",items:[],total:0,tokens:0};const r=_(e.limit,10,25),n=_(e.budget,900,2400),s=await j().recallHybridGlobal(t,{limit:r}),o=[],u=[];let i=0;for(const l of s){const p=l.artifact,c=String(p.problem??p.title??p.summary??p.key??p.kind??"").trim(),d=String(p.validated_fix??p.content??p.body??p.value??p.problem??"").replace(/\s+/g," ").trim(),m=`- ${c}${d?": "+d.slice(0,320):""}`,f=Math.ceil(m.length/4);i+f<=n?(o.push(m),i+=f):o.push(`- ${c.slice(0,64)} \u2026 (recall for detail)`),u.push({...p,relevance:Math.round(l.relevance_score*1e3)/1e3,match_type:l.match_type})}return{context:o.join(`
78
+ `),tokens:i,items:u,total:u.length}},"GET /ui/skills":()=>{const e=a().getDatabase();try{const t=e.prepare(`SELECT name, description, category, tier, usage_count, is_active
79
+ FROM skills ORDER BY category COLLATE NOCASE, name COLLATE NOCASE`).all();return{items:t,total:t.length}}catch{return{items:[],total:0}}},"GET /ui/homes":()=>{const e=K();let t=a().getDatabasePath();try{t=x(t)}catch{}return{homes:e.map(r=>({...r,active:r.dbPath===t}))}},"POST /ui/switch":e=>{const t=String(e&&e.path||""),r=K().find(n=>n.dbPath===t);if(!r)return{ok:!1,error:"unknown home"};try{return we(new W(r.dbPath)),{ok:!0,account:r.account,tier:r.tier}}catch(n){return{ok:!1,error:n instanceof Error?n.message:String(n)}}}};function We(e,t,r){if(!a().liveMemoryEnabled()){E(t,e,{e:"live memory disabled",disabled:1},503);return}const n=P(r.project??r.p);if(!n){E(t,e,{e:"not found"},404);return}const s=e.socket.remoteAddress||"unknown";if(w>=De){E(t,e,{e:"too many concurrent streams",retry_after:5},503);return}if((T.get(s)??0)>=Ae){E(t,e,{e:"too many concurrent streams from this client",retry_after:5},503);return}w++,T.set(s,(T.get(s)??0)+1);let o=J(e.headers["last-event-id"],r.since);const i=!(s==="127.0.0.1"||s==="::1"||s==="::ffff:127.0.0.1")||r.shared==="1"||r.shared==="true";t.writeHead(200,{...k(e),"Content-Type":"text/event-stream; charset=utf-8","Cache-Control":"no-cache, no-transform",Connection:"keep-alive","X-Accel-Buffering":"no"}),t.write(`retry: 3000
80
80
 
81
- `);let l,p,c=!1;const u=()=>{if(c)return;c=!0,l&&clearInterval(l),p&&clearInterval(p),w--;const f=(T.get(s)??1)-1;f<=0?T.delete(s):T.set(s,f)},m=()=>{if(t.writableEnded){u();return}try{const f=i?a().eventsForPush(n.id,o,200):a().eventsSince(n.id,o,200);for(const H of f)o=H.cursor,t.write(Oe(H))}catch{}};m(),l=setInterval(m,1e3),p=setInterval(()=>{try{t.write(Re)}catch{}},25e3),e.on("close",u),t.on("close",u),t.on("error",u)}const F=z.createServer(async(e,t)=>{if(!te(e,t).error)try{const n=new URL(e.url||"/",`http://localhost:${M}`);if(g&&ve(e.method||"GET",n.pathname)){E(t,e,{e:"read-only mode",readonly:1},403);return}let s;try{s=await we(e)}catch(u){if(u.message==="Invalid JSON"){E(t,e,{e:"Invalid JSON body"},400);return}throw u}if(n.searchParams.forEach((u,m)=>s[m]=u),e.method==="GET"&&n.pathname==="/dragon-mark.svg"){try{if(!v&&y($)&&(v=R($)),v){t.writeHead(200,{...j(e),"Content-Type":"image/svg+xml","Cache-Control":"public, max-age=86400","Content-Length":v.length}),t.end(v);return}}catch{}E(t,e,{e:"not found"},404);return}if(e.method==="GET"&&n.pathname==="/ui"){{const u=k(!1);let m=!1;try{m=!!a().getDatabase().prepare("SELECT 1 FROM projects WHERE name = ? LIMIT 1").get(u.fleetGrove)}catch{}ke(t,e,ce(k(m),re()))}return}if(e.method==="GET"&&n.pathname==="/events/stream"){Pe(e,t,s);return}const o=n.pathname.match(/^\/ui\/review\/(\d+)\/(approve|reject)$/);if(e.method==="POST"&&o){const u=parseInt(o[1],10),m=o[2],f=a().getDatabase();m==="approve"?b().approve(u):f.prepare("DELETE FROM memory_artifacts WHERE id = ?").run(u),E(t,e,{ok:!0});return}const d=`${e.method} ${n.pathname}`,i=X[d];if(!i){if(n.pathname==="/"){E(t,e,{wyrm:"3.0",auth:I().requireAuth?"required":"disabled",tip:"GET /c for quick context"});return}E(t,e,{e:"not found"},404);return}const l=Ce({header:e.headers["wyrm-actor"]}),{result:p,ms:c}=G(()=>Le(l,()=>i(s)));t.setHeader("X-Time-Ms",String(c)),p instanceof Promise?p.then(u=>E(t,e,u)).catch(u=>{const m=Y(u);if(m!==null){const f=J("http",m);t.setHeader("Retry-After",String(Math.ceil(f.error.retry_after_ms/1e3))),E(t,e,f,503);return}D.error("Fast API request failed",{path:e.url,error:u.message}),E(t,e,{e:"Internal server error"},500)}):E(t,e,p)}catch(n){const s=Y(n);if(s!==null){const o=J("http",s);t.setHeader("Retry-After",String(Math.ceil(o.error.retry_after_ms/1e3))),E(t,e,o,503);return}D.error("Fast API request failed",{path:e.url,error:n.message}),E(t,e,{e:"Internal server error"},500)}}),V=()=>{F.close(()=>{try{O?.close()}catch{}process.exit(0)})};process.on("SIGINT",V),process.on("SIGTERM",V);import{fileURLToPath as Fe}from"url";const He=Fe(import.meta.url);if(process.argv[1]===He){le().key&&!/^(0|false|no|off)$/i.test(process.env.WYRM_LICENSE_REFRESH??"")&&Ie();const e=process.env.WYRM_BIND_HOST||"127.0.0.1";F.listen(M,e,()=>{D.info("Wyrm Fast API started",{port:M,host:e}),console.log(`\u{F115D} Wyrm Fast API on ${e}:${M}`),console.log(` Auth: ${I().requireAuth?"required":"disabled"}`),g&&console.log(" Read-only: writes + off-box egress blocked (safe to expose)"),e!=="127.0.0.1"&&e!=="::1"&&e!=="localhost"&&(D.warn("Wyrm Fast API bound to a NON-loopback host \u2014 reachable beyond localhost; ensure auth is required",{host:e}),console.log(` \u26A0 bound to ${e}: reachable beyond localhost \u2014 make sure auth is required`),g||console.log(" \u26A0 not in read-only mode; set WYRM_UI_READONLY=1 for a public bind"))})}export{Ie as primeLicenseRevocations,F as server};
81
+ `);let l,p,c=!1;const d=()=>{if(c)return;c=!0,l&&clearInterval(l),p&&clearInterval(p),w--;const f=(T.get(s)??1)-1;f<=0?T.delete(s):T.set(s,f)},m=()=>{if(t.writableEnded){d();return}try{const f=i?a().eventsForPush(n.id,o,200):a().eventsSince(n.id,o,200);for(const H of f)o=H.cursor,t.write(Oe(H))}catch{}};m(),l=setInterval(m,1e3),p=setInterval(()=>{try{t.write(Re)}catch{}},25e3),e.on("close",d),t.on("close",d),t.on("error",d)}const F=V.createServer(async(e,t)=>{if(!ee(e,t).error)try{const n=new URL(e.url||"/",`http://localhost:${C}`);if(g&&ve(e.method||"GET",n.pathname)){E(t,e,{e:"read-only mode",readonly:1},403);return}let s;try{s=await He(e)}catch(d){if(d.message==="Invalid JSON"){E(t,e,{e:"Invalid JSON body"},400);return}throw d}if(n.searchParams.forEach((d,m)=>s[m]=d),e.method==="GET"&&n.pathname==="/ui"){{const d=I(!1);let m=!1;try{m=!!a().getDatabase().prepare("SELECT 1 FROM projects WHERE name = ? LIMIT 1").get(d.fleetGrove)}catch{}Fe(t,e,ce(I(m),te()))}return}if(e.method==="GET"&&n.pathname==="/events/stream"){We(e,t,s);return}const o=n.pathname.match(/^\/ui\/review\/(\d+)\/(approve|reject)$/);if(e.method==="POST"&&o){const d=parseInt(o[1],10),m=o[2],f=a().getDatabase();m==="approve"?j().approve(d):f.prepare("DELETE FROM memory_artifacts WHERE id = ?").run(d),E(t,e,{ok:!0});return}const u=`${e.method} ${n.pathname}`,i=Q[u];if(!i){if(n.pathname==="/"){E(t,e,{wyrm:ie(),ui:"/ui",auth:A().requireAuth?"required":"disabled",tip:"GET /c for quick context"});return}E(t,e,{e:"not found"},404);return}const l=Ce({header:e.headers["wyrm-actor"]}),{result:p,ms:c}=U(()=>Le(l,()=>i(s)));t.setHeader("X-Time-Ms",String(c)),p instanceof Promise?p.then(d=>E(t,e,d)).catch(d=>{const m=Y(d);if(m!==null){const f=B("http",m);t.setHeader("Retry-After",String(Math.ceil(f.error.retry_after_ms/1e3))),E(t,e,f,503);return}D.error("Fast API request failed",{path:e.url,error:d.message}),E(t,e,{e:"Internal server error"},500)}):E(t,e,p)}catch(n){const s=Y(n);if(s!==null){const o=B("http",s);t.setHeader("Retry-After",String(Math.ceil(o.error.retry_after_ms/1e3))),E(t,e,o,503);return}D.error("Fast API request failed",{path:e.url,error:n.message}),E(t,e,{e:"Internal server error"},500)}}),X=()=>{F.close(()=>{try{O?.close()}catch{}process.exit(0)})};process.on("SIGINT",X),process.on("SIGTERM",X);import{fileURLToPath as Ue}from"url";const Ge=Ue(import.meta.url);if(process.argv[1]===Ge){le().key&&!/^(0|false|no|off)$/i.test(process.env.WYRM_LICENSE_REFRESH??"")&&Pe();const e=process.env.WYRM_BIND_HOST||"127.0.0.1";F.listen(C,e,()=>{const t=Me(e,C);D.info("Wyrm Fast API started",{port:C,host:e,ui:t}),console.log(`\u{F115D} Wyrm Fast API on ${e}:${C}`),console.log(` Dashboard: ${t}`),console.log(` Auth: ${A().requireAuth?"required":"disabled"}`),g&&console.log(" Read-only: writes + off-box egress blocked (safe to expose)"),e!=="127.0.0.1"&&e!=="::1"&&e!=="localhost"&&(D.warn("Wyrm Fast API bound to a NON-loopback host \u2014 reachable beyond localhost; ensure auth is required",{host:e}),console.log(` \u26A0 bound to ${e}: reachable beyond localhost \u2014 make sure auth is required`),g||console.log(" \u26A0 not in read-only mode; set WYRM_UI_READONLY=1 for a public bind"))})}export{Me as dashboardUrl,Pe as primeLicenseRevocations,be as resolveHttpPort,F as server};
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{Server as fe}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as de}from"@modelcontextprotocol/sdk/server/stdio.js";import{scheduleMaintenanceSweep as ge}from"./self-maintenance.js";import{CallToolRequestSchema as he,GetPromptRequestSchema as we,ListPromptsRequestSchema as Se,ListResourcesRequestSchema as Re,ListResourceTemplatesRequestSchema as ve,ListToolsRequestSchema as ke,ReadResourceRequestSchema as be}from"@modelcontextprotocol/sdk/types.js";import{WyrmDB as Ee,resolveDbPath as De}from"./database.js";import{ValidationError as U}from"./validate.js";import{validationErrorResponse as q,cacheKeyFor as Ce}from"./render.js";import{handlerRegistry as h,registryToolDefs as Te,applyDeclaredOutputSchemas as Oe,buildStableToolList as xe}from"./handlers/registry.js";import{resolveActorEnvelope as V,runWithActor as J,getActor as Me,runWithReadCacheKey as We}from"./handlers/boundary.js";import{resolveAliasCall as Pe}from"./handlers/aliases.js";import{resolveShimCall as Ae,shimToolDefs as Ie}from"./handlers/shims.js";import{getPromptResult as Ne,wyrmPromptList as Le}from"./handlers/prompts.js";import{listWyrmResources as Ye,listWyrmResourceTemplates as je,readWyrmResource as Fe,ResourceNotFoundError as Be}from"./handlers/resources.js";import{TaskStore as Ke,resolveTaskGate as Ge,runLongOp as He}from"./tasks.js";import{registerTaskHandlers as Ue,finalizeEarly as qe,unwrapOutcome as Ve,applyAdminGate as Je}from"./tasks-dispatch.js";import{ReplicationManager as $e}from"./replication-daemon.js";import{WYRM_SERVER_INSTRUCTIONS as ze}from"./priority-embed.js";import{WyrmSync as Qe}from"./sync.js";import{cache as w,estimateTokens as W}from"./performance.js";import{readFileSync as $,unlinkSync as Xe,existsSync as z}from"fs";import{join as Ze}from"path";import{initializeOrchestrator as et}from"./auto-orchestrator.js";import{getCrypto as tt,initializeCrypto as rt}from"./crypto.js";import{initVectorSearch as ot}from"./vector-init.js";import{KnowledgeGraph as st}from"./knowledge-graph.js";import{MemoryArtifacts as nt}from"./memory-artifacts.js";import{GroundTruths as at,ReasoningScaffolds as it}from"./intelligence.js";import{classifyCapture as Qo}from"./capture.js";import{initializeLicense as ct,getLicenseInfo as mt}from"./license.js";import{refreshRevocations as Q}from"./revocations.js";import{refreshLicenseIfNeeded as X}from"./license-refresh.js";import{activationSatisfied as lt,activationGateResult as pt}from"./activation.js";import{WyrmAnalytics as _t}from"./analytics.js";import{WyrmCloudBackup as ut}from"./cloud-backup.js";import{CloudSyncManager as yt}from"./cloud-sync.js";import{FailurePatterns as ft}from"./failure-patterns.js";import{AgentPresence as dt}from"./presence.js";import{Causality as gt}from"./causality.js";import{wireTruthAutoCascade as ht}from"./truth-cascade.js";import{SymbolGraph as wt}from"./symbols.js";import{HourLedger as St}from"./hours.js";import{ToolAnalytics as Rt}from"./tool-analytics.js";import{Rehydration as vt}from"./rehydration.js";import{AuditLog as kt,loadAuditSignerFromEnv as bt}from"./audit.js";import{retryableWriteCause as Et,busyErrorResponse as Dt}from"./sqlite-busy.js";import{SubAgent as Ct}from"./sub-agent.js";import{Federation as Tt}from"./federation.js";import{Goals as Ot}from"./goals.js";import{OutboundMcpClient as xt}from"./mcp-client.js";import{AgentLoop as Mt}from"./agent-loop.js";import{makeInternalDispatch as Wt}from"./internal-dispatch.js";import{createUsageTracker as Pt}from"./usage-tracker.js";import{AgentDaemon as At}from"./agent-daemon.js";import{emitStartupVersionBanner as It}from"./version-check.js";import{resolveProfile as Nt,filterByProfile as Lt}from"./tool-profiles.js";import{annotateTools as Yt,elideDefaultAnnotations as jt}from"./tool-annotations.js";import{applyDeprecationNotices as Ft,noteDeprecatedToolInvocation as Bt,isHardCliExile as Kt,cliExileRedirectResponse as Gt}from"./deprecations.js";import{goldenCapture as f}from"./golden.js";import{makeEstimator as Ht}from"./token-budget.js";import{makeRunBudgetedContextBuild as Ut}from"./context-build-budgeted.js";import{assembleThread as qt}from"./thread-assemble.js";import{getThread as Vt}from"./thread-store.js";import{renderThreadForContext as Z}from"./handlers/thread.js";import{makeRunCompanionBuddy as Jt}from"./buddy-runner.js";import{loadWeightsFromEnv as $t}from"./context-ranking.js";import{SessionSeen as zt}from"./session-seen.js";import{recordServed as Qt}from"./served-records.js";import{DesignSystem as Xt}from"./design.js";import{fileURLToPath as Zt}from"url";import{dirname as er,join as ee}from"path";import{readFileSync as tr,existsSync as rr}from"fs";const or=137;let P=null;function sr(){return P||(P=new Xt(r.getDatabase())),P}const nr=Ht(),ar=$t();let A=null;function te(){return A||(A=new zt(r.getDatabase())),A}const C=(()=>{try{const e=er(Zt(import.meta.url));for(const t of[ee(e,"..","package.json"),ee(e,"..","..","package.json")])if(rr(t)){const s=JSON.parse(tr(t,"utf-8")).version;if(typeof s=="string")return s}}catch{}return"unknown"})(),r=new Ee(De()),ir=new Qe(r),re=new st(r.getDatabase()),R=new nt(r.getDatabase()),v=new at(r.getDatabase()),I=new it(r.getDatabase()),N=new ft(r.getDatabase()),L=new dt(r.getDatabase()),Y=new gt(r.getDatabase());ht(v,Y);const j=new wt(r.getDatabase()),cr=new St(r.getDatabase()),k=new Rt(r.getDatabase()),mr=Ut({groundTruths:v,scaffoldLib:I,memory:R,toolAnalytics:k,sessionSeen:te,tokenEstimator:nr,rankWeights:ar,threadText:e=>{try{return Z(qt(r.getDatabase(),e))}catch{try{const t=Vt(r.getDatabase(),e);return t?Z(t):""}catch{return""}}}}),oe=new vt(r.getDatabase()),lr=new kt(r.getDatabase(),bt()),pr=new Ct(r.getDatabase()),se=new Tt(r.getDatabase()),ne=new Ot(r.getDatabase()),ae={projects:r,goals:ne,getActor:Me,store:r,raw:()=>r.getDatabase(),memory:R,truths:v,scaffolds:I,failures:N,presence:L,rehydration:oe,graph:re,symbols:j,vectors:()=>T,indexing:()=>K,cache:w,decrypt:e=>B.maybeDecrypt(e),clientSupportsResources:()=>{const e=c.getClientCapabilities()?.experimental;return!!e&&"resources"in e}},F=new xt(r.getDatabase()),_r=Jt({db:r,mcpClient:F,version:C}),ur=new At(r.getDatabase()),yr=Wt({db:r,failures:N,symbols:j,rehydration:oe,causality:Y,presence:L,federation:se,memory:R,groundTruths:v}),fr=new Mt(r.getDatabase(),F,yr);if(process.env.WYRM_ENCRYPTION_KEY)try{rt(process.env.WYRM_ENCRYPTION_KEY)}catch(e){console.error("Wyrm: Failed to initialize encryption:",e)}const B=tt();let T=null,K=null;{const e=ot(r,R,B);T=e.vectorStore,K=e.indexingPipeline}const dr=et({autoOrchestrateEnabled:!0,minConfidenceThreshold:65,maxParallelAgents:6,defaultHaikuBoosting:!0,trackMetrics:!0});ct();const O=mt();O.tier!=="free"&&console.error(`Wyrm: Licensed \u2014 ${O.tier} tier (expires: ${O.expiresAt||"never"})`);const gr=!!O.key&&!/^(0|false|no|off)$/i.test(process.env.WYRM_LICENSE_REFRESH??"");gr&&(Promise.all([Q(),X()]).catch(()=>{}),setInterval(()=>{Promise.all([Q(),X()]).catch(()=>{})},1440*60*1e3).unref?.());try{const e=process.env.HOME||process.env.USERPROFILE||"",t=Ze(e,".wyrm","bundled-skills.json");if(e&&z(t)){const s=JSON.parse($(t,"utf-8"));let _=0;for(const i of s.skills)try{if(!z(i.path))continue;const m=$(i.path,"utf-8").match(/^---\s*\n([\s\S]*?)\n---/);let a=i.name,u;if(m){const g=m[1].match(/description:\s*\|?\s*\n([\s\S]*?)(?:\nname:|\nmetadata:|\ncategory:|\ntype:|$)/);g&&(a=g[1].split(`
3
- `).map(E=>E.trim()).filter(Boolean).join(" ").slice(0,500));const S=m[1].match(/category:\s*([^\n]+)/);S&&(u=S[1].trim())}r.registerSkill(i.name,a,i.path,u,"Ghost Protocol",void 0,"bundled"),_++}catch{}_>0&&console.error(`Wyrm: Registered ${_} bundled skill(s) on first start.`);try{Xe(t)}catch{}}}catch{}const G=new _t(r.getDatabase()),ie=new ut;process.env.WYRM_R2_ENDPOINT&&process.env.WYRM_R2_ACCESS_KEY&&process.env.WYRM_R2_SECRET_KEY&&ie.configure({endpoint:process.env.WYRM_R2_ENDPOINT,bucket:process.env.WYRM_R2_BUCKET||"wyrm-backups",accessKeyId:process.env.WYRM_R2_ACCESS_KEY,secretAccessKey:process.env.WYRM_R2_SECRET_KEY},process.env.WYRM_ENCRYPTION_KEY);import{fileURLToPath as hr}from"url";import{dirname as wr,join as ce}from"path";const Sr=hr(import.meta.url),me=wr(Sr),Rr=new yt(ce(me,"cloud-sync-entrypoint.js")),vr=new $e(ce(me,"replication-daemon-entrypoint.js")),{trackUsage:d,getUsageStats:kr,usageLog:br}=Pt(G),Er=new Map;function Dr(e,t=!1){return{content:[{type:"text",text:e}]}}const Cr=new Set(["wyrm_list_projects","wyrm_project_context","wyrm_global_context","wyrm_all_quests","wyrm_data_query","wyrm_data_categories","wyrm_search","wyrm_stats","wyrm_skill_list","wyrm_skill_get","wyrm_skill_search","wyrm_skill_stats","wyrm_orchestration_config","wyrm_orchestration_stats","wyrm_license","wyrm_analytics_dashboard","wyrm_cost_report","wyrm_entity_search","wyrm_entity_graph","wyrm_entity_path","wyrm_truth_get","wyrm_scaffold_get","wyrm_session_prime"]);function Tr(e,t){return!(!Cr.has(e)||e==="wyrm_session_prime"&&(t?.run_id===void 0||t?.run_id===null))}const le=new Set(["wyrm_session_start","wyrm_session_update","wyrm_quest_add","wyrm_quest_complete","wyrm_data_insert","wyrm_data_batch_insert","wyrm_set_global","wyrm_scan_projects","wyrm_sync","wyrm_maintenance","wyrm_vector_setup","wyrm_reindex","wyrm_skill_register","wyrm_skill_delete","wyrm_skill_activate","wyrm_skill_deactivate","wyrm_spec_register","wyrm_activate","wyrm_cloud_backup","wyrm_cloud_sync","wyrm_encrypt_setup","wyrm_entity_add","wyrm_entity_link","wyrm_entity_merge","wyrm_remember","wyrm_recall","wyrm_feedback","wyrm_truth_set","wyrm_scaffold_save","wyrm_distill","wyrm_review","wyrm_capture","wyrm_import_git","wyrm_import_pr","wyrm_import_rules","wyrm_inject_prompt","wyrm_prune","wyrm_sync_export","wyrm_sync_import"]),b=new Ke,c=new fe({name:"wyrm",version:C},{capabilities:{tools:{},prompts:{},resources:{},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}},instructions:ze}),pe={...ae,db:r,sync:ir,graph:re,memory:R,groundTruths:v,scaffoldLib:I,failures:N,presence:L,causality:Y,symbols:j,hours:cr,toolAnalytics:k,auditLog:lr,subAgent:pr,federation:se,goals:ne,mcpClient:F,agentDaemon:ur,agentLoop:fr,analytics:G,cloudBackup:ie,cloudSyncManager:Rr,replicationManager:vr,orchestrator:dr,server:c,wyrmCrypto:B,get vectorStore(){return T},get indexingPipeline(){return K},setVectorStore:e=>{T=e},WYRM_PACKAGE_VERSION:C,WYRM_TOOL_COUNT:or,WRITE_TOOLS:le,usageLog:br,responseFingerprints:Er,designSystem:sr,sessionSeen:te,cachedResponse:Dr,getUsageStats:kr,runCompanionBuddy:_r,runBudgetedContextBuild:mr};c.setRequestHandler(ke,async()=>{const e=[...Te(),...Ie()],t=Nt();return{tools:xe(Oe(Ft(jt(Yt(Lt(e,t))))))}}),c.setRequestHandler(Se,async()=>({prompts:[...Le()]})),c.setRequestHandler(we,async e=>{const t=e.params.arguments??{},s=V({args:t,meta:e.params._meta,clientName:c.getClientVersion()?.name});return J(s,()=>Ne(e.params.name,t,ae))}),c.setRequestHandler(Re,async()=>({resources:Ye()})),c.setRequestHandler(ve,async()=>({resourceTemplates:je()})),c.setRequestHandler(be,async e=>{const t=e.params.uri;try{const s=Fe(t,pe),{nextCursor:_,...i}=s;return _?{contents:[i],_meta:{"wyrm/nextCursor":_}}:{contents:[i]}}catch(s){throw s instanceof Be?new Error(s.message):s}}),Ue(c,b),c.setRequestHandler(he,async e=>{const{name:t,arguments:s}=e.params;if(!lt())return pt();const _=V({args:s??{},meta:e.params._meta,clientName:c.getClientVersion()?.name});Bt(t);const i=performance.now(),x=JSON.stringify(s||{}),m=W(x);let a,u,g=null;try{const o=Pe(t,s??{});o.via?.kind==="cli-exile"&&(g=o.via),{tool:a,args:u}=Ae(o.tool,o.args)}catch(o){if(o instanceof U){const n=Math.round(performance.now()-i);d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:n,timestamp:new Date().toISOString()});const l=q(t,o.field,o.message);return f({tool:t,args:s,meta:e.params._meta,response:l,outcome:"validation_error",ms:n,dispatch:"switch"}),l}throw o}if(g&&Kt(g.name)){const o=Math.round(performance.now()-i);d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:o,timestamp:new Date().toISOString()});const n=Gt(g.name);return f({tool:t,args:s,meta:e.params._meta,response:n,outcome:"soft_error",ms:o,dispatch:"switch"}),n}const S=Ge(c.getClientCapabilities()?.tasks,e.params),E=Je(b,S,a,o=>{const n=Math.round(performance.now()-i);d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:n,timestamp:new Date().toISOString()}),f({tool:t,args:s,meta:e.params._meta,response:o,outcome:"soft_error",ms:n,dispatch:h.has(a)?"registry":"switch"})});if(E!==null)return E;const _e=a===t?x:JSON.stringify(u),M=Tr(a,u??{})?Ce(a,_e):null;if(M){const o=w.get(M);if(o){const n=Math.round(performance.now()-i),l=W(JSON.stringify(o));d({tool:t,tokens_in:m,tokens_out:l,cached:!0,ms:n,timestamp:new Date().toISOString()});const p={...o};return f({tool:t,args:s,meta:e.params._meta,response:p,cached:!0,ms:n,dispatch:h.has(a)?"registry":"switch"}),qe(b,S,a,p)}}if(le.has(a)){const o=u?.projectPath;o&&w.invalidate(o),w.invalidate("wyrm_list_projects"),w.invalidate("wyrm_global_context"),w.invalidate("wyrm_all_quests"),w.invalidate("wyrm_stats")}let D;const ue=u||{};try{const o=await J(_,async()=>{const H=h.get(a);return H?await He(a,S,b,()=>We(M,()=>H(ue,pe))):{kind:"inline",result:{content:[{type:"text",text:`Unknown tool: ${a}`}],isError:!0}}}),{wireValue:n,payload:l}=Ve(b,o);D=l;const p=Math.round(performance.now()-i),y=JSON.stringify(D),ye=W(y);return Qt(r.getDatabase(),y),d({tool:t,tokens_in:m,tokens_out:ye,cached:!1,ms:p,timestamp:new Date().toISOString()}),k.log({tool_name:t,args:s,success:!D?.isError,latency_ms:p}),f({tool:t,args:s,meta:e.params._meta,response:D,ms:p,dispatch:h.has(a)?"registry":"switch"}),n}catch(o){const n=Math.round(performance.now()-i);if(o instanceof U){d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:n,timestamp:new Date().toISOString()});const y=q(t,o.field,o.message);return f({tool:t,args:s,meta:e.params._meta,response:y,outcome:"validation_error",ms:n,dispatch:h.has(a)?"registry":"switch"}),y}const l=Et(o);if(l!==null){d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:n,timestamp:new Date().toISOString()}),k.log({tool_name:t,args:s,success:!1,error_message:`WYRM_BUSY[${l}]: ${String(o).slice(0,400)}`,latency_ms:n});const y=Dt(t,l);return f({tool:t,args:s,meta:e.params._meta,response:y,outcome:"error",ms:n,dispatch:h.has(a)?"registry":"switch"}),y}d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:n,timestamp:new Date().toISOString()}),k.log({tool_name:t,args:s,success:!1,error_message:String(o).slice(0,500),latency_ms:n});const p={content:[{type:"text",text:`Error: ${o}`}],isError:!0};return f({tool:t,args:s,meta:e.params._meta,response:p,outcome:"error",ms:n,dispatch:h.has(a)?"registry":"switch"}),p}}),process.on("uncaughtException",e=>{try{console.error("Wyrm[uncaughtException]:",e instanceof Error?e.stack:e)}catch{}}),process.on("unhandledRejection",e=>{try{console.error("Wyrm[unhandledRejection]:",e instanceof Error?e.stack:e)}catch{}});async function Or(){const e=new de;await c.connect(e),ge(r),It(r.getDatabase(),C).catch(()=>{});const t=()=>{try{G.shutdown()}catch{}process.exit(0)};process.on("SIGINT",t),process.on("SIGTERM",t)}Or().catch(console.error);export{Qo as classifyCapture};
2
+ import{Server as we}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Se}from"@modelcontextprotocol/sdk/server/stdio.js";import{scheduleMaintenanceSweep as Re}from"./self-maintenance.js";import{watchForOrphaning as ve,makeShutdown as ke,trackInFlight as be,resolveDrainMs as Ee}from"./stdio-lifecycle.js";import{CallToolRequestSchema as De,GetPromptRequestSchema as Ce,ListPromptsRequestSchema as Te,ListResourcesRequestSchema as Oe,ListResourceTemplatesRequestSchema as xe,ListToolsRequestSchema as Me,ReadResourceRequestSchema as We}from"@modelcontextprotocol/sdk/types.js";import{WyrmDB as Pe,resolveDbPath as Ae}from"./database.js";import{ValidationError as V}from"./validate.js";import{validationErrorResponse as $,cacheKeyFor as Ie}from"./render.js";import{handlerRegistry as h,registryToolDefs as W,applyDeclaredOutputSchemas as Ne,buildStableToolList as Le}from"./handlers/registry.js";import{resolveActorEnvelope as J,runWithActor as z,getActor as Ye,runWithReadCacheKey as je}from"./handlers/boundary.js";import{resolveAliasCall as Fe}from"./handlers/aliases.js";import{rejectUnknownArgs as Be}from"./handlers/arg-keys.js";import{resolveShimCall as Ke,shimToolDefs as P}from"./handlers/shims.js";import{getPromptResult as Ue,wyrmPromptList as Ge}from"./handlers/prompts.js";import{listWyrmResources as He,listWyrmResourceTemplates as qe,readWyrmResource as Ve,ResourceNotFoundError as $e}from"./handlers/resources.js";import{TaskStore as Je,resolveTaskGate as ze,runLongOp as Qe}from"./tasks.js";import{registerTaskHandlers as Xe,finalizeEarly as Ze,unwrapOutcome as et,applyAdminGate as tt}from"./tasks-dispatch.js";import{ReplicationManager as rt}from"./replication-daemon.js";import{WYRM_SERVER_INSTRUCTIONS as ot}from"./priority-embed.js";import{WyrmSync as st}from"./sync.js";import{cache as w,estimateTokens as A}from"./performance.js";import{readFileSync as Q,unlinkSync as nt,existsSync as X}from"fs";import{join as at}from"path";import{initializeOrchestrator as it}from"./auto-orchestrator.js";import{getCrypto as ct,initializeCrypto as mt}from"./crypto.js";import{initVectorSearch as lt}from"./vector-init.js";import{KnowledgeGraph as pt}from"./knowledge-graph.js";import{MemoryArtifacts as ut}from"./memory-artifacts.js";import{GroundTruths as _t,ReasoningScaffolds as ft}from"./intelligence.js";import{classifyCapture as ss}from"./capture.js";import{initializeLicense as yt,getLicenseInfo as dt}from"./license.js";import{refreshRevocations as Z}from"./revocations.js";import{refreshLicenseIfNeeded as ee}from"./license-refresh.js";import{activationSatisfied as gt,activationGateResult as ht}from"./activation.js";import{WyrmAnalytics as wt}from"./analytics.js";import{WyrmCloudBackup as St}from"./cloud-backup.js";import{CloudSyncManager as Rt}from"./cloud-sync.js";import{FailurePatterns as vt}from"./failure-patterns.js";import{AgentPresence as kt}from"./presence.js";import{Causality as bt}from"./causality.js";import{wireTruthAutoCascade as Et}from"./truth-cascade.js";import{SymbolGraph as Dt}from"./symbols.js";import{HourLedger as Ct}from"./hours.js";import{ToolAnalytics as Tt}from"./tool-analytics.js";import{Rehydration as Ot}from"./rehydration.js";import{AuditLog as xt,loadAuditSignerFromEnv as Mt}from"./audit.js";import{retryableWriteCause as Wt,busyErrorResponse as Pt}from"./sqlite-busy.js";import{SubAgent as At}from"./sub-agent.js";import{Federation as It}from"./federation.js";import{Goals as Nt}from"./goals.js";import{OutboundMcpClient as Lt}from"./mcp-client.js";import{AgentLoop as Yt}from"./agent-loop.js";import{makeInternalDispatch as jt}from"./internal-dispatch.js";import{createUsageTracker as Ft}from"./usage-tracker.js";import{AgentDaemon as Bt}from"./agent-daemon.js";import{emitStartupVersionBanner as Kt}from"./version-check.js";import{resolveProfile as te,filterByProfile as re}from"./tool-profiles.js";import{annotateTools as Ut,elideDefaultAnnotations as Gt}from"./tool-annotations.js";import{applyDeprecationNotices as Ht,noteDeprecatedToolInvocation as qt,isHardCliExile as Vt,cliExileRedirectResponse as $t}from"./deprecations.js";import{goldenCapture as y}from"./golden.js";import{makeEstimator as Jt}from"./token-budget.js";import{makeRunBudgetedContextBuild as zt}from"./context-build-budgeted.js";import{assembleThread as Qt}from"./thread-assemble.js";import{getThread as Xt}from"./thread-store.js";import{renderThreadForContext as oe}from"./handlers/thread.js";import{makeRunCompanionBuddy as Zt}from"./buddy-runner.js";import{loadWeightsFromEnv as er}from"./context-ranking.js";import{SessionSeen as tr}from"./session-seen.js";import{recordServed as rr}from"./served-records.js";import{DesignSystem as or}from"./design.js";import{fileURLToPath as sr}from"url";import{dirname as nr,join as se}from"path";import{readFileSync as ar,existsSync as ir}from"fs";const cr=137;let I=null;function mr(){return I||(I=new or(r.getDatabase())),I}const lr=Jt(),pr=er();let N=null;function ne(){return N||(N=new tr(r.getDatabase())),N}const C=(()=>{try{const e=nr(sr(import.meta.url));for(const t of[se(e,"..","package.json"),se(e,"..","..","package.json")])if(ir(t)){const o=JSON.parse(ar(t,"utf-8")).version;if(typeof o=="string")return o}}catch{}return"unknown"})(),r=new Pe(Ae()),ur=new st(r),ae=new pt(r.getDatabase()),R=new ut(r.getDatabase()),v=new _t(r.getDatabase()),L=new ft(r.getDatabase()),Y=new vt(r.getDatabase()),j=new kt(r.getDatabase()),F=new bt(r.getDatabase());Et(v,F);const B=new Dt(r.getDatabase()),_r=new Ct(r.getDatabase()),k=new Tt(r.getDatabase()),fr=zt({groundTruths:v,scaffoldLib:L,memory:R,toolAnalytics:k,sessionSeen:ne,tokenEstimator:lr,rankWeights:pr,threadText:e=>{try{return oe(Qt(r.getDatabase(),e))}catch{try{const t=Xt(r.getDatabase(),e);return t?oe(t):""}catch{return""}}}}),ie=new Ot(r.getDatabase()),yr=new xt(r.getDatabase(),Mt()),dr=new At(r.getDatabase()),ce=new It(r.getDatabase()),me=new Nt(r.getDatabase()),le={projects:r,goals:me,getActor:Ye,store:r,raw:()=>r.getDatabase(),memory:R,truths:v,scaffolds:L,failures:Y,presence:j,rehydration:ie,graph:ae,symbols:B,vectors:()=>T,indexing:()=>G,cache:w,decrypt:e=>U.maybeDecrypt(e),clientSupportsResources:()=>{const e=c.getClientCapabilities()?.experimental;return!!e&&"resources"in e}},K=new Lt(r.getDatabase()),gr=Zt({db:r,mcpClient:K,version:C}),hr=new Bt(r.getDatabase()),wr=jt({db:r,failures:Y,symbols:B,rehydration:ie,causality:F,presence:j,federation:ce,memory:R,groundTruths:v}),Sr=new Yt(r.getDatabase(),K,wr);if(process.env.WYRM_ENCRYPTION_KEY)try{mt(process.env.WYRM_ENCRYPTION_KEY)}catch(e){console.error("Wyrm: Failed to initialize encryption:",e)}const U=ct();let T=null,G=null;{const e=lt(r,R,U);T=e.vectorStore,G=e.indexingPipeline}const Rr=it({autoOrchestrateEnabled:!0,minConfidenceThreshold:65,maxParallelAgents:6,defaultHaikuBoosting:!0,trackMetrics:!0});yt();const O=dt();O.tier!=="free"&&console.error(`Wyrm: Licensed \u2014 ${O.tier} tier (expires: ${O.expiresAt||"never"})`);const vr=!!O.key&&!/^(0|false|no|off)$/i.test(process.env.WYRM_LICENSE_REFRESH??"");vr&&(Promise.all([Z(),ee()]).catch(()=>{}),setInterval(()=>{Promise.all([Z(),ee()]).catch(()=>{})},1440*60*1e3).unref?.());try{const e=process.env.HOME||process.env.USERPROFILE||"",t=at(e,".wyrm","bundled-skills.json");if(e&&X(t)){const o=JSON.parse(Q(t,"utf-8"));let l=0;for(const i of o.skills)try{if(!X(i.path))continue;const m=Q(i.path,"utf-8").match(/^---\s*\n([\s\S]*?)\n---/);let a=i.name,_;if(m){const g=m[1].match(/description:\s*\|?\s*\n([\s\S]*?)(?:\nname:|\nmetadata:|\ncategory:|\ntype:|$)/);g&&(a=g[1].split(`
3
+ `).map(E=>E.trim()).filter(Boolean).join(" ").slice(0,500));const S=m[1].match(/category:\s*([^\n]+)/);S&&(_=S[1].trim())}r.registerSkill(i.name,a,i.path,_,"Ghost Protocol",void 0,"bundled"),l++}catch{}l>0&&console.error(`Wyrm: Registered ${l} bundled skill(s) on first start.`);try{nt(t)}catch{}}}catch{}const H=new wt(r.getDatabase()),pe=new St;process.env.WYRM_R2_ENDPOINT&&process.env.WYRM_R2_ACCESS_KEY&&process.env.WYRM_R2_SECRET_KEY&&pe.configure({endpoint:process.env.WYRM_R2_ENDPOINT,bucket:process.env.WYRM_R2_BUCKET||"wyrm-backups",accessKeyId:process.env.WYRM_R2_ACCESS_KEY,secretAccessKey:process.env.WYRM_R2_SECRET_KEY},process.env.WYRM_ENCRYPTION_KEY);import{fileURLToPath as kr}from"url";import{dirname as br,join as ue}from"path";const Er=kr(import.meta.url),_e=br(Er),Dr=new Rt(ue(_e,"cloud-sync-entrypoint.js")),Cr=new rt(ue(_e,"replication-daemon-entrypoint.js")),{trackUsage:d,getUsageStats:Tr,usageLog:Or}=Ft(H),xr=new Map;function Mr(e,t=!1){return{content:[{type:"text",text:e}]}}const Wr=new Set(["wyrm_list_projects","wyrm_project_context","wyrm_global_context","wyrm_all_quests","wyrm_data_query","wyrm_data_categories","wyrm_search","wyrm_stats","wyrm_skill_list","wyrm_skill_get","wyrm_skill_search","wyrm_skill_stats","wyrm_orchestration_config","wyrm_orchestration_stats","wyrm_license","wyrm_analytics_dashboard","wyrm_cost_report","wyrm_entity_search","wyrm_entity_graph","wyrm_entity_path","wyrm_truth_get","wyrm_scaffold_get","wyrm_session_prime"]);function Pr(e,t){return!(!Wr.has(e)||e==="wyrm_session_prime"&&(t?.run_id===void 0||t?.run_id===null))}const fe=new Set(["wyrm_session_start","wyrm_session_update","wyrm_quest_add","wyrm_quest_complete","wyrm_data_insert","wyrm_data_batch_insert","wyrm_set_global","wyrm_scan_projects","wyrm_sync","wyrm_maintenance","wyrm_vector_setup","wyrm_reindex","wyrm_skill_register","wyrm_skill_delete","wyrm_skill_activate","wyrm_skill_deactivate","wyrm_spec_register","wyrm_activate","wyrm_cloud_backup","wyrm_cloud_sync","wyrm_encrypt_setup","wyrm_entity_add","wyrm_entity_link","wyrm_entity_merge","wyrm_remember","wyrm_recall","wyrm_feedback","wyrm_truth_set","wyrm_scaffold_save","wyrm_distill","wyrm_review","wyrm_capture","wyrm_import_git","wyrm_import_pr","wyrm_import_rules","wyrm_inject_prompt","wyrm_prune","wyrm_sync_export","wyrm_sync_import"]),b=new Je,c=new we({name:"wyrm",version:C},{capabilities:{tools:{},prompts:{},resources:{},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}},instructions:ot}),ye={...le,db:r,sync:ur,graph:ae,memory:R,groundTruths:v,scaffoldLib:L,failures:Y,presence:j,causality:F,symbols:B,hours:_r,toolAnalytics:k,auditLog:yr,subAgent:dr,federation:ce,goals:me,mcpClient:K,agentDaemon:hr,agentLoop:Sr,analytics:H,cloudBackup:pe,cloudSyncManager:Dr,replicationManager:Cr,orchestrator:Rr,server:c,wyrmCrypto:U,get vectorStore(){return T},get indexingPipeline(){return G},setVectorStore:e=>{T=e},WYRM_PACKAGE_VERSION:C,WYRM_TOOL_COUNT:cr,toolCounts:()=>({active:re([...W(),...P()],te()).length,full:W().length+P().length}),WRITE_TOOLS:fe,usageLog:Or,responseFingerprints:xr,designSystem:mr,sessionSeen:ne,cachedResponse:Mr,getUsageStats:Tr,runCompanionBuddy:gr,runBudgetedContextBuild:fr};c.setRequestHandler(Me,async()=>{const e=[...W(),...P()],t=te();return{tools:Le(Ne(Ht(Gt(Ut(re(e,t))))))}}),c.setRequestHandler(Te,async()=>({prompts:[...Ge()]})),c.setRequestHandler(Ce,async e=>{const t=e.params.arguments??{},o=J({args:t,meta:e.params._meta,clientName:c.getClientVersion()?.name});return z(o,()=>Ue(e.params.name,t,le))}),c.setRequestHandler(Oe,async()=>({resources:He()})),c.setRequestHandler(xe,async()=>({resourceTemplates:qe()})),c.setRequestHandler(We,async e=>{const t=e.params.uri;try{const o=Ve(t,ye),{nextCursor:l,...i}=o;return l?{contents:[i],_meta:{"wyrm/nextCursor":l}}:{contents:[i]}}catch(o){throw o instanceof $e?new Error(o.message):o}}),Xe(c,b),c.setRequestHandler(De,async e=>{const{name:t,arguments:o}=e.params;if(!gt())return ht();const l=J({args:o??{},meta:e.params._meta,clientName:c.getClientVersion()?.name});qt(t);const i=performance.now(),x=JSON.stringify(o||{}),m=A(x);let a,_,g=null;try{const s=Fe(t,o??{});s.via?.kind==="cli-exile"&&(g=s.via),{tool:a,args:_}=Ke(s.tool,s.args),Be(t,o??{},a)}catch(s){if(s instanceof V){const n=Math.round(performance.now()-i);d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:n,timestamp:new Date().toISOString()});const p=$(t,s.field,s.message);return y({tool:t,args:o,meta:e.params._meta,response:p,outcome:"validation_error",ms:n,dispatch:"switch"}),p}throw s}if(g&&Vt(g.name)){const s=Math.round(performance.now()-i);d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:s,timestamp:new Date().toISOString()});const n=$t(g.name);return y({tool:t,args:o,meta:e.params._meta,response:n,outcome:"soft_error",ms:s,dispatch:"switch"}),n}const S=ze(c.getClientCapabilities()?.tasks,e.params),E=tt(b,S,a,s=>{const n=Math.round(performance.now()-i);d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:n,timestamp:new Date().toISOString()}),y({tool:t,args:o,meta:e.params._meta,response:s,outcome:"soft_error",ms:n,dispatch:h.has(a)?"registry":"switch"})});if(E!==null)return E;const de=a===t?x:JSON.stringify(_),M=Pr(a,_??{})?Ie(a,de):null;if(M){const s=w.get(M);if(s){const n=Math.round(performance.now()-i),p=A(JSON.stringify(s));d({tool:t,tokens_in:m,tokens_out:p,cached:!0,ms:n,timestamp:new Date().toISOString()});const u={...s};return y({tool:t,args:o,meta:e.params._meta,response:u,cached:!0,ms:n,dispatch:h.has(a)?"registry":"switch"}),Ze(b,S,a,u)}}if(fe.has(a)){const s=_?.projectPath;s&&w.invalidate(s),w.invalidate("wyrm_list_projects"),w.invalidate("wyrm_global_context"),w.invalidate("wyrm_all_quests"),w.invalidate("wyrm_stats")}let D;const ge=_||{};try{const s=await z(l,async()=>{const q=h.get(a);return q?await Qe(a,S,b,()=>je(M,()=>q(ge,ye))):{kind:"inline",result:{content:[{type:"text",text:`Unknown tool: ${a}`}],isError:!0}}}),{wireValue:n,payload:p}=et(b,s);D=p;const u=Math.round(performance.now()-i),f=JSON.stringify(D),he=A(f);return rr(r.getDatabase(),f),d({tool:t,tokens_in:m,tokens_out:he,cached:!1,ms:u,timestamp:new Date().toISOString()}),k.log({tool_name:t,args:o,success:!D?.isError,latency_ms:u}),y({tool:t,args:o,meta:e.params._meta,response:D,ms:u,dispatch:h.has(a)?"registry":"switch"}),n}catch(s){const n=Math.round(performance.now()-i);if(s instanceof V){d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:n,timestamp:new Date().toISOString()});const f=$(t,s.field,s.message);return y({tool:t,args:o,meta:e.params._meta,response:f,outcome:"validation_error",ms:n,dispatch:h.has(a)?"registry":"switch"}),f}const p=Wt(s);if(p!==null){d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:n,timestamp:new Date().toISOString()}),k.log({tool_name:t,args:o,success:!1,error_message:`WYRM_BUSY[${p}]: ${String(s).slice(0,400)}`,latency_ms:n});const f=Pt(t,p);return y({tool:t,args:o,meta:e.params._meta,response:f,outcome:"error",ms:n,dispatch:h.has(a)?"registry":"switch"}),f}d({tool:t,tokens_in:m,tokens_out:0,cached:!1,ms:n,timestamp:new Date().toISOString()}),k.log({tool_name:t,args:o,success:!1,error_message:String(s).slice(0,500),latency_ms:n});const u={content:[{type:"text",text:`Error: ${s}`}],isError:!0};return y({tool:t,args:o,meta:e.params._meta,response:u,outcome:"error",ms:n,dispatch:h.has(a)?"registry":"switch"}),u}}),process.on("uncaughtException",e=>{try{console.error("Wyrm[uncaughtException]:",e instanceof Error?e.stack:e)}catch{}}),process.on("unhandledRejection",e=>{try{console.error("Wyrm[unhandledRejection]:",e instanceof Error?e.stack:e)}catch{}});async function Ar(){const e=ke([()=>H.shutdown(),()=>r.close()]);process.on("SIGINT",()=>e()),process.on("SIGTERM",()=>e());const{transport:t,inFlight:o}=be(new Se);ve({inFlight:o,drainMs:Ee(),onOrphan:l=>e(`client gone (${l})`)}),await c.connect(t),Re(r),Kt(r.getDatabase(),C).catch(()=>{})}Ar().catch(console.error);export{ss as classifyCapture};
package/dist/logger.js CHANGED
@@ -1,2 +1,2 @@
1
- import{appendFileSync as h,existsSync as u,mkdirSync as p}from"fs";import{homedir as $}from"os";import{join as f}from"path";const m={debug:0,info:1,warn:2,error:3},w={debug:"\x1B[36m",info:"\x1B[32m",warn:"\x1B[33m",error:"\x1B[31m"},s="\x1B[0m",x="\x1B[1m",g="\x1B[2m";class l{config;correlationId;logDir;constructor(o){this.config={level:o?.level??"info",console:o?.console??!0,json:o?.json??!1,file:o?.file},this.logDir=f($(),".wyrm","logs"),u(this.logDir)||p(this.logDir,{recursive:!0})}setCorrelationId(o){this.correlationId=o}generateCorrelationId(){return this.correlationId=`wyrm-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.correlationId}shouldLog(o){return m[o]>=m[this.config.level]}format(o){if(this.config.json)return JSON.stringify(o);const r=w[o.level],n=o.level.toUpperCase().padEnd(5),t=o.timestamp.split("T")[1]?.split(".")[0]||o.timestamp;let e=`${g}${t}${s} ${r}${x}${n}${s} ${o.message}`;return o.context&&Object.keys(o.context).length>0&&(e+=` ${g}${JSON.stringify(o.context)}${s}`),o.correlationId&&(e+=` ${g}[${o.correlationId}]${s}`),e}log(o,r,n){if(!this.shouldLog(o))return;const t={timestamp:new Date().toISOString(),level:o,message:r,context:n,correlationId:this.correlationId},e=this.format(t);if(this.config.console&&console.error(e),this.config.file)try{const a=f(this.logDir,this.config.file);h(a,(this.config.json?e:JSON.stringify(t))+`
2
- `)}catch{}}debug(o,r){this.log("debug",o,r)}info(o,r){this.log("info",o,r)}warn(o,r){this.log("warn",o,r)}error(o,r){this.log("error",o,r)}time(o,r){const n=performance.now();try{const t=r(),e=performance.now()-n;return this.debug(`${o} completed`,{duration:`${e.toFixed(2)}ms`}),t}catch(t){const e=performance.now()-n;throw this.error(`${o} failed`,{duration:`${e.toFixed(2)}ms`,error:String(t)}),t}}async timeAsync(o,r){const n=performance.now();try{const t=await r(),e=performance.now()-n;return this.debug(`${o} completed`,{duration:`${e.toFixed(2)}ms`}),t}catch(t){const e=performance.now()-n;throw this.error(`${o} failed`,{duration:`${e.toFixed(2)}ms`,error:String(t)}),t}}child(o){const r=new l(this.config);r.correlationId=this.correlationId;const n=r.log.bind(r);return r.log=(t,e,a)=>{n(t,e,{...o,...a})},r}}let d=null;function c(){return d||(d=new l({level:process.env.WYRM_LOG_LEVEL||"info",console:process.env.WYRM_LOG_CONSOLE!=="false",json:process.env.WYRM_LOG_JSON==="true",file:"wyrm.log"})),d}function b(i){return new l(i)}const I={debug:(i,o)=>c().debug(i,o),info:(i,o)=>c().info(i,o),warn:(i,o)=>c().warn(i,o),error:(i,o)=>c().error(i,o)};export{l as WyrmLogger,b as createLogger,c as getLogger,I as logger};
1
+ import{appendFileSync as O,existsSync as w,mkdirSync as $}from"fs";import{homedir as v}from"os";import{join as p}from"path";import{shouldUseColor as x}from"./cli.js";const u={debug:0,info:1,warn:2,error:3},S=x(process.env,process.stderr.isTTY),i=e=>S?e:"",_={debug:i("\x1B[36m"),info:i("\x1B[32m"),warn:i("\x1B[33m"),error:i("\x1B[31m")},a=i("\x1B[0m"),b=i("\x1B[1m"),d=i("\x1B[2m");function I(e=process.env){return e.WYRM_LOG_DIR||p(v(),".wyrm","logs")}class l{config;correlationId;logDir;constructor(o){this.config={level:o?.level??"info",console:o?.console??!0,json:o?.json??!1,file:o?.file},this.logDir=I()}setCorrelationId(o){this.correlationId=o}generateCorrelationId(){return this.correlationId=`wyrm-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.correlationId}shouldLog(o){return u[o]>=u[this.config.level]}format(o){if(this.config.json)return JSON.stringify(o);const r=_[o.level],s=o.level.toUpperCase().padEnd(5),t=o.timestamp.split("T")[1]?.split(".")[0]||o.timestamp;let n=`${d}${t}${a} ${r}${b}${s}${a} ${o.message}`;return o.context&&Object.keys(o.context).length>0&&(n+=` ${d}${JSON.stringify(o.context)}${a}`),o.correlationId&&(n+=` ${d}[${o.correlationId}]${a}`),n}log(o,r,s){if(!this.shouldLog(o))return;const t={timestamp:new Date().toISOString(),level:o,message:r,context:s,correlationId:this.correlationId},n=this.format(t);if(this.config.console&&console.error(n),this.config.file)try{w(this.logDir)||$(this.logDir,{recursive:!0});const f=p(this.logDir,this.config.file);O(f,(this.config.json?n:JSON.stringify(t))+`
2
+ `)}catch{}}debug(o,r){this.log("debug",o,r)}info(o,r){this.log("info",o,r)}warn(o,r){this.log("warn",o,r)}error(o,r){this.log("error",o,r)}time(o,r){const s=performance.now();try{const t=r(),n=performance.now()-s;return this.debug(`${o} completed`,{duration:`${n.toFixed(2)}ms`}),t}catch(t){const n=performance.now()-s;throw this.error(`${o} failed`,{duration:`${n.toFixed(2)}ms`,error:String(t)}),t}}async timeAsync(o,r){const s=performance.now();try{const t=await r(),n=performance.now()-s;return this.debug(`${o} completed`,{duration:`${n.toFixed(2)}ms`}),t}catch(t){const n=performance.now()-s;throw this.error(`${o} failed`,{duration:`${n.toFixed(2)}ms`,error:String(t)}),t}}child(o){const r=new l(this.config);r.correlationId=this.correlationId;const s=r.log.bind(r);return r.log=(t,n,f)=>{s(t,n,{...o,...f})},r}}let g=null,m="info";function C(e){m=e,g=null}function h(){const e=(process.env.WYRM_LOG_LEVEL??"").toLowerCase();return e in u?e:m}function c(){return g||(g=new l({level:h(),console:process.env.WYRM_LOG_CONSOLE!=="false",json:process.env.WYRM_LOG_JSON==="true",file:"wyrm.log"})),g}const L=new Map;function R(){const e=`${m}|${process.env.WYRM_LOG_LEVEL??""}|${process.env.WYRM_LOG_CONSOLE??""}|${process.env.WYRM_LOG_JSON??""}`;let o=L.get(e);return o||(o=new l({level:h(),console:process.env.WYRM_LOG_CONSOLE!=="false",json:process.env.WYRM_LOG_JSON==="true"}),L.set(e,o)),o}function Y(e){const o=R(),r=Object.create(o);return r.warn=(s,t)=>c().warn(s,{store:e,...t}),r.error=(s,t)=>c().error(s,{store:e,...t}),r}function j(e){return new l(e)}const N={debug:(e,o)=>c().debug(e,o),info:(e,o)=>c().info(e,o),warn:(e,o)=>c().warn(e,o),error:(e,o)=>c().error(e,o)};export{l as WyrmLogger,j as createLogger,c as getLogger,Y as getStoreLogger,I as logDirectory,N as logger,C as setDefaultLogLevel};
package/dist/receipt.js CHANGED
@@ -1 +1 @@
1
- function s(e){const n=["fts5"];e.vectorsAvailable&&n.push("vector"),e.rerankActive&&n.push("rerank");const t=[];e.vectorsAvailable&&e.embedEgressHost&&t.push(`embed:${e.embedEgressHost}`),e.rerankActive&&e.rerankEgressHost&&t.push(`rerank:${e.rerankEgressHost}`);const r=t.length===0?"none":t.join("; ");return{deterministic:!0,generativeLlmCalls:0,dataEgress:r,local:r==="none",stages:n,embedModel:e.vectorsAvailable?e.embedModel??null:null,rerankModel:e.rerankActive?e.rerankModel??null:null,...e.stageMs?{stageMs:e.stageMs}:{},...e.indexStale?{indexStale:e.indexStale}:{},...!e.vectorsAvailable&&e.ftsOnlyReason?{ftsOnlyReason:e.ftsOnlyReason}:{}}}function l(e){const n=[e.embedModel,e.rerankModel].filter(Boolean).join(", "),t=e.ftsOnlyReason?` Vector stage skipped: ${e.ftsOnlyReason}.`:"",r=`${e.stages.join(" -> ")}${n?` (${n})`:""}`;return e.local?`No generative LLM touched this query; no data left this machine. Retrieved by ${r}, all local.${t}`:`No generative LLM touched this query. Non-generative scoring by an explicit opt-in remote provider (${e.dataEgress}). Retrieved by ${r}.`}function a(e){const n=e.toLowerCase();return n==="localhost"||n==="::1"||n==="[::1]"?!0:/^127(\.\d{1,3}){3}$/.test(n)}function o(e){if(!e)return null;try{const n=new URL(e).hostname.toLowerCase();return a(n)?null:n}catch{return null}}export{l as attestation,s as buildDeterminismReceipt,o as egressHostOf,a as isLoopbackHost};
1
+ const d=.25;function v(e){let t;if(e.vectorsAvailable&&e.coverage&&e.coverage.eligible>0){const a=Math.floor(e.coverage.eligible),l=Math.max(0,Math.min(Math.floor(e.coverage.indexed),a)),i=l/a;t={indexed:l,eligible:a,ratio:i,effectivelyFtsOnly:i<.25}}const r=["fts5"];e.vectorsAvailable&&r.push("vector"),e.rerankActive&&r.push("rerank");const n=[];e.vectorsAvailable&&e.embedEgressHost&&n.push(`embed:${e.embedEgressHost}`),e.rerankActive&&e.rerankEgressHost&&n.push(`rerank:${e.rerankEgressHost}`);const o=n.length===0?"none":n.join("; ");return{deterministic:!0,generativeLlmCalls:0,dataEgress:o,local:o==="none",stages:r,embedModel:e.vectorsAvailable?e.embedModel??null:null,rerankModel:e.rerankActive?e.rerankModel??null:null,...e.stageMs?{stageMs:e.stageMs}:{},...e.indexStale?{indexStale:e.indexStale}:{},...!e.vectorsAvailable&&e.ftsOnlyReason?{ftsOnlyReason:e.ftsOnlyReason}:{},...t?{vectorCoverage:t}:{}}}function f(e){const t=[e.embedModel,e.rerankModel].filter(Boolean).join(", "),r=e.ftsOnlyReason?` Vector stage skipped: ${e.ftsOnlyReason}.`:"",n=`${e.stages.join(" -> ")}${t?` (${t})`:""}`,o=e.vectorCoverage?.effectivelyFtsOnly?` Effectively FTS-only: ${e.embedModel??"the active model"} has vectors for ${e.vectorCoverage.indexed} of ${e.vectorCoverage.eligible} memories (${s(e.vectorCoverage.ratio)}); run \`wyrm index rebuild\` to embed the rest.`:"";return e.local?`No generative LLM touched this query; no data left this machine. Retrieved by ${n}, all local.${r}${o}`:`No generative LLM touched this query. Non-generative scoring by an explicit opt-in remote provider (${e.dataEgress}). Retrieved by ${n}.${o}`}function s(e){const t=e*100;return t>0&&t<.1?"<0.1%":`${t.toFixed(1)}%`}function c(e){const t=e.toLowerCase();return t==="localhost"||t==="::1"||t==="[::1]"?!0:/^127(\.\d{1,3}){3}$/.test(t)}function u(e){if(!e)return null;try{const t=new URL(e).hostname.toLowerCase();return c(t)?null:t}catch{return null}}export{d as LOW_VECTOR_COVERAGE,f as attestation,v as buildDeterminismReceipt,u as egressHostOf,c as isLoopbackHost};
@@ -1,11 +1,19 @@
1
- class m{db;constructor(p){this.db=p}rehydrate(p,c){const s=this.db.prepare("SELECT * FROM sessions WHERE id = ?").get(p);if(!s)return null;const a=this.db.prepare("SELECT name, path FROM projects WHERE id = ?").get(s.project_id);if(!a)return null;const f=c?.include_artifacts??!0,_=c?.include_failures??!0,u=Math.max(200,Math.min(c?.max_truth_chars??2e3,1e4)),h=this.db.prepare(`
1
+ const z=10,P="WYRM_REHYDRATE_MAX_CHARS";function X(i){if(typeof i!="string"||i.length===0)return!1;const e=i.split("_")[0].toLowerCase();return/(?:^|[-.:])(?:cron|scheduled|maintenance)$/.test(e)}const V=/\[IMPORTANT: The user has invoked the "[^"\n]*" skill[^\]]*(?:\]|$)(?:\s*---\r?\n[\s\S]*?(?:\r?\n---[ \t]*(?:\r?\n|$)|$))?/g;function K(i){return i?i.replace(V,"").replace(/\n{3,}/g,`
2
+
3
+ `).trim():""}function f(i,e){return i.length<=e?i:`${i.slice(0,Math.max(0,e-2)).trimEnd()} \u2026`}function E(i){return i.replace(/\s+/g," ").trim()}function _(i){return i.replace(/\r?\n/g,`
4
+ `)}class G{budget;lines=[];used=0;constructor(e){this.budget=e}fits(e,a=0){return this.used+e.length+1+a<=this.budget}push(e){this.lines.push(e),this.used+=e.length+1}get chars(){return this.used}remaining(){return this.budget-this.used}}const q=160,b={narrative:.25,truths:.2,failures:.25,artifacts:.15};class J{db;constructor(e){this.db=e}latestSessionId(e,a){let r;try{r=this.db.prepare(`
5
+ SELECT id, run_id FROM sessions
6
+ WHERE project_id = ? AND is_archived = 0
7
+ ORDER BY date DESC, id DESC
8
+ LIMIT 200
9
+ `).all(e)}catch{const o=this.db.prepare("SELECT id FROM sessions WHERE project_id = ? AND is_archived = 0 ORDER BY date DESC, id DESC LIMIT 1").get(e);return o?o.id:null}return r.length===0?null:a?.includeAutomated?r[0].id:(r.find(o=>!X(o.run_id))??r[0]).id}rehydrate(e,a){const r=this.db.prepare("SELECT * FROM sessions WHERE id = ?").get(e);if(!r)return null;const l=this.db.prepare("SELECT name, path FROM projects WHERE id = ?").get(r.project_id);if(!l)return null;const o=a?.include_artifacts??!0,M=a?.include_failures??!0,m=Math.max(200,Math.min(a?.max_truth_chars??2e3,1e4)),u=Math.max(0,Math.min(Math.floor(a?.max_quests??10),100)),g=Number.parseInt(process.env[P]??"",10),h=typeof a?.max_chars=="number"?a.max_chars:Number.isFinite(g)?g:0,n=h>0,d=this.db.prepare(`
2
10
  SELECT category, key, value, rationale, confidence, last_verified_at,
3
11
  ttl_days,
4
12
  CAST((julianday('now') - julianday(last_verified_at)) AS REAL) AS age_days
5
13
  FROM ground_truths
6
14
  WHERE project_id = ? AND is_current = 1
7
15
  ORDER BY category, key
8
- `).all(s.project_id),i=this.db.prepare(`
16
+ `).all(r.project_id),y=this.db.prepare(`
9
17
  SELECT id, title, description, priority, status, tags
10
18
  FROM quests
11
19
  WHERE project_id = ? AND status IN ('pending','in_progress')
@@ -13,19 +21,26 @@ class m{db;constructor(p){this.db=p}rehydrate(p,c){const s=this.db.prepare("SELE
13
21
  CASE priority WHEN 'critical' THEN 0 WHEN 'high' THEN 1
14
22
  WHEN 'medium' THEN 2 ELSE 3 END,
15
23
  created_at DESC
16
- `).all(s.project_id);let n=[];if(f)try{n=this.db.prepare(`
24
+ `).all(r.project_id);let v=[];if(o)try{v=this.db.prepare(`
17
25
  SELECT id, problem, constraints, validated_fix, why_it_worked, tags
18
26
  FROM memory_artifacts
19
27
  WHERE project_id = ? AND (needs_review = 0 OR needs_review IS NULL)
20
28
  ORDER BY (CASE WHEN problem LIKE '[auto:%' THEN 1 ELSE 0 END), id DESC
21
29
  LIMIT 20
22
- `).all(s.project_id)}catch{n=[]}let o=[];if(_)try{o=this.db.prepare(`
30
+ `).all(r.project_id)}catch{v=[]}let D=[];if(M)try{D=this.db.prepare(`
23
31
  SELECT id, scope, target, description, why_failed, occurrences, severity, last_seen
24
32
  FROM failure_patterns
25
33
  WHERE (project_id = ? OR project_id IS NULL) AND resolved = 0
26
34
  ORDER BY last_seen DESC LIMIT 15
27
- `).all(s.project_id)}catch{o=[]}const e=[];if(e.push("# Session Rehydration Brief"),e.push(""),e.push(`**Session #${s.id}** \xB7 ${a.name} \xB7 ${s.date}`),e.push(`**Project root:** \`${a.path}\``),e.push(""),s.objectives&&(e.push("## Objectives at start"),e.push(s.objectives),e.push("")),s.completed&&(e.push("## What was completed"),e.push(s.completed),e.push("")),s.issues&&(e.push("## Open issues at session close"),e.push(s.issues),e.push("")),s.notes&&(e.push("## Notes"),e.push(s.notes),e.push("")),s.summary&&(e.push("## Summary"),e.push(s.summary),e.push("")),h.length>0){e.push("## Ground truths for this project"),e.push("");let t=0;for(const r of h){const E=r.ttl_days!=null&&r.age_days>r.ttl_days?" [\u26A0\uFE0F STALE]":"",d=`- **${r.category}.${r.key}**${E}: ${r.value}`+(r.rationale?` *(rationale: ${r.rationale})*`:"")+(r.confidence<1?` *(conf: ${r.confidence})*`:"");if(t+=d.length,t>u){e.push(`- _\u2026 ${h.length-(e.length-3)} more truths omitted (cap ${u} chars) \u2014 query wyrm_truth_get for full list._`);break}e.push(d)}e.push("")}if(i.length>0){e.push(`## Open quests (${i.length})`),e.push("");for(const t of i.slice(0,20))e.push(`- **#${t.id}** [${t.priority}] ${t.title}`+(t.description?`
28
- ${t.description.slice(0,200)}`:""));i.length>20&&e.push(`- _\u2026 ${i.length-20} more \u2014 query wyrm_all_quests._`),e.push("")}if(n.length>0){e.push("## Validated patterns (memory artifacts)"),e.push("");for(const t of n.slice(0,10))e.push(`- **${t.problem}**`+(t.validated_fix?` \u2192 ${t.validated_fix.slice(0,150)}`:""));e.push("")}if(o.length>0){e.push("## Unresolved failure patterns \u2014 DO NOT repeat these"),e.push("");for(const t of o)e.push(`- \u{1F534} #${t.id} [${t.severity}] ${t.scope}:${t.target} \xD7${t.occurrences}
29
- ${t.description}`+(t.why_failed?`
30
- Why: ${t.why_failed}`:""));e.push("")}e.push("---"),e.push(`*Rehydrated from session created at ${s.created_at}. Continue from where the prior agent left off.*`);const l=e.join(`
31
- `);return{session_id:s.id,project_name:a.name,project_path:a.path,briefing_markdown:l,context_chars:l.length,attached:{quests:i.length,truths:h.length,artifacts:n.length,failures:o.length}}}}export{m as Rehydration};
35
+ `).all(r.project_id)}catch{D=[]}const L=["---",`*Rehydrated from session created at ${r.created_at}. Continue from where the prior agent left off.*`],O=L.join(`
36
+ `).length+1,s=new G(n?Math.max(0,h-O):1/0);s.push("# Session Rehydration Brief"),s.push(""),s.push(`**Session #${r.id}** \xB7 ${l.name} \xB7 ${r.date}`),s.push(`**Project root:** \`${l.path}\``),s.push("");const C=s.chars;let N=0;const S=t=>n?(N+=t*(s.budget-C),Math.max(0,N-(s.chars-C))):1/0,T=[["Objectives at start",r.objectives],["What was completed",r.completed],["Open issues at session close",r.issues],["Notes",r.notes],["Summary",r.summary]].map(([t,c])=>[t,K(c)]).filter(([,t])=>t.length>0),x=S(b.narrative),H=n&&T.length>0?Math.max(120,Math.floor(x/T.length)-40):1/0;for(const[t,c]of T){const $=`## ${t}`;let p=f(c,H);if(!s.fits(`${$}
37
+ ${p}
38
+ `)){const R=s.remaining()-$.length-8;if(R<120)continue;p=f(p,R)}s.push($),s.push(p),s.push("")}const W=n?240:Math.max(200,Math.floor(m/2)),A=[];let j=0;for(const t of d){const $=t.ttl_days!=null&&t.age_days>t.ttl_days?" [\u26A0\uFE0F STALE]":"",p=`- **${t.category}.${t.key}**${$}: ${t.value}`+(t.rationale?` *(rationale: ${t.rationale})*`:"")+(t.confidence<1?` *(conf: ${t.confidence})*`:""),R=f(n?E(p):_(p),W);if(j+=R.length,j>m)break;A.push(R)}const k=this.section(s,"## Ground truths for this project",A,d.length-A.length,t=>`- _\u2026 ${t} more truths not shown. Query wyrm_truth_get for the full list._`,S(b.truths)),F=D.map(t=>{const c=`- \u{1F534} #${t.id} [${t.severity}] ${t.scope}:${t.target} \xD7${t.occurrences}`;return n?f(`${c}: ${E(t.description+(t.why_failed?` Why: ${t.why_failed}`:""))}`,240):c+`
39
+ ${_(t.description)}`+(t.why_failed?`
40
+ Why: ${_(t.why_failed)}`:"")}),B=this.section(s,"## Unresolved failure patterns \u2014 DO NOT repeat these",F,0,t=>`- _\u2026 ${t} more unresolved failure patterns not shown. Run wyrm_failure_check before retrying an approach._`,S(b.failures)),Y=v.slice(0,10).map(t=>{const c=t.validated_fix?` \u2192 ${t.validated_fix.slice(0,n?80:150)}`:"";return n?f(`- **${f(E(t.problem),160)}**${E(c)}`,260):`- **${_(t.problem)}**${_(c)}`}),U=this.section(s,"## Validated patterns (memory artifacts)",Y,0,t=>`- _\u2026 ${t} more patterns not shown. Query wyrm_recall for the rest._`,S(b.artifacts)),I=y.slice(0,u).map(t=>n?f(`- **#${t.id}** [${t.priority}] ${E(t.title)}${t.description?`: ${E(t.description)}`:""}`,200):`- **#${t.id}** [${t.priority}] ${_(t.title)}`+(t.description?`
41
+ ${_(t.description.slice(0,200))}`:"")),Q=this.section(s,`## Open quests (${y.length})`,I,y.length-I.length,t=>`- _\u2026 ${t} more open quests not shown. Query wyrm_quest (action: list) for the rest._`,1/0);for(const t of L)s.push(t);const w=s.lines.join(`
42
+ `);return{session_id:r.id,project_name:l.name,project_path:l.path,briefing_markdown:w,context_chars:w.length,attached:{quests:Q,truths:k,artifacts:U,failures:B}}}section(e,a,r,l,o,M){const m=r.length+l;if(m===0)return 0;let u=0,g=0;for(let n=0;n<r.length;n++){const d=u===0?`${a}
43
+
44
+ ${r[n]}`:r[n],y=n<r.length-1||l>0;if(g+d.length+1>M||!e.fits(d,y?q:0))break;e.push(d),g+=d.length+1,u++}const h=m-u;if(u===0){const n=`${a}
45
+
46
+ ${o(h)}`;return e.fits(n)&&(e.push(n),e.push("")),0}return h>0&&e.fits(o(h))&&e.push(o(h)),e.push(""),u}}export{z as DEFAULT_MAX_QUESTS,P as MAX_CHARS_ENV,J as Rehydration,X as isAutomatedRunId,K as stripInjectedPreamble};
package/dist/render.js CHANGED
@@ -1,4 +1,4 @@
1
- import{ICON as u}from"./icons.js";function x(){const t=process.env.WYRM_FANCY;return t==="1"||t==="true"}const y={brand:"",ok:"",fail:"",warn:"",paused:"",resumed:"",bullet:"-",point:">"},d={brand:u.brand,ok:u.ok,fail:u.blocked,warn:u.failure,paused:"\u23F8",resumed:"\u25B6",bullet:u.bullet,point:u.point};function a(){return x()?d:y}function E(t,e){return t?`${t} ${e}`:e}const $=/[\x00-\x08\x0b-\x1f\x7f]/g;function l(t){return t.replace($,"")}function p(){const t=process.env.WYRM_CHANNEL;return t==="text"||t==="structured"?t:"both"}function N(t,e){return`${p()}:${t}:${e}`}const g=`
1
+ import{ICON as u}from"./icons.js";function l(){const t=process.env.WYRM_FANCY;return t==="1"||t==="true"}const y={brand:"",ok:"",fail:"",warn:"",paused:"",resumed:"",bullet:"-",point:">"},$={brand:u.brand,ok:u.ok,fail:u.blocked,warn:u.failure,paused:"\u23F8",resumed:"\u25B6",bullet:u.bullet,point:u.point};function d(){return l()?$:y}function O(t,e){return t?`${t} ${e}`:e}const g=/[\x00-\x08\x0b-\x1f\x7f]/g;function m(t){return t.replace(g,"")}function p(){const t=process.env.WYRM_CHANNEL;return t==="text"||t==="structured"?t:"both"}function E(t,e){return`${p()}:${t}:${e}`}const b=`
2
2
 
3
- _(full body in structuredContent)_`;function A(t){const e=t.indexOf(`
4
- `);return e===-1?t:t.slice(0,e)}function T(t,e,o){const r=e?l(e(t,a())):JSON.stringify(t,null,2),s=p();if(s==="structured"&&!o?.exemptStructured){const n=(o?.summary?l(o.summary(t,a())):e?A(r):r)+g;return{content:[{type:"text",text:n.length<r.length?n:r}],structuredContent:t}}return s==="text"?{content:[{type:"text",text:r}]}:{content:[{type:"text",text:r}],structuredContent:t}}function b(t){return p()==="text"?{content:[{type:"text",text:JSON.stringify(t,null,2)}],isError:!0}:{content:[{type:"text",text:JSON.stringify(t,null,2)}],isError:!0,structuredContent:t}}const h="WYRM_VALIDATION";function S(t,e,o){return{error:{code:h,message:`${t}: ${o}`,retryable:!1,field:e},expected:`Correct the '${e}' argument \u2014 ${(()=>{const r=o.replace(`'${e}' `,"");return/^(must|is|are|should|has|have|cannot|can't|exceeds|matches|needs)\b/.test(r)?`it ${r}`:r})()} \u2014 and call ${t} again. This rejection is deterministic: the SAME arguments will fail the SAME way, so do not retry unchanged (unlike WYRM_BUSY, which is retryable as-is). Validators run at the argument-binding seam (validate.ts) before the handler's write path, so re-calling with corrected arguments is safe. The tool's inputSchema documents the accepted values.`}}function O(t,e,o){return b(S(t,e,o))}function m(t,e,o="$"){const r=[],s=Array.isArray(e.type)?e.type:e.type?[e.type]:[],f=n=>n===null?"null":Array.isArray(n)?"array":typeof n=="number"?Number.isInteger(n)?"integer":"number":typeof n;if(s.length>0){const n=f(t);s.some(c=>c===n||c==="number"&&n==="integer")||r.push(`${o}: expected ${s.join("|")}, got ${n}`)}if(e.enum&&!e.enum.includes(t)&&r.push(`${o}: ${JSON.stringify(t)} not in enum`),typeof t=="number"&&(typeof e.minimum=="number"&&t<e.minimum&&r.push(`${o}: < minimum`),typeof e.maximum=="number"&&t>e.maximum&&r.push(`${o}: > maximum`)),t&&typeof t=="object"&&!Array.isArray(t)&&e.properties){const n=e.properties;for(const i of e.required??[])i in t||r.push(`${o}: missing required '${i}'`);for(const[i,c]of Object.entries(t))n[i]&&r.push(...m(c,n[i],`${o}.${i}`))}return Array.isArray(t)&&e.items&&t.forEach((n,i)=>r.push(...m(n,e.items,`${o}[${i}]`))),r}export{h as WYRM_VALIDATION_CODE,N as cacheKeyFor,p as channelPolicy,a as glyphs,x as isFancy,b as renderErrorResponse,T as renderResult,l as stripWireControls,m as validateAgainstSchema,S as validationErrorBody,O as validationErrorResponse,E as withGlyph};
3
+ _(full body in structuredContent)_`;function h(t){const e=t.indexOf(`
4
+ `);return e===-1?t:t.slice(0,e)}function _(t,e,r){const n=e?m(e(t,d())):JSON.stringify(t,null,2),s=p();if(s==="structured"&&!r?.exemptStructured){const o=(r?.summary?m(r.summary(t,d())):e?h(n):n)+b;return{content:[{type:"text",text:o.length<n.length?o:n}],structuredContent:t}}return s==="text"?{content:[{type:"text",text:n}]}:{content:[{type:"text",text:n}],structuredContent:t}}const f=new Set;function N(t){for(const e of t)f.add(e)}function R(t){return f.has(t)}function A(t,e){return p()==="text"||e!==void 0&&f.has(e)?{content:[{type:"text",text:JSON.stringify(t,null,2)}],isError:!0}:{content:[{type:"text",text:JSON.stringify(t,null,2)}],isError:!0,structuredContent:t}}const S="WYRM_VALIDATION";function T(t,e,r){return{error:{code:S,message:`${t}: ${r}`,retryable:!1,field:e},expected:`Correct the '${e}' argument: ${(()=>{const n=r.replace(`'${e}' `,"");return(/^(must|is|are|should|has|have|cannot|can't|exceeds|matches|needs)\b/.test(n)?`it ${n}`:n).replace(/[.\s]+$/,"")})()}. Then call ${t} again. This rejection is deterministic: the SAME arguments will fail the SAME way, so do not retry unchanged (unlike WYRM_BUSY, which is retryable as-is). Validators run at the argument-binding seam (validate.ts) before the handler's write path, so re-calling with corrected arguments is safe.`+(/\bone of\b/.test(r)?" The accepted values are listed in the message.":"")}}function w(t,e,r){return A(T(t,e,r),t)}function I(t){if(t&&typeof t=="object"&&t.isError===!0&&"structuredContent"in t){const{structuredContent:e,...r}=t;return r}return t}function x(t,e,r="$"){const n=[],s=Array.isArray(e.type)?e.type:e.type?[e.type]:[],a=o=>o===null?"null":Array.isArray(o)?"array":typeof o=="number"?Number.isInteger(o)?"integer":"number":typeof o;if(s.length>0){const o=a(t);s.some(c=>c===o||c==="number"&&o==="integer")||n.push(`${r}: expected ${s.join("|")}, got ${o}`)}if(e.enum&&!e.enum.includes(t)&&n.push(`${r}: ${JSON.stringify(t)} not in enum`),typeof t=="number"&&(typeof e.minimum=="number"&&t<e.minimum&&n.push(`${r}: < minimum`),typeof e.maximum=="number"&&t>e.maximum&&n.push(`${r}: > maximum`)),t&&typeof t=="object"&&!Array.isArray(t)&&e.properties){const o=e.properties;for(const i of e.required??[])i in t||n.push(`${r}: missing required '${i}'`);for(const[i,c]of Object.entries(t))o[i]&&n.push(...x(c,o[i],`${r}.${i}`))}return Array.isArray(t)&&e.items&&t.forEach((o,i)=>n.push(...x(o,e.items,`${r}[${i}]`))),n}export{S as WYRM_VALIDATION_CODE,E as cacheKeyFor,p as channelPolicy,N as declareOutputSchemaTools,R as declaresOutputSchema,d as glyphs,l as isFancy,A as renderErrorResponse,_ as renderResult,m as stripWireControls,x as validateAgainstSchema,T as validationErrorBody,w as validationErrorResponse,O as withGlyph,I as withoutErrorStructuredContent};
package/dist/setup.js CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import{existsSync as w,readFileSync as D}from"node:fs";import{BUNDLED_MODEL_SIZE_LABEL as L}from"./providers/bundled-model.js";import{homedir as b}from"node:os";import{join as A}from"node:path";import{detectClients as E,autoConfigureAll as N,removeFromAll as W,configureSpecific as _,reconfAll as B,getStatusSummary as j,findWyrmServerPath as z,getDefaultDbPath as I,loadWyrmMeta as O,exportServerConfig as T}from"./autoconfig.js";import{c as o,icons as g,BANNER as F,MINI_BANNER as f,printSuccess as U,printError as x,printWarning as Y,printSection as d}from"./cli.js";import{runWizard as Z}from"./setup-wizard.js";function H(n){const e=n.slice(2);if(e.length===0)return{command:"auto"};const s={command:"auto"};for(let c=0;c<e.length;c++)switch(e[c]){case"--check":case"-c":case"check":case"status":s.command="check";break;case"--remove":case"-r":case"remove":case"uninstall":s.command="remove";break;case"--only":case"-o":case"only":s.command="only",e[c+1]&&(s.clientIds=e[c+1].split(",").map(t=>t.trim()),c++);break;case"--reconf":case"--reconfigure":case"reconf":s.command="reconf";break;case"--list":case"-l":case"list":s.command="list";break;case"--export":case"export":{s.command="export";const t=e[c+1];(t==="stdio"||t==="vscode"||t==="mcp-json")&&(s.exportFormat=t,c++);break}case"--server":case"-s":e[c+1]&&(s.serverPath=e[c+1],c++);break;case"--db":case"-d":e[c+1]&&(s.dbPath=e[c+1],c++);break;case"--wizard":case"wizard":s.command="wizard";break;case"--no-wizard":case"--plain":s.noWizard=!0;break;case"--no-model":s.noModel=!0;break;case"--help":case"-h":case"help":s.command="help";break}return s}function k(n){console.log("");const e=n.filter(l=>l.action==="configured"),s=n.filter(l=>l.action==="updated"),c=n.filter(l=>l.action==="skipped"),t=n.filter(l=>l.action==="failed");for(const l of e)console.log(` ${g.success} ${l.client.icon} ${o.green(l.client.name)} \u2014 ${o.success("configured")}`),l.backup&&console.log(` ${o.dim(`backup \u2192 ${l.backup}`)}`);for(const l of s)console.log(` ${g.sync} ${l.client.icon} ${o.blue(l.client.name)} \u2014 ${o.cyan("updated")}`),l.backup&&console.log(` ${o.dim(`backup \u2192 ${l.backup}`)}`);for(const l of c)console.log(` ${o.dim(` \u25CB ${l.client.icon} ${l.client.name} \u2014 ${l.message}`)}`);for(const l of t)console.log(` ${g.error} ${l.client.icon} ${o.red(l.client.name)} \u2014 ${o.error(l.message)}`);console.log("");const p=e.length+s.length;p>0?(console.log(` ${o.success(`${g.dragon} Wyrm connected to ${p} AI client(s)`)}`),console.log(` ${o.dim("Switch AIs anytime \u2014 run wyrm-setup again to reconnect")}`)):t.length>0?console.log(` ${o.error("Some configurations failed. Check errors above.")}`):console.log(` ${o.dim("No AI clients detected. Install one and try again.")}`),console.log("")}function J(n){return n.split(b()).join("~")}async function v(n,e){const{bundledModelPresent:s,downloadBundledModel:c,BUNDLED_MODEL_SIZE_LABEL:t}=await import("./providers/bundled-model.js"),{resolveEmbeddingState:p,tierForResolution:l}=await import("./providers/embedding-provider.js");if(d("Enabling meaning-based search"),s())console.log(o.dim(" Local embedding model already present."));else if(n)console.log(o.dim(" Skipped (--no-model). Recall is keyword-only until: wyrm vectors download"));else{console.log(o.dim(` Downloading nomic-embed-text-v1.5 (${t}, Apache-2.0, from huggingface.co with models.ghosts.lk as fallback). Skip with --no-model.`));let r=-1;const C=await c({onProgress:($,M,R)=>{const y=Math.floor(M/R*100);y!==r&&(r=y,process.stdout.write(`\r ${$}: ${y}% `))}});if(process.stdout.write(`
3
- `),C.ok){U(`Meaning-based search is on (${t}, local, no account).`);const{runBundledBackfill:$}=await import("./reindex.js");await $()}else Y(`Could not download the model (${C.error}).`),console.log(o.dim(" Keyword search works fine meanwhile. Retry later: wyrm vectors download"))}d("Health check");const u=p(),i=l(u);console.log(` ${u.resolved!=="none"?"\u2714":"\u25CB"} search: ${i.label} (${u.resolved}${u.model?` \xB7 ${u.model}`:""})`);const P=I();console.log(w(P)?` \u2714 memory file: ${J(P)}`:" \u25CB memory file: created on first run");const a=e.find(r=>r.client.id==="claude-code-hooks");let m;if(a&&(a.action==="configured"||a.action==="updated"))m=!0,console.log(` \u2714 auto-memory hooks: ${a.action==="updated"?"updated":"installed"}`);else if(a&&a.action==="skipped"&&a.client.configured)m=!0,console.log(` \u2714 auto-memory hooks: ${a.message}`);else if(a)m=!1,console.log(` \u25CB auto-memory hooks: ${a.message}`);else{const r=A(b(),".claude","hooks","wyrm-session-capture.mjs");m=w(r),console.log(m?" \u2714 auto-memory hooks: already installed":" \u25CB auto-memory hooks: not installed by this command")}const S=e.find(r=>r.client.id==="claude-code-guard");let h;if(S)h=S.client.configured===!0;else{const r=A(b(),".claude","settings.json");try{h=w(r)&&/wyrm-guard/.test(D(r,"utf-8"))}catch{h=!1}}d("What happens automatically now"),console.log(m?" \u2022 Every session is captured to memory when it ends.":" \u2022 On this client, the model handles capture per server instructions."),console.log(m?" \u2022 Every new session starts with your context restored.":" \u2022 Each session starts by priming from memory (the model calls wyrm_session_prime first)."),console.log(h?" \u2022 The failure firewall blocks repeats of recorded mistakes. Always on.":" \u2022 The failure firewall arms once hooks are installed."),console.log(" \u2022 The store prunes and re-ranks itself daily. No cron, no timer to write."),console.log(" \u2022 The token firewall notes files you read in full twice; wyrm doctor shows what it found."),console.log(` \u2022 Something off? ${o.cyan("wyrm doctor")} fails loudly with the exact fix; ${o.cyan("wyrm report")} is the shareable diagnostic.`),console.log(""),console.log(i.n>=3?`Search: tier ${i.n}/3 (${i.label}).`:i.n===2?`Search: tier ${i.n}/3 (${i.label}). ${o.cyan("wyrm upgrade")} \u2192 max recall.`:`Search: tier ${i.n}/3 (${i.label}). ${o.cyan("wyrm vectors download")} \u2192 local vectors (free, no account); then ${o.cyan("wyrm upgrade")} \u2192 max recall.`)}function K(){console.log(f()),console.log(""),console.log(`${o.bold("Usage:")} wyrm-setup ${o.dim("[command] [options]")}`),console.log(""),console.log(`${o.bold("Commands:")}`),console.log(` ${o.cyan("(no args)")} Auto-detect and configure all AI clients`),console.log(` ${o.cyan("check")} Show current configuration status`),console.log(` ${o.cyan("list")} List all supported AI clients`),console.log(` ${o.cyan("remove")} Remove Wyrm from all AI clients`),console.log(` ${o.cyan("reconf")} Re-configure previously configured clients`),console.log(` ${o.cyan("only X,Y")} Configure specific clients only`),console.log(` ${o.cyan("export [fmt]")} Print a portable config (fmt: mcp-json|vscode|stdio) for any MCP host`),console.log(` ${o.cyan("help")} Show this help message`),console.log(""),console.log(`${o.bold("Options:")}`),console.log(` ${o.cyan("--server P")} Override Wyrm MCP server path`),console.log(` ${o.cyan("--db P")} Override Wyrm database path`),console.log(` ${o.cyan("--no-model")} Skip the one-time local embedding model download (${L}); recall stays keyword-only`),console.log(` ${o.cyan("--plain")} Non-interactive flag flow (no wizard) \u2014 the default when not on a TTY`),console.log(""),console.log(`${o.bold("Client IDs:")}`);const n=E();for(const e of n)console.log(` ${e.icon} ${o.cyan(e.id.padEnd(18))} ${e.name}`);console.log(""),console.log(`${o.bold("Examples:")}`),console.log(` wyrm-setup ${o.dim("# Auto-configure everything")}`),console.log(` wyrm-setup check ${o.dim("# See what's configured")}`),console.log(` wyrm-setup only vscode-copilot,cursor ${o.dim("# Only VS Code + Cursor")}`),console.log(` wyrm-setup --server /path/to/wyrm/dist/index.js ${o.dim("# Custom server path")}`),console.log(` wyrm-setup remove ${o.dim("# Remove from all clients")}`),console.log(` wyrm-setup export stdio > wyrm.json ${o.dim("# Portable config for any MCP host")}`),console.log("")}function V(){console.log(f()),console.log(""),d("Supported AI Clients"),console.log("");const n=E();for(const e of n){const s=e.detected?e.configured?o.success("\u25CF connected"):o.yellow("\u25D0 available"):o.dim("\u25CB not found"),c=e.version?` ${o.dim(`v${e.version}`)}`:"";console.log(` ${e.icon} ${o.bold(e.name.padEnd(20))} ${o.cyan(e.id.padEnd(18))} ${s}${c}`),console.log(` ${o.dim(`Config: ${e.configPath}`)}`)}console.log("")}async function X(){const n=H(process.argv);if(n.command==="wizard"||n.command==="auto"&&!n.noWizard){const e=await Z({serverPath:n.serverPath,dbPath:n.dbPath});if(e===!1)n.command==="wizard"&&(n.command="auto");else if(e===null){console.log(o.dim("Setup aborted, nothing changed."));return}else{await v(n.noModel??!1,e);return}}switch(n.command){case"help":K();break;case"check":{console.log(f()),console.log(""),console.log(j());break}case"list":V();break;case"auto":{console.log(F()),d("Auto-Configure"),console.log("");const e=n.serverPath||z(),s=n.dbPath||I();console.log(` ${g.sword} Server: ${o.cyan(e)}`),console.log(` ${g.treasure} DB: ${o.cyan(s)}`),console.log(""),console.log(` ${o.dim("Scanning for AI clients...")}`);const c=N({serverPath:e,dbPath:s});k(c),await v(n.noModel??!1,c);break}case"only":{(!n.clientIds||n.clientIds.length===0)&&(x("No client IDs specified. Use: wyrm-setup only vscode-copilot,cursor"),process.exit(1)),console.log(f()),d(`Configure: ${n.clientIds.join(", ")}`);const e=_(n.clientIds,{serverPath:n.serverPath,dbPath:n.dbPath});k(e),await v(n.noModel??!1,e);break}case"remove":{console.log(f()),d("Remove Wyrm from AI Clients"),console.log(""),console.log(` ${o.warning("Removing Wyrm configuration from all AI clients...")}`);const e=W(),s=e.filter(t=>t.action==="configured"),c=e.filter(t=>t.action==="skipped");for(const t of s)console.log(` ${g.check} ${t.client.icon} ${t.client.name} \u2014 removed`),t.backup&&console.log(` ${o.dim(`backup \u2192 ${t.backup}`)}`);for(const t of c)console.log(` ${o.dim(` \u25CB ${t.client.icon} ${t.client.name} \u2014 ${t.message}`)}`);console.log(""),s.length>0&&console.log(` ${o.success(`Removed from ${s.length} client(s). Run wyrm-setup to reconnect.`)}`),console.log("");break}case"reconf":{console.log(f()),d("Re-Configure");const e=O();console.log(e?` ${o.dim(`Restoring config for: ${e.configuredClients.join(", ")}`)}`:` ${o.dim("No previous config found \u2014 running full auto-configure")}`);const s=B();k(s);break}case"export":{const e=n.exportFormat??"mcp-json",s=T(e,{serverPath:n.serverPath,dbPath:n.dbPath});process.stderr.write(`${o.dim(`# Wyrm MCP config (${e}). Paste into any MCP-compatible host.`)}
2
+ import{existsSync as $,readFileSync as x}from"node:fs";import{BUNDLED_MODEL_SIZE_LABEL as R}from"./providers/bundled-model.js";import{homedir as y}from"node:os";import{join as S}from"node:path";import{detectClients as C,autoConfigureAll as M,removeFromAll as D,configureSpecific as L,reconfAll as N,getStatusSummary as W,findWyrmServerPath as _,getDefaultDbPath as A,loadWyrmMeta as B,exportServerConfig as j}from"./autoconfig.js";import{c as o,icons as g,BANNER as z,MINI_BANNER as f,printSuccess as O,printError as E,printWarning as T,printSection as d,createDownloadProgress as F}from"./cli.js";import{runWizard as U}from"./setup-wizard.js";function Y(n){const e=n.slice(2);if(e.length===0)return{command:"auto"};const s={command:"auto"};for(let l=0;l<e.length;l++)switch(e[l]){case"--check":case"-c":case"check":case"status":s.command="check";break;case"--remove":case"-r":case"remove":case"uninstall":s.command="remove";break;case"--only":case"-o":case"only":s.command="only",e[l+1]&&(s.clientIds=e[l+1].split(",").map(t=>t.trim()),l++);break;case"--reconf":case"--reconfigure":case"reconf":s.command="reconf";break;case"--list":case"-l":case"list":s.command="list";break;case"--export":case"export":{s.command="export";const t=e[l+1];(t==="stdio"||t==="vscode"||t==="mcp-json")&&(s.exportFormat=t,l++);break}case"--server":case"-s":e[l+1]&&(s.serverPath=e[l+1],l++);break;case"--db":case"-d":e[l+1]&&(s.dbPath=e[l+1],l++);break;case"--wizard":case"wizard":s.command="wizard";break;case"--no-wizard":case"--plain":s.noWizard=!0;break;case"--no-model":s.noModel=!0;break;case"--help":case"-h":case"help":s.command="help";break}return s}function w(n){console.log("");const e=n.filter(c=>c.action==="configured"),s=n.filter(c=>c.action==="updated"),l=n.filter(c=>c.action==="skipped"),t=n.filter(c=>c.action==="failed");for(const c of e)console.log(` ${g.success} ${c.client.icon} ${o.green(c.client.name)} \u2014 ${o.success("configured")}`),c.backup&&console.log(` ${o.dim(`backup \u2192 ${c.backup}`)}`);for(const c of s)console.log(` ${g.sync} ${c.client.icon} ${o.blue(c.client.name)} \u2014 ${o.cyan("updated")}`),c.backup&&console.log(` ${o.dim(`backup \u2192 ${c.backup}`)}`);for(const c of l)console.log(` ${o.dim(` \u25CB ${c.client.icon} ${c.client.name} \u2014 ${c.message}`)}`);for(const c of t)console.log(` ${g.error} ${c.client.icon} ${o.red(c.client.name)} \u2014 ${o.error(c.message)}`);console.log("");const p=[...e,...s].filter(c=>!c.client.id.startsWith("claude-code-")).length;p>0?(console.log(` ${o.success(`${g.dragon} Wyrm connected to ${p} AI client(s)`)}`),console.log(` ${o.dim("Switch AIs anytime \u2014 run wyrm-setup again to reconnect")}`)):t.length>0?console.log(` ${o.error("Some configurations failed. Check errors above.")}`):console.log(` ${o.dim("No AI clients detected. Install one and try again.")}`),console.log("")}function Z(n){return n.split(y()).join("~")}async function b(n,e){const{bundledModelPresent:s,downloadBundledModel:l,BUNDLED_MODEL_SIZE_LABEL:t}=await import("./providers/bundled-model.js"),{resolveEmbeddingState:p,tierForResolution:c}=await import("./providers/embedding-provider.js");if(d("Enabling meaning-based search"),s())console.log(o.dim(" Local embedding model already present."));else if(n)console.log(o.dim(" Skipped (--no-model). Recall is keyword-only until: wyrm vectors download"));else{console.log(o.dim(` Downloading nomic-embed-text-v1.5 (${t}, Apache-2.0, from huggingface.co with models.ghosts.lk as fallback). Skip with --no-model.`));const r=F(process.stdout),P=await l({onProgress:r.onProgress});if(r.finish(),P.ok){O(`Meaning-based search is on (${t}, local, no account).`);const{runBundledBackfill:I}=await import("./reindex.js");await I()}else T(`Could not download the model (${P.error}).`),console.log(o.dim(" Keyword search works fine meanwhile. Retry later: wyrm vectors download"))}d("Health check");const u=p(),i=c(u);console.log(` ${u.resolved!=="none"?"\u2714":"\u25CB"} search: ${i.label} (${u.resolved}${u.model?` \xB7 ${u.model}`:""})`);const k=A();console.log($(k)?` \u2714 memory file: ${Z(k)}`:" \u25CB memory file: created on first run");const a=e.find(r=>r.client.id==="claude-code-hooks");let m;if(a&&(a.action==="configured"||a.action==="updated"))m=!0,console.log(` \u2714 auto-memory hooks: ${a.action==="updated"?"updated":"installed"}`);else if(a&&a.action==="skipped"&&a.client.configured)m=!0,console.log(` \u2714 auto-memory hooks: ${a.message}`);else if(a)m=!1,console.log(` \u25CB auto-memory hooks: ${a.message}`);else{const r=S(y(),".claude","hooks","wyrm-session-capture.mjs");m=$(r),console.log(m?" \u2714 auto-memory hooks: already installed":" \u25CB auto-memory hooks: not installed by this command")}const v=e.find(r=>r.client.id==="claude-code-guard");let h;if(v)h=v.client.configured===!0;else{const r=S(y(),".claude","settings.json");try{h=$(r)&&/wyrm-guard/.test(x(r,"utf-8"))}catch{h=!1}}d("What happens automatically now"),console.log(m?" \u2022 Every session is captured to memory when it ends.":" \u2022 On this client, the model handles capture per server instructions."),console.log(m?" \u2022 Every new session starts with your context restored.":" \u2022 Each session starts by priming from memory (the model calls wyrm_session_prime first)."),console.log(h?" \u2022 The failure firewall blocks repeats of recorded mistakes. Always on.":" \u2022 The failure firewall arms once hooks are installed."),console.log(" \u2022 The store prunes and re-ranks itself daily. No cron, no timer to write."),console.log(" \u2022 The token firewall notes files you read in full twice; wyrm doctor shows what it found."),console.log(` \u2022 Something off? ${o.cyan("wyrm doctor")} fails loudly with the exact fix; ${o.cyan("wyrm report")} is the shareable diagnostic.`),console.log(""),console.log(i.n>=3?`Search: tier ${i.n}/3 (${i.label}).`:i.n===2?`Search: tier ${i.n}/3 (${i.label}). ${o.cyan("wyrm upgrade")} \u2192 max recall.`:`Search: tier ${i.n}/3 (${i.label}). ${o.cyan("wyrm vectors download")} \u2192 local vectors (free, no account); then ${o.cyan("wyrm upgrade")} \u2192 max recall.`)}function H(){console.log(f()),console.log(""),console.log(`${o.bold("Usage:")} wyrm-setup ${o.dim("[command] [options]")}`),console.log(""),console.log(`${o.bold("Commands:")}`),console.log(` ${o.cyan("(no args)")} Auto-detect and configure all AI clients`),console.log(` ${o.cyan("check")} Show current configuration status`),console.log(` ${o.cyan("list")} List all supported AI clients`),console.log(` ${o.cyan("remove")} Remove Wyrm from all AI clients`),console.log(` ${o.cyan("reconf")} Re-configure previously configured clients`),console.log(` ${o.cyan("only X,Y")} Configure specific clients only`),console.log(` ${o.cyan("export [fmt]")} Print a portable config (fmt: mcp-json|vscode|stdio) for any MCP host`),console.log(` ${o.cyan("help")} Show this help message`),console.log(""),console.log(`${o.bold("Options:")}`),console.log(` ${o.cyan("--server P")} Override Wyrm MCP server path`),console.log(` ${o.cyan("--db P")} Override Wyrm database path`),console.log(` ${o.cyan("--no-model")} Skip the one-time local embedding model download (${R}); recall stays keyword-only`),console.log(` ${o.cyan("--plain")} Non-interactive flag flow (no wizard) \u2014 the default when not on a TTY`),console.log(""),console.log(`${o.bold("Client IDs:")}`);const n=C();for(const e of n)console.log(` ${e.icon} ${o.cyan(e.id.padEnd(18))} ${e.name}`);console.log(""),console.log(`${o.bold("Examples:")}`),console.log(` wyrm-setup ${o.dim("# Auto-configure everything")}`),console.log(` wyrm-setup check ${o.dim("# See what's configured")}`),console.log(` wyrm-setup only vscode-copilot,cursor ${o.dim("# Only VS Code + Cursor")}`),console.log(` wyrm-setup --server /path/to/wyrm/dist/index.js ${o.dim("# Custom server path")}`),console.log(` wyrm-setup remove ${o.dim("# Remove from all clients")}`),console.log(` wyrm-setup export stdio > wyrm.json ${o.dim("# Portable config for any MCP host")}`),console.log("")}function J(){console.log(f()),console.log(""),d("Supported AI Clients"),console.log("");const n=C();for(const e of n){const s=e.detected?e.configured?o.success("\u25CF connected"):o.yellow("\u25D0 available"):o.dim("\u25CB not found"),l=e.version?` ${o.dim(`v${e.version}`)}`:"";console.log(` ${e.icon} ${o.bold(e.name.padEnd(20))} ${o.cyan(e.id.padEnd(18))} ${s}${l}`),console.log(` ${o.dim(`Config: ${e.configPath}`)}`)}console.log("")}async function K(){const n=Y(process.argv);if(n.command==="wizard"||n.command==="auto"&&!n.noWizard){const e=await U({serverPath:n.serverPath,dbPath:n.dbPath});if(e===!1)n.command==="wizard"&&(n.command="auto");else if(e===null){console.log(o.dim("Setup aborted, nothing changed."));return}else{await b(n.noModel??!1,e);return}}switch(n.command){case"help":H();break;case"check":{console.log(f()),console.log(""),console.log(W());break}case"list":J();break;case"auto":{console.log(z()),d("Auto-Configure"),console.log("");const e=n.serverPath||_(),s=n.dbPath||A();console.log(` ${g.sword} Server: ${o.cyan(e)}`),console.log(` ${g.treasure} DB: ${o.cyan(s)}`),console.log(""),console.log(` ${o.dim("Scanning for AI clients...")}`);const l=M({serverPath:e,dbPath:s});w(l),await b(n.noModel??!1,l);break}case"only":{(!n.clientIds||n.clientIds.length===0)&&(E("No client IDs specified. Use: wyrm-setup only vscode-copilot,cursor"),process.exit(1)),console.log(f()),d(`Configure: ${n.clientIds.join(", ")}`);const e=L(n.clientIds,{serverPath:n.serverPath,dbPath:n.dbPath});w(e),await b(n.noModel??!1,e);break}case"remove":{console.log(f()),d("Remove Wyrm from AI Clients"),console.log(""),console.log(` ${o.warning("Removing Wyrm configuration from all AI clients...")}`);const e=D(),s=e.filter(t=>t.action==="configured"),l=e.filter(t=>t.action==="skipped");for(const t of s)console.log(` ${g.check} ${t.client.icon} ${t.client.name} \u2014 removed`),t.backup&&console.log(` ${o.dim(`backup \u2192 ${t.backup}`)}`);for(const t of l)console.log(` ${o.dim(` \u25CB ${t.client.icon} ${t.client.name} \u2014 ${t.message}`)}`);console.log(""),s.length>0&&console.log(` ${o.success(`Removed from ${s.length} client(s). Run wyrm-setup to reconnect.`)}`),console.log("");break}case"reconf":{console.log(f()),d("Re-Configure");const e=B();console.log(e?` ${o.dim(`Restoring config for: ${e.configuredClients.join(", ")}`)}`:` ${o.dim("No previous config found \u2014 running full auto-configure")}`);const s=N();w(s);break}case"export":{const e=n.exportFormat??"mcp-json",s=j(e,{serverPath:n.serverPath,dbPath:n.dbPath});process.stderr.write(`${o.dim(`# Wyrm MCP config (${e}). Paste into any MCP-compatible host.`)}
4
3
  `),process.stdout.write(JSON.stringify(s,null,2)+`
5
- `);break}}}X().catch(n=>{x(`Setup failed: ${n}`),process.exit(1)});
4
+ `);break}}}K().catch(n=>{E(`Setup failed: ${n}`),process.exit(1)});
@@ -1 +1 @@
1
- import{renderErrorResponse as o}from"./render.js";const n="WYRM_BUSY",i="WYRM_CIRCUIT_OPEN",s="WYRM_DAEMON_AMBIGUOUS",a=1e3,c=3e4;function u(e){if(e===null||typeof e!="object")return!1;const t=e.code;return typeof t=="string"&&t.startsWith("SQLITE_BUSY")}function p(e){if(e===null||typeof e!="object")return!1;const t=e.code;return typeof t=="string"&&t.startsWith("SQLITE_CONSTRAINT")}function _(e){if(u(e))return"lock";if(e===null||typeof e!="object")return null;const t=e.code;return t===i?"circuit":t===s?"daemon":null}function d(e,t="lock"){const r=t==="circuit"?`${e}: the Wyrm write path's circuit breaker is open after repeated write failures (WYRM_CIRCUIT_OPEN); writes are refused until it half-opens (~30s).`:t==="daemon"?`${e}: the daemon write outcome is unknown (WYRM_DAEMON_WRITES=1 and the daemon stopped responding mid-write); the local fallback was withheld to avoid a duplicate row.`:`${e}: the Wyrm database is briefly write-locked by another process (SQLITE_BUSY \u2014 the cross-process write lock outlived the busy_timeout grace window, or a read-then-write transaction lost a snapshot upgrade race).`;return{error:{code:n,message:r,retryable:!0,retry_after_ms:t==="circuit"?c:a},expected:`Retry the SAME ${e} call with the SAME arguments after retry_after_ms; no arguments need to change. Retrying is safe: writes are transactional or coalesce by key (a retried failure_record may count one extra occurrence by design`+(t==="daemon"?"; forwarded writes reuse their idempotency key inside the retry window, so the daemon cannot apply the write twice":"")+")."}}function f(e,t="lock"){return o(d(e,t))}export{a as BUSY_RETRY_AFTER_MS,c as CIRCUIT_RETRY_AFTER_MS,n as WYRM_BUSY_CODE,i as WYRM_CIRCUIT_OPEN_CODE,s as WYRM_DAEMON_AMBIGUOUS_CODE,d as busyErrorBody,f as busyErrorResponse,u as isSqliteBusyError,p as isSqliteConstraintError,_ as retryableWriteCause};
1
+ import{renderErrorResponse as o}from"./render.js";const n="WYRM_BUSY",i="WYRM_CIRCUIT_OPEN",s="WYRM_DAEMON_AMBIGUOUS",a=1e3,c=3e4;function u(e){if(e===null||typeof e!="object")return!1;const t=e.code;return typeof t=="string"&&t.startsWith("SQLITE_BUSY")}function p(e){if(e===null||typeof e!="object")return!1;const t=e.code;return typeof t=="string"&&t.startsWith("SQLITE_CONSTRAINT")}function _(e){if(u(e))return"lock";if(e===null||typeof e!="object")return null;const t=e.code;return t===i?"circuit":t===s?"daemon":null}function d(e,t="lock"){const r=t==="circuit"?`${e}: the Wyrm write path's circuit breaker is open after repeated write failures (WYRM_CIRCUIT_OPEN); writes are refused until it half-opens (~30s).`:t==="daemon"?`${e}: the daemon write outcome is unknown (WYRM_DAEMON_WRITES=1 and the daemon stopped responding mid-write); the local fallback was withheld to avoid a duplicate row.`:`${e}: the Wyrm database is briefly write-locked by another process (SQLITE_BUSY: the cross-process write lock outlived the busy_timeout grace window, or a read-then-write transaction lost a snapshot upgrade race).`;return{error:{code:n,message:r,retryable:!0,retry_after_ms:t==="circuit"?c:a},expected:`Retry the SAME ${e} call with the SAME arguments after retry_after_ms; no arguments need to change. Retrying is safe: writes are transactional or coalesce by key (a retried failure_record may count one extra occurrence by design`+(t==="daemon"?"; forwarded writes reuse their idempotency key inside the retry window, so the daemon cannot apply the write twice":"")+")."}}function f(e,t="lock"){return o(d(e,t),e)}export{a as BUSY_RETRY_AFTER_MS,c as CIRCUIT_RETRY_AFTER_MS,n as WYRM_BUSY_CODE,i as WYRM_CIRCUIT_OPEN_CODE,s as WYRM_DAEMON_AMBIGUOUS_CODE,d as busyErrorBody,f as busyErrorResponse,u as isSqliteBusyError,p as isSqliteConstraintError,_ as retryableWriteCause};
@@ -0,0 +1,2 @@
1
+ import{readFileSync as f,statSync as p}from"node:fs";import{dirname as m,join as u}from"node:path";import{fileURLToPath as d}from"node:url";import{LIVE_EMBEDDING_KEY as M,pidAlive as b}from"./live-embedding-state.js";const y=100,A=5e3,E=e=>f(e,"utf8");function N(e,r=E){if(!Number.isInteger(e)||e<=0)return null;try{const s=r(`/proc/${e}/stat`),o=s.slice(s.lastIndexOf(")")+2).trim().split(/\s+/),i=Number(o[19]),a=r("/proc/stat").split(`
2
+ `).find(n=>n.startsWith("btime ")),t=Number(a?.split(/\s+/)[1]);return!Number.isFinite(i)||!Number.isFinite(t)||a===void 0?null:t*1e3+Math.round(i*1e3/y)}catch{return null}}function _(e=u(m(d(import.meta.url)),"..")){let r=null;for(const s of[u(e,"package.json"),u(e,"dist","index.js")])try{const o=p(s),i=Math.max(o.mtimeMs,o.ctimeMs);r=r===null?i:Math.max(r,i)}catch{}return r}function g(e,r={}){const s=r.alive??b,o=r.startOf??(t=>N(t));let i;try{const t=e.prepare("SELECT value FROM wyrm_meta WHERE key = ?").get(M);if(!t)return[];const n=JSON.parse(t.value);if(!n||typeof n!="object"||Array.isArray(n))return[];i=n}catch{return[]}const a=[];for(const t of Object.values(i)){if(!t||typeof t.pid!="number"||!s(t.pid))continue;const n=typeof t.at=="string"?Date.parse(t.at):NaN,c=o(t.pid);if(c!==null&&Number.isFinite(n)&&c>n+6e4)continue;const l=c??n;Number.isFinite(l)&&a.push({pid:t.pid,cwd:typeof t.cwd=="string"?t.cwd:"",startedAtMs:l})}return a.sort((t,n)=>t.startedAtMs-n.startedAtMs)}function w(e,r){return e.filter(s=>s.startedAtMs<r-A)}export{A as STALE_GRACE_MS,g as liveServers,_ as packageInstalledAtMs,N as processStartMs,w as serversPredatingInstall};
@@ -0,0 +1 @@
1
+ const S=2e3,T=3e4;function x(e=process.env){const t=e.WYRM_STDIO_DRAIN_MS;if(t===void 0||t.trim()==="")return 3e4;const n=Number(t);return Number.isInteger(n)&&n>=0?n:3e4}const A=e=>`${typeof e}:${String(e)}`,M=e=>typeof e.method=="string"&&e.id!==void 0&&e.id!==null,w=e=>e.method===void 0&&e.id!==void 0&&("result"in e||"error"in e);function D(e){const t=new Set,n=new Set,s=o=>{if(!(!t.delete(A(o))||t.size>0))for(const c of[...n])c()},i={start:()=>e.start(),close:()=>e.close(),async send(o,c){try{await e.send(o,c)}finally{w(o)&&s(o.id)}},get sessionId(){return e.sessionId}};return e.setProtocolVersion&&(i.setProtocolVersion=o=>e.setProtocolVersion?.(o)),e.onmessage=(o,c)=>{const d=o;M(d)?t.add(A(d.id)):d.method==="notifications/cancelled"&&d.params?.requestId!==void 0&&s(d.params.requestId),i.onmessage?.(o,c)},e.onclose=()=>i.onclose?.(),e.onerror=o=>i.onerror?.(o),{transport:i,inFlight:{size:()=>t.size,onIdle(o){return n.add(o),()=>{n.delete(o)}}}}}function E(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}function P(e,t){let n=!1;const s=()=>{n||(n=!0,clearTimeout(i),t())},i=setTimeout(s,1e3);try{e.write("",s)}catch{s()}}function F(e){const t=e.stdin??process.stdin,n=e.stdout??process.stdout,s=e.getPpid??(()=>process.ppid),i=e.isAlive??E,o=e.log??(r=>{try{console.error(r)}catch{}}),c=s();let d=!1,g=!1,u,f;const l=r=>{d||(d=!0,clearInterval(h),clearTimeout(u),f?.(),r==="stdin-end"||r==="stdin-close"?P(n,()=>e.onOrphan(r)):e.onOrphan(r))},a=r=>{if(d||g)return;const _=e.inFlight?.size()??0;if(_===0){l(r);return}g=!0;const p=e.drainMs??3e4;o(`Wyrm: stdin closed with ${_} request(s) in flight; answering before exit (up to ${p} ms)`),f=e.inFlight?.onIdle(()=>l(r)),u=setTimeout(()=>{o(`Wyrm: ${e.inFlight?.size()??0} request(s) still in flight after ${p} ms; exiting without them`),l(r)},p)},m=()=>a("stdin-end"),I=()=>a("stdin-close"),y=r=>{if(r?.code==="EPIPE"){l("stdout-epipe");return}o(`Wyrm[stdout]: ${r?.message??r}`)};t.on("end",m),t.on("close",I),n.on("error",y);const h=setInterval(()=>{(s()!==c||c>1&&!i(c))&&l("parent-exited")},e.intervalMs??2e3);return h.unref?.(),(t.readableEnded||t.destroyed)&&queueMicrotask(()=>a("stdin-end")),()=>{d=!0,clearInterval(h),clearTimeout(u),f?.(),t.off("end",m),t.off("close",I),n.off("error",y)}}function R(e,t=n=>process.exit(n)){let n=!1;return s=>{if(!n){if(n=!0,s)try{console.error(`Wyrm: ${s}, shutting down`)}catch{}for(const i of e)try{i()}catch{}t(0)}}}export{T as DEFAULT_DRAIN_MS,S as PARENT_POLL_MS,R as makeShutdown,E as pidAlive,x as resolveDrainMs,D as trackInFlight,F as watchForOrphaning};
@@ -1,4 +1,4 @@
1
- import o from"better-sqlite3";import{createRequire as l}from"node:module";import{NodeSqliteFacade as n}from"./node-sqlite-facade.js";const d=l(import.meta.url);let i=!1;function s(){try{return d("node:sqlite"),!0}catch{return!1}}function u(){if(process.env.WYRM_STORAGE==="node"){if(s())return"node";i||(i=!0,process.stderr.write(`wyrm: WYRM_STORAGE=node requested but node:sqlite is unavailable in this Node runtime; falling back to better-sqlite3
2
- `))}return"better-sqlite3"}function c(e){const t=e instanceof Error?e.message:String(e);return/bindings file|better_sqlite3\.node|did not self-register|NODE_MODULE_VERSION|different Node\.js version|ERR_DLOPEN|invalid ELF header|Cannot find module/i.test(t)}function q(e,t={}){if(u()==="node")return new n(e,t);try{return new o(e,t)}catch(r){if(c(r)&&s()){if(!i){i=!0;const a=r instanceof Error?r.message.split(`
1
+ import l from"better-sqlite3";import{createRequire as d}from"node:module";import{NodeSqliteFacade as o}from"./node-sqlite-facade.js";const u=d(import.meta.url);let i=!1;function s(){try{return u("node:sqlite"),!0}catch{return!1}}function c(){if(process.env.WYRM_STORAGE==="node"){if(s())return"node";i||(i=!0,process.stderr.write(`wyrm: WYRM_STORAGE=node requested but node:sqlite is unavailable in this Node runtime; falling back to better-sqlite3
2
+ `))}return"better-sqlite3"}function f(e){const t=e instanceof Error?e.message:String(e);return/bindings file|better_sqlite3\.node|did not self-register|NODE_MODULE_VERSION|different Node\.js version|ERR_DLOPEN|invalid ELF header|Cannot find module/i.test(t)}function w(e,t={}){if(c()==="node")return new o(e,t);const n=process.report;n&&(n.excludeNetwork=!0);try{return new l(e,t)}catch(r){if(f(r)&&s()){if(!i){i=!0;const a=r instanceof Error?r.message.split(`
3
3
  `)[0]:String(r);process.stderr.write(`wyrm: better-sqlite3 native binding unavailable (${a}); falling back to built-in node:sqlite (experimental). Rebuild the native driver with: npm install -g wyrm-mcp --allow-scripts=wyrm-mcp,better-sqlite3
4
- `)}return new n(e,t)}throw r}}export{q as openDatabase,u as resolveBackend};
4
+ `)}return new o(e,t)}throw r}}export{w as openDatabase,c as resolveBackend};