wyrm-mcp 9.2.2 → 9.2.3

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 (118) hide show
  1. package/dist/activation.js +1 -1
  2. package/dist/agent-loop.js +2 -2
  3. package/dist/audit.js +2 -2
  4. package/dist/autoconfig.js +6 -6
  5. package/dist/backup-cli.js +6 -0
  6. package/dist/backup.js +1 -0
  7. package/dist/bridge.js +1 -1
  8. package/dist/buddy-runner.js +1 -1
  9. package/dist/buddy.js +4 -4
  10. package/dist/capabilities.js +1 -1
  11. package/dist/causality.js +3 -3
  12. package/dist/cloud/cli.js +3 -3
  13. package/dist/cloud/sync-daemon-entrypoint.js +1 -1
  14. package/dist/cloud/sync-engine.js +8 -7
  15. package/dist/cloud-backup.js +4 -4
  16. package/dist/cloud-sync-entrypoint.js +1 -1
  17. package/dist/cloud-sync.js +1 -1
  18. package/dist/connectors/ingest.js +2 -2
  19. package/dist/constellation.js +1 -1
  20. package/dist/context-build-budgeted.js +4 -4
  21. package/dist/context-ranking.js +1 -1
  22. package/dist/daemon-writer.js +1 -1
  23. package/dist/database.js +41 -23
  24. package/dist/design.js +1 -1
  25. package/dist/erasure-cli.js +3 -0
  26. package/dist/erasure-log.js +8 -0
  27. package/dist/erasure.js +1 -0
  28. package/dist/event-replication.js +1 -1
  29. package/dist/events.js +11 -11
  30. package/dist/failure-patterns.js +67 -44
  31. package/dist/federation.js +11 -10
  32. package/dist/governance.js +1 -0
  33. package/dist/handlers/agent.js +4 -4
  34. package/dist/handlers/alias-adapters.js +1 -1
  35. package/dist/handlers/audit.js +1 -1
  36. package/dist/handlers/boundary.js +1 -1
  37. package/dist/handlers/capture.js +54 -52
  38. package/dist/handlers/causality.js +2 -2
  39. package/dist/handlers/cloud.js +9 -9
  40. package/dist/handlers/companion.js +4 -4
  41. package/dist/handlers/entity.js +6 -6
  42. package/dist/handlers/events.js +4 -4
  43. package/dist/handlers/failure.js +15 -12
  44. package/dist/handlers/goals.js +2 -2
  45. package/dist/handlers/intelligence.js +81 -74
  46. package/dist/handlers/mcpclient.js +3 -3
  47. package/dist/handlers/presence.js +1 -1
  48. package/dist/handlers/prompts.js +2 -2
  49. package/dist/handlers/quest.js +11 -4
  50. package/dist/handlers/recall.js +10 -10
  51. package/dist/handlers/resources.js +1 -1
  52. package/dist/handlers/review.js +3 -3
  53. package/dist/handlers/run.js +3 -3
  54. package/dist/handlers/search.js +1 -1
  55. package/dist/handlers/session.js +27 -25
  56. package/dist/handlers/share.js +3 -3
  57. package/dist/handlers/skill.js +2 -2
  58. package/dist/handlers/symbols.js +5 -5
  59. package/dist/handlers/syncops.js +2 -2
  60. package/dist/harvest.js +5 -5
  61. package/dist/hours.js +1 -1
  62. package/dist/http-auth.js +2 -2
  63. package/dist/http-fast.js +17 -17
  64. package/dist/http-projects.js +4 -0
  65. package/dist/http-rate-limit.js +1 -0
  66. package/dist/index-health.js +52 -0
  67. package/dist/index.js +2 -2
  68. package/dist/indexer.js +4 -4
  69. package/dist/intelligence.js +36 -29
  70. package/dist/lane-provenance.js +39 -0
  71. package/dist/license.js +1 -1
  72. package/dist/lineage.js +15 -0
  73. package/dist/live-embedding-state.js +2 -2
  74. package/dist/maintenance.js +2 -2
  75. package/dist/mcp-integrity.js +2 -2
  76. package/dist/memory-artifacts.js +39 -37
  77. package/dist/metabolize.js +9 -7
  78. package/dist/metrics.js +1 -1
  79. package/dist/migrate-prompt.js +1 -1
  80. package/dist/migrations.js +236 -45
  81. package/dist/priority-embed.js +1 -1
  82. package/dist/providers/embedding-provider.js +1 -1
  83. package/dist/readonly-gate.js +1 -1
  84. package/dist/redact-backfill.js +1 -0
  85. package/dist/rehydration.js +30 -20
  86. package/dist/reindex.js +1 -1
  87. package/dist/render-target.js +6 -6
  88. package/dist/repl-guard.js +1 -1
  89. package/dist/replication-daemon-entrypoint.js +1 -1
  90. package/dist/replication-daemon.js +1 -1
  91. package/dist/retention.js +1 -0
  92. package/dist/reverse-bridge.js +6 -6
  93. package/dist/review-sample.js +31 -0
  94. package/dist/security.js +1 -1
  95. package/dist/self-maintenance.js +4 -4
  96. package/dist/served-records.js +8 -2
  97. package/dist/setup-wizard.js +1 -1
  98. package/dist/setup.js +1 -1
  99. package/dist/skill-author.js +2 -2
  100. package/dist/store-open.js +1 -0
  101. package/dist/store-readonly.js +1 -0
  102. package/dist/sub-agent.js +2 -2
  103. package/dist/tool-manifest-v2.json +1 -1
  104. package/dist/tool-manifest.json +1 -1
  105. package/dist/truth-freshness.js +8 -0
  106. package/dist/ui-dashboard.js +4 -4
  107. package/dist/vault.js +1 -1
  108. package/dist/vector-init.js +1 -1
  109. package/dist/vectors.js +4 -3
  110. package/dist/visibility.js +12 -12
  111. package/dist/write-guard.js +1 -0
  112. package/dist/wyrm-cli.js +108 -92
  113. package/dist/wyrm-guard.js +13 -12
  114. package/dist/wyrm-loop.js +3 -3
  115. package/dist/wyrm-manifest.json +1 -1
  116. package/dist/wyrm-memo.js +5 -5
  117. package/package.json +1 -1
  118. package/scripts/hooks/wyrm-session-capture.mjs +3 -0
package/dist/http-fast.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
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(`
2
+ import re from"http";import{WyrmDB as x}from"./database.js";import{cache as h,estimateTokens as ne,truncateToTokens as se,timed as $}from"./performance.js";import{authMiddleware as oe,getAuthStatus as w,getSecurityHeaders as P,getUiNonce as ae,siteContextFor as ie}from"./http-auth.js";import{refuseWrite as ce}from"./write-guard.js";import{WyrmLogger as le}from"./logger.js";import{SecurityError as ue,sanitizeFtsQuery as q,validateProjectPath as de}from"./security.js";import{listProjectsPage as pe,parseProjectListQuery as me,registerProjectAt as fe}from"./http-projects.js";import{readFileSync as L,existsSync as T,readdirSync as Ee,realpathSync as Y}from"fs";import{homedir as he}from"os";import{dirname as B,join as y}from"path";import{fileURLToPath as _e}from"url";let b=null;function Se(){if(b!==null)return b;b="unknown";try{const e=B(_e(import.meta.url));for(const t of[y(e,"..","package.json"),y(e,"..","..","package.json")]){if(!T(t))continue;const r=JSON.parse(L(t,"utf-8")).version;if(typeof r=="string"){b=r;break}}}catch{}return b}import{getUIDashboardHTML as ye}from"./ui-dashboard.js";import{resolveBranding as F}from"./branding.js";import{verifyLicense as J,getLicenseInfo as ge}from"./license.js";import{loadRevocations as Te,refreshRevocations as Oe}from"./revocations.js";import{rerankConfigured as Re,rerankEgressHost as ve}from"./rerank.js";import{MemoryArtifacts as Ce}from"./memory-artifacts.js";import{createVectorStore as Le}from"./vectors.js";import{scheduleMaintenanceSweep as be}from"./self-maintenance.js";import{GroundTruths as je,computeStaleness as Ne}from"./intelligence.js";import{Causality as Me}from"./causality.js";import{wireTruthAutoCascade as Ae}from"./truth-cascade.js";import{FailurePatterns as De}from"./failure-patterns.js";import{handleDaemonWrite as Ie}from"./daemon-write-endpoint.js";import{retryableWriteCause as K,busyErrorBody as Q}from"./sqlite-busy.js";import{sseFrame as ke,resolveStartCursor as V,SSE_KEEPALIVE as we}from"./events-sse.js";import{readonlyBlocks as Pe}from"./readonly-gate.js";import{resolveActorEnvelope as Fe,runWithActor as He,setDefaultWriter as We}from"./handlers/boundary.js";import{setGovernanceSurface as Ge}from"./governance.js";import{asNewerStoreError as Ue,NEWER_STORE_CODE as xe}from"./store-readonly.js";Ge("http");function X(e,t,r){const n=Ue(r);return n?(E(e,t,{e:n.message,code:xe,readonly:1,store_schema:n.store,binary_schema:n.binary},503),!0):!1}function $e(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 qe=/^(?:(?:0+\.){3}0+|::)$/;function Ye(e,t){const r=e===""||qe.test(e)?"127.0.0.1":e;return`http://${r.includes(":")?`[${r}]`:r}:${t}/ui`}const j=$e(),O=process.env.WYRM_UI_READONLY==="1",Be=512*1024,D=500,Je=parseInt(process.env.WYRM_MAX_SSE_STREAMS||"64",10)||64,Ke=parseInt(process.env.WYRM_MAX_SSE_PER_IP||"8",10)||8;let H=0;const R=new Map;let N=!1;const W=new Set;let v=null,M=null,A=null,I=null;function a(){return v||(v=new x(process.env.WYRM_DB_PATH)),v}function g(){if(!M){M=new Ce(a().getDatabase());try{const e=process.env.WYRM_VECTOR_PROVIDER||"auto";e!=="none"&&M.setVectorStore(Le({provider:e},a().getDatabase()))}catch{}}return M}function Qe(){return A||(A=new je(a().getDatabase()),Ae(A,new Me(a().getDatabase()))),A}function Ve(){return I||(I=new De(a().getDatabase())),I}function Xe(e){const t=v;v=e,M=null,A=null,I=null;try{t?.close()}catch{}}async function ze(e={}){Te(e.publicKeyPem),await Oe(e).catch(()=>{})}function z(){const e=[],t=he(),r=new Set;let n=[];try{n=Ee(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=Y(y(t,s))}catch{continue}if(r.has(o))continue;const l=y(o,"wyrm.db");if(!T(l))continue;r.add(o);let i="Local",u="free";try{const c=y(o,"license.json");if(T(c)){const m=JSON.parse(L(c,"utf-8")),p=J(m);i=m.license&&m.license.issued_to||i,u=p.valid?p.tier:"free"}else{const m=y(o,"cloud.json");T(m)&&(i=JSON.parse(L(m,"utf-8")).email||i)}}catch{}const d=s.replace(/^\.wyrm-?/,"")||"default";e.push({name:d,dbPath:l,account:i,tier:u})}return e}const k=new le({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 G(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=P(t);e.writeHead(n,{"Content-Type":"application/json","Content-Length":Buffer.byteLength(s),"X-Tokens":String(ne(r)),...o,...N?{Connection:"close"}:{}}),e.end(s)}function Ze(e,t,r){const n=P(t);e.writeHead(200,{...n,"Content-Type":"text/html; charset=utf-8","Content-Length":Buffer.byteLength(r),"Cache-Control":"no-store",...N?{Connection:"close"}:{}}),e.end(r)}function et(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 Z={"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 l=a().getPendingQuests(o.id),i=a().getRecentSessions(o.id,3);s={n:o.name,s:o.stack,q:l.length,qt:l.slice(0,5).map(u=>u.title),r:i[0]?.summary||i[0]?.notes?.slice(0,200)||null}}else{const o=a().getAllProjects(20),l=a().getAllPendingQuests();s={p:o.map(i=>({n:i.name,s:i.stack,q:a().getPendingQuests(i.id).length})),tq:l.length}}return h.set(t,s),s},"GET /p":e=>{const t=me(e);if(t)return pe(a(),t);const r=h.get("projects");if(r)return r;const s=a().getAllProjects(50).map(o=>({i:o.id,n:o.name,p:o.path,s:o.stack}));return h.set("projects",s),s},"POST /scan":e=>{const t=e.d||e.directory||process.env.HOME+"/Git Projects";let r;try{r=de(t)}catch{return{e:"path not allowed"}}return h.invalidate(),{found:a().scanForProjects(r,!0).length}},"POST /pa":e=>{const t=fe(a(),e);return"e"in t||(h.invalidate("projects"),h.invalidate("ctx")),t},"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){try{a().scanForProjects(t,!1)}catch(s){if(s instanceof ue)return{e:"path not allowed"};throw s}r=a().getProject(t)}if(!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=q(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:se(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 l=a().searchData(n,r.id);return s&&(l=l.filter(i=>i.category===s)),l.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,l=_(e.l,1e3,1e4),i={};for(const u of a().queryData(r.id,n,l)){let d;try{d=JSON.parse(u.value)}catch{continue}if(s&&d.stack_key!==s||o&&d.scanner!==o)continue;const c=String(d.scanner??""),m=String(d.payload_hash??"");if(!c||!m)continue;const p=`${c}:${m}`,f=i[p]??{s:c,ph:m,sk:String(d.stack_key??""),h:0,t:0};f.t+=1,d.hit&&(f.h+=1),i[p]=f}return Object.values(i).map(u=>({...u,r:u.t>0?u.h/u.t:0})).sort((u,d)=>d.r-u.r||d.h-u.h)},"POST /batch":e=>{const t=e.ops;if(!t||!Array.isArray(t))return{e:"ops required"};if(t.length>D)return{e:`max ${D} ops per batch`};const r=performance.now();return{r:t.map(s=>{const o=`${s.m} ${s.r}`,l=Z[o];if(!l)return{e:"unknown"};try{return{d:l(s.a||{})}}catch{return{e:"op failed"}}}),ms:Math.round(performance.now()-r)}},"POST /write":e=>Ie({db:a(),artifacts:g(),truths:Qe(),failures:Ve()},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,63 +19,63 @@ import V 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,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}
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 u=a().getProject(s);u&&(n=u.id)}const o=Array.isArray(e.tool_names)?e.tool_names.map(u=>String(u)):e.tool_names!=null?String(e.tool_names):null,l=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(l)?l:null})}}catch(u){return{e:u.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",l=[["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(d=>d.name==="sync_policy")?"AND (project_id IS NULL OR project_id IN (SELECT id FROM projects WHERE sync_policy = 'team'))":""}catch{return""}})();for(const[u,d,c]of l){if(s.length>=r)break;try{const m=n.prepare(`SELECT * FROM ${d}
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 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(`
25
+ LIMIT ?`).all(o,Math.max(1,r-s.length));for(const p of m)s.push({kind:u,id:p.id,project_id:p.project_id??null,updated_at:p[c]??null,payload:p})}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=G(e.project??e.p);if(!t)return{e:"not found"};const r=V(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),l=o.length?o[o.length-1].cursor:r;return{project:t.name,cursor:l,count:o.length,events:o}},"POST /events":e=>{if(!a().liveMemoryEnabled())return{e:"live memory disabled",disabled:1};const t=G(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>D)return{e:`max ${D} events per request`};let n=0,s=0,o=0;for(const l of r){const i=a().ingestRemoteEvent(t.id,l);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}=$(()=>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=g().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:Re()?1:0,provider:(process.env.WYRM_RERANK_PROVIDER||"llamacpp").trim()||"llamacpp",egress:ve()??"none"},r},"GET /auth/status":()=>{const e=w();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,l=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,u=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: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=`
28
+ `).all();return{projects:t,sessions:r,active_quests:n,data_points:s,artifacts:o,review_queue:l,truths:i,recent_sessions:u}},"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):"",l=(r-1)*n;let i,u,d,c;if(o){const f=q(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
32
32
  LEFT JOIN projects p ON ma.project_id = p.id
33
33
  WHERE memory_artifacts_fts MATCH ? AND ma.kind = ?
34
34
  AND ma.supersedes_id IS NULL
35
- ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,l=`
35
+ ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,u=`
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,u],c=[f,s]):(i=`
39
+ AND ma.supersedes_id IS NULL`,d=[f,s,n,l],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
43
43
  LEFT JOIN projects p ON ma.project_id = p.id
44
44
  WHERE memory_artifacts_fts MATCH ? AND ma.supersedes_id IS NULL
45
- ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,l=`
45
+ ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,u=`
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,u],c=[f])}else s?(i=`
48
+ WHERE memory_artifacts_fts MATCH ? AND ma.supersedes_id IS NULL`,d=[f,n,l],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,u],c=[s]):(i=`
53
+ ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,u="SELECT COUNT(*) as c FROM memory_artifacts WHERE kind = ? AND supersedes_id IS NULL",d=[s,n,l],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,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(`
58
+ ORDER BY ma.confidence DESC LIMIT ? OFFSET ?`,u="SELECT COUNT(*) as c FROM memory_artifacts WHERE supersedes_id IS NULL",d=[n,l],c=[]);const m=t.prepare(i).all(...d),p=t.prepare(u).get(...c).c;return{items:m,total:p,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,...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(`
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,...m)=>{try{const p=e.prepare(c).get(...m);return p?Object.values(p)[0]??0:0}catch{return 0}},r=(c,...m)=>{try{return e.prepare(c).all(...m)}catch{return[]}},n=F(!1).fleetGrove,o=(()=>{try{return e.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(n)}catch{return}})()?.id??-1,l=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 m=(Date.now()-new Date(c.last_heartbeat.replace(" ","T")+"Z").getTime())/1e3;return m>=0&&m<(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)},u=[];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))u.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 m=String(c.tags).includes("verdict")?"verdict":String(c.tags).includes("receipt")?"receipt":"note";u.push({type:m,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))u.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)});u.sort((c,m)=>String(m.ts).localeCompare(String(c.ts)));const d={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:l,loop:i,metrics:d,feed:u.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),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(`
69
+ `).all(n,s),l=t.prepare("SELECT COUNT(*) as c FROM ground_truths WHERE is_current = 1").get().c;return{items:o.map(u=>({...u,staleness:Ne(u)})),total:l,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=$(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=B(a().getDatabasePath());try{const t=y(e,"license.json");if(T(t)){const r=JSON.parse(L(t,"utf-8")),n=J(r);return{account:r.license&&r.license.issued_to||"unknown",tier:n.valid?n.tier:"free",valid:!!n.valid,expires:n.expiresAt||null,readonly:O}}}catch{}try{const t=y(e,"cloud.json");if(T(t))return{account:JSON.parse(L(t,"utf-8")).email||"Local",tier:"free",valid:!1,expires:null,readonly:O}}catch{}return{account:"Local",tier:"free",valid:!1,expires:null,readonly:O}},"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 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
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 g().recallHybridGlobal(t,{limit:r,kind:n})).map(l=>({...l.artifact,relevance:Math.round(l.relevance_score*1e3)/1e3,match_type:l.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 g().recallHybridGlobal(t,{limit:r}),o=[],l=[];let i=0;for(const u of s){const d=u.artifact,c=String(d.problem??d.title??d.summary??d.key??d.kind??"").trim(),m=String(d.validated_fix??d.content??d.body??d.value??d.problem??"").replace(/\s+/g," ").trim(),p=`- ${c}${m?": "+m.slice(0,320):""}`,f=Math.ceil(p.length/4);i+f<=n?(o.push(p),i+=f):o.push(`- ${c.slice(0,64)} \u2026 (recall for detail)`),l.push({...d,relevance:Math.round(u.relevance_score*1e3)/1e3,match_type:u.match_type})}return{context:o.join(`
78
+ `),tokens:i,items:l,total:l.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=z();let t=a().getDatabasePath();try{t=Y(t)}catch{}return{homes:e.map(r=>({...r,active:r.dbPath===t}))}},"POST /ui/switch":e=>{const t=String(e&&e.path||""),r=z().find(n=>n.dbPath===t);if(!r)return{ok:!1,error:"unknown home"};try{return Xe(new x(r.dbPath)),{ok:!0,account:r.account,tier:r.tier}}catch(n){return{ok:!1,error:n instanceof Error?n.message:String(n)}}}};function tt(e,t,r){if(!a().liveMemoryEnabled()){E(t,e,{e:"live memory disabled",disabled:1},503);return}const n=G(r.project??r.p);if(!n){E(t,e,{e:"not found"},404);return}const s=e.socket.remoteAddress||"unknown";if(H>=Je){E(t,e,{e:"too many concurrent streams",retry_after:5},503);return}if((R.get(s)??0)>=Ke){E(t,e,{e:"too many concurrent streams from this client",retry_after:5},503);return}H++,R.set(s,(R.get(s)??0)+1);let o=V(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,{...P(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 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};
81
+ `),W.add(t);let u,d,c=!1;const m=()=>{if(c)return;c=!0,W.delete(t),u&&clearInterval(u),d&&clearInterval(d),H--;const f=(R.get(s)??1)-1;f<=0?R.delete(s):R.set(s,f)},p=()=>{if(t.writableEnded){m();return}try{const f=i?a().eventsForPush(n.id,o,200):a().eventsSince(n.id,o,200);for(const C of f)o=C.cursor,t.write(ke(C))}catch{}};p(),u=setInterval(p,1e3),d=setInterval(()=>{try{t.write(we)}catch{}},25e3),e.on("close",m),t.on("close",m),t.on("error",m)}const S=re.createServer(async(e,t)=>{if(N){E(t,e,{e:"shutting down"},503);return}const r=ce(e.method||"GET",e.headers,ie(e));if(r){E(t,e,{e:r.e},r.status);return}if(!oe(e,t).error)try{const s=new URL(e.url||"/",`http://localhost:${j}`);if(O&&Pe(e.method||"GET",s.pathname)){E(t,e,{e:"read-only mode",readonly:1},403);return}let o;try{o=await et(e)}catch(p){if(p.message==="Invalid JSON"){E(t,e,{e:"Invalid JSON body"},400);return}throw p}if(s.searchParams.forEach((p,f)=>o[f]=p),e.method==="GET"&&s.pathname==="/ui"){{const p=F(!1);let f=!1;try{f=!!a().getDatabase().prepare("SELECT 1 FROM projects WHERE name = ? LIMIT 1").get(p.fleetGrove)}catch{}Ze(t,e,ye(F(f),ae()))}return}if(e.method==="GET"&&s.pathname==="/events/stream"){tt(e,t,o);return}const l=s.pathname.match(/^\/ui\/review\/(\d+)\/(approve|reject)$/);if(e.method==="POST"&&l){const p=parseInt(l[1],10);l[2]==="approve"?g().approve(p):g().reject(p),E(t,e,{ok:!0});return}const i=`${e.method} ${s.pathname}`,u=Z[i];if(!u){if(s.pathname==="/"){E(t,e,{wyrm:Se(),ui:"/ui",auth:w().requireAuth?"required":"disabled",tip:"GET /c for quick context"});return}E(t,e,{e:"not found"},404);return}const d=Fe({header:e.headers["wyrm-actor"],transport:"http"}),{result:c,ms:m}=$(()=>He(d,()=>u(o)));t.setHeader("X-Time-Ms",String(m)),c instanceof Promise?c.then(p=>E(t,e,p)).catch(p=>{if(X(t,e,p))return;const f=K(p);if(f!==null){const C=Q("http",f);t.setHeader("Retry-After",String(Math.ceil(C.error.retry_after_ms/1e3))),E(t,e,C,503);return}k.error("Fast API request failed",{path:e.url,error:p.message}),E(t,e,{e:"Internal server error"},500)}):E(t,e,c)}catch(s){if(X(t,e,s))return;const o=K(s);if(o!==null){const l=Q("http",o);t.setHeader("Retry-After",String(Math.ceil(l.error.retry_after_ms/1e3))),E(t,e,l,503);return}k.error("Fast API request failed",{path:e.url,error:s.message}),E(t,e,{e:"Internal server error"},500)}});S.once("listening",()=>{be(()=>a(),process.env,{vectors:()=>g().getVectorStore()??null})});const rt=4e3;let ee=!1;const U=()=>{if(!ee){ee=!0;try{v?.close()}catch{}process.exit(0)}},te=()=>{if(N){S.closeAllConnections(),U();return}N=!0,S.close(()=>U());for(const e of W)try{e.end()}catch{}S.closeIdleConnections(),setInterval(()=>S.closeIdleConnections(),100).unref(),setTimeout(()=>{S.closeAllConnections(),U()},rt).unref()};process.on("SIGINT",te),process.on("SIGTERM",te);import{fileURLToPath as nt}from"url";const st=nt(import.meta.url);if(process.argv[1]===st){ge().key&&!/^(0|false|no|off)$/i.test(process.env.WYRM_LICENSE_REFRESH??"")&&ze();const e=process.env.WYRM_BIND_HOST||"127.0.0.1";S.listen(j,e,()=>{const t=Ye(e,j);k.info("Wyrm Fast API started",{port:j,host:e,ui:t}),console.log(`\u{F115D} Wyrm Fast API on ${e}:${j}`),console.log(` Dashboard: ${t}`),console.log(` Auth: ${w().requireAuth?"required":"disabled"}`),O&&console.log(" Read-only: writes + off-box egress blocked (safe to expose)"),e!=="127.0.0.1"&&e!=="::1"&&e!=="localhost"&&(k.warn("Wyrm Fast API bound to a NON-loopback host, reachable beyond localhost; ensure auth is required",{host:e}),console.log(` \u26A0 bound to ${e}: reachable beyond localhost; make sure auth is required`),O||console.log(" \u26A0 not in read-only mode; set WYRM_UI_READONLY=1 for a public bind"))})}S.on("listening",()=>We("http"));export{rt as SHUTDOWN_GRACE_MS,Ye as dashboardUrl,ze as primeLicenseRevocations,$e as resolveHttpPort,S as server};
@@ -0,0 +1,4 @@
1
+ import{realpathSync as f}from"fs";import{basename as u,resolve as E}from"path";import{SecurityError as h,validateProjectPath as m}from"./security.js";const d=50,S=500,L=1e9,l=200,P=["limit","offset","q","path"];function s(e){return{i:e.id,n:e.name,p:e.path,s:e.stack??null}}function N(e){if(!P.some(a=>e[a]!==void 0&&e[a]!==null))return null;const t=Number.parseInt(String(e.limit??""),10),r=Number.parseInt(String(e.offset??""),10),i=e.q==null?"":String(e.q).trim(),n=e.path==null?"":String(e.path).trim();return{limit:Number.isFinite(t)&&t>=1?Math.min(t,S):d,offset:Number.isFinite(r)&&r>0?Math.min(r,L):0,q:i?i.slice(0,l):null,path:n&&!n.includes("\0")?E(n):null}}function A(e){return e.replace(/[\\%_]/g,t=>`\\${t}`)}function _(e,t){const r=t.q===null?null:`%${A(t.q)}%`,i=[t.path,t.path,r,r,r],n=e.getDatabase(),a=n.prepare(`SELECT COUNT(*) AS c FROM projects
2
+ WHERE (? IS NULL OR path = ?) AND (? IS NULL OR name LIKE ? ESCAPE '\\' OR path LIKE ? ESCAPE '\\')`).get(...i).c,c=n.prepare(`SELECT id, name, path, stack FROM projects
3
+ WHERE (? IS NULL OR path = ?) AND (? IS NULL OR name LIKE ? ESCAPE '\\' OR path LIKE ? ESCAPE '\\')
4
+ ORDER BY updated_at DESC, id DESC LIMIT ? OFFSET ?`).all(...i,t.limit,t.offset),o=t.offset+c.length,p=c.length>0&&o<a;return{items:c.map(s),total:a,limit:t.limit,offset:t.offset,more:p?1:0,next:p?o:null}}function C(e,t){const r=typeof t.path=="string"?t.path.trim():"";if(!r)return{e:"path required"};if(r.includes("\0"))return{e:"path not allowed"};let i;if(t.name!==void 0&&t.name!==null&&t.name!==""){const o=typeof t.name=="string"?t.name.trim():"";if(!o||o.length>l)return{e:`name must be 1 to ${l} characters`};if(/[\u0000-\u001f\u007f]/.test(o))return{e:"name must not contain control characters"};i=o}let n;try{n=m(r),m(f(n))}catch(o){return o instanceof h&&o.code==="INVALID_DIRECTORY"?{e:"not a directory"}:{e:"path not allowed"}}const a=e.getProject(n);if(a)return{...s(a),created:0};const c=e.registerProject(i??u(n),n);return{...s(c),created:1}}export{d as PROJECT_PAGE_DEFAULT,S as PROJECT_PAGE_MAX,s as compactProject,A as escapeLike,_ as listProjectsPage,N as parseProjectListQuery,C as registerProjectAt};
@@ -0,0 +1 @@
1
+ const u=Object.freeze({enabled:!0,requests:100,windowMs:6e4,loopbackRequests:6e3,authFailures:20,loopbackAuthFailures:300});function i(e,t){const s=typeof e=="number"?e:typeof e=="string"&&e.trim()!==""?Number(e):Number.NaN;return Number.isFinite(s)&&s>=0?Math.floor(s):t}function l(e){const t=e&&typeof e=="object"&&!Array.isArray(e)?e:{},s=i(t.windowMs,u.windowMs);return{enabled:typeof t.enabled=="boolean"?t.enabled:u.enabled,requests:i(t.requests,u.requests),windowMs:s>=1e3?s:u.windowMs,loopbackRequests:i(t.loopbackRequests,u.loopbackRequests),authFailures:i(t.authFailures,u.authFailures),loopbackAuthFailures:i(t.loopbackAuthFailures,u.loopbackAuthFailures)}}function c(e){return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}function h(e,t){const s=c(t);return e?.kind==="token"?`token:${e.tokenHash.slice(0,16)}:${s?"loopback":"remote"}`:e?.kind==="ui"||e?.kind==="dev"?e.kind:`${e?"open":"public"}:${t||"unknown"}`}function b(e,t){return c(t)?e.loopbackRequests:e.requests}function f(e,t){return c(t)?e.loopbackAuthFailures:e.authFailures}class k{maxEntries;entries=new Map;constructor(t=1e4){this.maxEntries=t}get size(){return this.entries.size}hit(t,s,n,r){const o=this.live(t,n,r);return o.count++,{allowed:s===0||o.count<=s,limit:s,remaining:s===0?Number.POSITIVE_INFINITY:Math.max(0,s-o.count),resetAt:o.resetAt}}peek(t,s,n,r){const o=this.entries.get(t),a=o&&o.resetAt>r?o:{count:0,resetAt:r+n};return{allowed:s===0||a.count<s,limit:s,remaining:s===0?Number.POSITIVE_INFINITY:Math.max(0,s-a.count),resetAt:a.resetAt}}live(t,s,n){let r=this.entries.get(t);return(!r||r.resetAt<=n)&&(this.entries.delete(t),this.makeRoom(n),r={count:0,resetAt:n+s},this.entries.set(t,r)),r}makeRoom(t){if(!(this.entries.size<this.maxEntries)){for(const[s,n]of this.entries)n.resetAt<=t&&this.entries.delete(s);for(;this.entries.size>=this.maxEntries;){const s=this.entries.keys().next().value;if(s===void 0)break;this.entries.delete(s)}}}}export{u as DEFAULT_RATE_LIMIT,k as WindowCounter,h as budgetKey,f as failureLimit,c as isLoopbackAddress,l as normalizeRateLimit,b as requestLimit};
@@ -0,0 +1,52 @@
1
+ import{NON_EMBED_MODELS as O}from"./vectors.js";import{getMeta as m}from"./events.js";import{RETIRED_NIM_EMBED_MODELS as v}from"./providers/embedding-provider.js";import{QUEUE_MAX_RETRIES as f}from"./indexer.js";const K="idx_vectors_model_type_project",L=["artifact","quest","session"],A=200;function I(e){return`${e.problem}${e.validated_fix?" "+e.validated_fix:""}`.slice(0,2e3)}const _={artifact:{from:"memory_artifacts r",where:"r.needs_review = 0 AND r.supersedes_id IS NULL"},quest:{from:"quests r",where:"(COALESCE(r.title, '') <> '' OR COALESCE(r.description, '') <> '')"},session:{from:"sessions r",where:"(COALESCE(r.objectives, '') <> '' OR COALESCE(r.completed, '') <> '' OR COALESCE(r.notes, '') <> '' OR COALESCE(r.summary, '') <> '')"}};function D(e,n,r){const o=_[e];return`SELECT ${n} FROM ${o.from}
2
+ WHERE ${o.where}${r?" AND r.project_id = @project":""}
3
+ AND NOT EXISTS (SELECT 1 FROM vectors v
4
+ WHERE v.content_type = '${e}' AND v.content_id = r.id AND v.model = @model)`}function F(e,n,r={}){const o={artifact:0,quest:0,session:0,total:0},t=r.projectId!=null;for(const s of L){const a={model:n};t&&(a.project=r.projectId);const E=e.prepare(D(s,"COUNT(*) AS n",t)).get(a).n;o[s]=E,o.total+=E}return o}function g(e,n,r={}){const o=[],t=r.projectId!=null,s=r.limit!=null&&r.limit>0;for(const a of L){const E=s?r.limit-o.length:-1;if(E===0)break;const u={model:n,limit:E};t&&(u.project=r.projectId);const i=`${D(a,`'${a}' AS content_type, r.id AS content_id, r.project_id AS project_id`,t)}
5
+ ORDER BY r.id DESC LIMIT @limit`;o.push(...e.prepare(i).all(u))}return o}function b(e,n,r){let o=null;if(n==="artifact"){const t=e.prepare("SELECT problem, validated_fix, needs_review, supersedes_id FROM memory_artifacts WHERE id = ?").get(r);t&&t.needs_review===0&&t.supersedes_id==null&&(o=I(t))}else if(n==="quest"){const t=e.prepare("SELECT title, description FROM quests WHERE id = ?").get(r);t&&(o=[t.title,t.description].filter(Boolean).join(" "))}else{const t=e.prepare("SELECT objectives, completed, notes, summary FROM sessions WHERE id = ?").get(r);t&&(o=[t.objectives,t.completed,t.notes,t.summary].filter(Boolean).join(" "))}return!o||o.startsWith("ENCRYPTED:")?null:o}async function h(e,n,r={}){const o=n.getProvider().model,t=F(e,o,{projectId:r.projectId}),s={model:o,dryRun:r.dryRun===!0,eligible:t.total,byType:{artifact:t.artifact,quest:t.quest,session:t.session},attempted:0,embedded:0,failed:0,aborted:!1};if(s.dryRun||t.total===0)return s;const a=r.maxConsecutiveFailures??3;let E=0,u=null;try{u=e.prepare("DELETE FROM indexing_queue WHERE content_type = ? AND content_id = ? AND retry_count >= ?")}catch{u=null}for(const i of g(e,o,{limit:r.limit,projectId:r.projectId})){const c=b(e,i.content_type,i.content_id);if(c===null)continue;s.attempted++;let d=null;try{d=await n.addVector(c,i.content_type,i.content_id,i.project_id)}catch{d=null}if(d){s.embedded++,E=0;try{u?.run(i.content_type,i.content_id,f)}catch{}continue}if(s.failed++,++E>=a){s.aborted=!0;break}}return s}function H(e,n){const r=n.getProvider();return r.name==="none"?!1:W(e,r.model)!==null}function x(e){const n=m(e,"embed_last_ok_at"),r=m(e,"embed_last_error_at");return!!r&&(!n||Date.parse(r)>Date.parse(n))}function W(e,n){return!n||O.has(n)||v[n]||x(e)?null:n}async function Y(e,n,r=process.env){const o=Number(r.WYRM_BACKFILL_LIMIT??A),t=Number.isFinite(o)&&o>=0?Math.floor(o):A;return t===0||!H(e,n)?null:h(e,n,{limit:t})}const C=[["artifact","memory_artifacts"],["session","sessions"],["quest","quests"],["note","data_lake"]],S="(v.content_type = 'context')",N=`(v.content_type = 'context'
6
+ AND EXISTS (SELECT 1 FROM quests p WHERE p.id = v.content_id)
7
+ AND NOT EXISTS (SELECT 1 FROM vectors w WHERE w.content_type = 'quest' AND w.content_id = v.content_id AND w.model = v.model))`,q=`(${C.map(([e,n])=>`(v.content_type = '${e}' AND NOT EXISTS (SELECT 1 FROM ${n} p WHERE p.id = v.content_id))`).join(" OR ")})`,$=`(v.content_type = 'artifact'
8
+ AND EXISTS (SELECT 1 FROM memory_artifacts p WHERE p.id = v.content_id AND p.supersedes_id IS NOT NULL))`,j=`(${C.map(([e,n])=>`(v.content_type = '${e}' AND EXISTS (SELECT 1 FROM ${n} p WHERE p.id = v.content_id${e==="artifact"?" AND p.supersedes_id IS NULL":""}))`).join(" OR ")})`,U=`(v.model <> @active
9
+ AND v.model NOT IN (SELECT value FROM json_each(@protected))
10
+ AND ${j}
11
+ AND EXISTS (SELECT 1 FROM vectors w WHERE w.content_type = v.content_type AND w.content_id = v.content_id AND w.model = @active))`;function w(e,n={}){const r=n.dryRun===!0,o=n.activeModel&&!O.has(n.activeModel)?n.activeModel:null,t={dryRun:r,activeModel:o,orphans:0,superseded:0,mislabelled:0,relabelled:0,oldModel:0,bytes:0,deleted:0};if(!e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'vectors'").get())return t;const a={active:o??"",protected:JSON.stringify([...n.protectedModels??[]])},E=(c,d={})=>e.prepare(`SELECT COUNT(*) AS n, COALESCE(SUM(length(v.embedding)), 0) AS b FROM vectors v WHERE ${c}`).get(d),u=(c,d={})=>e.prepare(`DELETE FROM vectors WHERE id IN (SELECT v.id FROM vectors v WHERE ${c})`).run(d).changes,i=[{key:"orphans",pred:q},{key:"superseded",pred:$}];if(o&&i.push({key:"oldModel",pred:U,params:a}),r){const c=E(N).n,d=E(`${S} AND NOT ${N}`);t.relabelled=c,t.mislabelled=c+d.n,t.bytes+=d.b;for(const l of i){const p=E(l.pred,l.params);t[l.key]=p.n,t.bytes+=p.b}return t}return e.transaction(()=>{t.relabelled=e.prepare(`UPDATE OR IGNORE vectors SET content_type = 'quest' WHERE id IN (SELECT v.id FROM vectors v WHERE ${N})`).run().changes;const c=E(S);t.bytes+=c.b;const d=u(S);t.mislabelled=t.relabelled+d,t.deleted+=d;for(const l of i){t.bytes+=E(l.pred,l.params).b;const p=u(l.pred,l.params);t[l.key]=p,t.deleted+=p}})(),t}const R=`(
12
+ (q.content_type = 'artifact' AND NOT EXISTS (SELECT 1 FROM memory_artifacts p WHERE p.id = q.content_id))
13
+ OR (q.content_type IN ('quest', 'context') AND NOT EXISTS (SELECT 1 FROM quests p WHERE p.id = q.content_id))
14
+ OR (q.content_type = 'session' AND NOT EXISTS (SELECT 1 FROM sessions p WHERE p.id = q.content_id))
15
+ OR (q.content_type = 'note' AND NOT EXISTS (SELECT 1 FROM data_lake p WHERE p.id = q.content_id)))`,T=`(NOT ${R} AND (
16
+ q.content_type = 'context'
17
+ OR (q.content_type = 'artifact' AND EXISTS (SELECT 1 FROM memory_artifacts r WHERE r.id = q.content_id AND NOT (${_.artifact.where})))
18
+ OR (q.content_type = 'quest' AND EXISTS (SELECT 1 FROM quests r WHERE r.id = q.content_id AND NOT ${_.quest.where}))
19
+ OR (q.content_type = 'session' AND EXISTS (SELECT 1 FROM sessions r WHERE r.id = q.content_id AND NOT ${_.session.where}))))`,M=`(NOT ${R} AND NOT ${T}
20
+ AND EXISTS (SELECT 1 FROM vectors v WHERE v.content_type = q.content_type AND v.content_id = q.content_id AND v.model = @active))`,X=`
21
+ SELECT COUNT(*) AS stuck,
22
+ COALESCE(SUM(CASE WHEN ${R} THEN 1 ELSE 0 END), 0) AS gone,
23
+ COALESCE(SUM(CASE WHEN ${T} THEN 1 ELSE 0 END), 0) AS notNeeded,
24
+ COALESCE(SUM(CASE WHEN ${M} THEN 1 ELSE 0 END), 0) AS embedded
25
+ FROM indexing_queue q WHERE q.retry_count >= @max`,k=`
26
+ DELETE FROM indexing_queue WHERE id IN (
27
+ SELECT q.id FROM indexing_queue q
28
+ WHERE q.retry_count >= @max AND (${R} OR ${T} OR ${M}))`;function G(e,n={}){const r=n.dryRun===!0,o={active:n.activeModel??"",max:n.maxRetries??f};if(!e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'indexing_queue'").get())return{stuck:0,gone:0,notNeeded:0,embedded:0,cleared:0,remaining:0,dryRun:r};const s=e.prepare(X).get(o),a=s.gone+s.notNeeded+s.embedded,E=r||a===0?0:e.prepare(k).run(o).changes;return{stuck:s.stuck,gone:s.gone,notNeeded:s.notNeeded,embedded:s.embedded,cleared:E,remaining:s.stuck-a,dryRun:r}}const y=90;function J(e=process.env){const n=Number(e.WYRM_RUN_RETAIN_DAYS??y);return Number.isFinite(n)&&n>=0?Math.floor(n):y}function z(e,n){const r=n.dryRun===!0,o=e.prepare(`
29
+ SELECT r.run_id FROM runs r
30
+ WHERE r.status IN ('completed', 'failed', 'abandoned')
31
+ AND r.updated_at < datetime('now', ?)
32
+ AND NOT EXISTS (SELECT 1 FROM failure_patterns fp
33
+ WHERE fp.run_id = r.run_id AND fp.resolved = 0 AND fp.quarantine_scope = 'run')
34
+ AND NOT EXISTS (SELECT 1 FROM runs c WHERE c.parent_run_id = r.run_id AND c.status = 'running')
35
+ `).all(`-${Math.max(0,n.olderThanDays)} days`).map(a=>a.run_id),t=JSON.stringify(o),s=e.prepare("SELECT COUNT(*) AS n FROM run_agents WHERE run_id IN (SELECT value FROM json_each(?))").get(t).n;return r||o.length===0?{runs:o.length,runAgents:s,dryRun:r}:(e.transaction(()=>{e.prepare("DELETE FROM run_agents WHERE run_id IN (SELECT value FROM json_each(?))").run(t),e.prepare("DELETE FROM runs WHERE run_id IN (SELECT value FROM json_each(?))").run(t)})(),{runs:o.length,runAgents:s,dryRun:r})}function Z(e,n={}){const r=n.dryRun===!0,o=e.prepare(`
36
+ SELECT r.id FROM relationships r
37
+ WHERE NOT EXISTS (SELECT 1 FROM entities e WHERE e.id = r.source_entity_id)
38
+ OR NOT EXISTS (SELECT 1 FROM entities e WHERE e.id = r.target_entity_id)
39
+ OR (r.extraction_method = 'auto-extract'
40
+ AND r.weight <= 0.3000001
41
+ AND r.source_memory LIKE 'mem:%'
42
+ AND NOT EXISTS (SELECT 1 FROM memory_artifacts a
43
+ WHERE a.id = CAST(substr(r.source_memory, 5) AS INTEGER) AND a.supersedes_id IS NULL))
44
+ `).all().map(i=>i.id),t=JSON.stringify(o),s=e.prepare(`
45
+ SELECT e.id, e.project_id, e.name FROM entities e
46
+ WHERE e.created_by = 'auto-extract'
47
+ AND NOT EXISTS (SELECT 1 FROM entity_aliases x WHERE x.entity_id = e.id)
48
+ AND NOT EXISTS (SELECT 1 FROM relationships r
49
+ WHERE r.source_entity_id = e.id AND r.id NOT IN (SELECT value FROM json_each(@edges)))
50
+ AND NOT EXISTS (SELECT 1 FROM relationships r
51
+ WHERE r.target_entity_id = e.id AND r.id NOT IN (SELECT value FROM json_each(@edges)))
52
+ `).all({edges:t}),a=new Map,E=i=>{let c=a.get(i);return c||(c=e.prepare("SELECT problem, validated_fix FROM memory_artifacts WHERE project_id = ? AND needs_review = 0 AND supersedes_id IS NULL").all(i).map(d=>`${d.problem} ${d.validated_fix??""}`.toLowerCase()),a.set(i,c)),c},u=s.filter(i=>{const c=i.name.toLowerCase();return!E(i.project_id).some(d=>d.includes(c))}).map(i=>i.id);return!r&&(o.length>0||u.length>0)&&e.transaction(()=>{e.prepare("DELETE FROM relationships WHERE id IN (SELECT value FROM json_each(?))").run(t),e.prepare("DELETE FROM entities WHERE id IN (SELECT value FROM json_each(?))").run(JSON.stringify(u))})(),{relationships:o.length,entities:u.length,dryRun:r}}function ee(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}export{A as DEFAULT_BACKFILL_LIMIT,y as DEFAULT_RUN_RETAIN_DAYS,K as VECTOR_INDEX_NAME,I as artifactVectorText,b as backfillContent,h as backfillVectors,Z as compactGraph,F as countUnembedded,H as embeddingHealthy,g as findUnembedded,ee as formatBytes,Y as maybeBackfill,z as pruneEndedRuns,W as pruneReferenceModel,G as pruneStuckQueue,w as pruneVectors,J as runRetainDays};
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
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};
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,describeStoreError as Ie}from"./database.js";import{ValidationError as V}from"./validate.js";import{validationErrorResponse as $,cacheKeyFor as Ne}from"./render.js";import{handlerRegistry as h,registryToolDefs as W,applyDeclaredOutputSchemas as Le,buildStableToolList as Ye}from"./handlers/registry.js";import{resolveActorEnvelope as J,runWithActor as z,getActor as je,runWithReadCacheKey as Fe}from"./handlers/boundary.js";import{resolveAliasCall as Be}from"./handlers/aliases.js";import{rejectUnknownArgs as Ke}from"./handlers/arg-keys.js";import{resolveShimCall as Ue,shimToolDefs as P}from"./handlers/shims.js";import{getPromptResult as Ge,wyrmPromptList as He}from"./handlers/prompts.js";import{listWyrmResources as qe,listWyrmResourceTemplates as Ve,readWyrmResource as $e,ResourceNotFoundError as Je}from"./handlers/resources.js";import{TaskStore as ze,resolveTaskGate as Qe,runLongOp as Xe}from"./tasks.js";import{registerTaskHandlers as Ze,finalizeEarly as et,unwrapOutcome as tt,applyAdminGate as rt}from"./tasks-dispatch.js";import{ReplicationManager as ot}from"./replication-daemon.js";import{WYRM_SERVER_INSTRUCTIONS as st}from"./priority-embed.js";import{WyrmSync as nt}from"./sync.js";import{cache as w,estimateTokens as A}from"./performance.js";import{readFileSync as Q,unlinkSync as at,existsSync as X}from"fs";import{join as it}from"path";import{initializeOrchestrator as ct}from"./auto-orchestrator.js";import{getCrypto as mt,initializeCrypto as lt}from"./crypto.js";import{initVectorSearch as pt}from"./vector-init.js";import{KnowledgeGraph as ut}from"./knowledge-graph.js";import{MemoryArtifacts as _t}from"./memory-artifacts.js";import{GroundTruths as ft,ReasoningScaffolds as yt}from"./intelligence.js";import{classifyCapture as ns}from"./capture.js";import{initializeLicense as dt,getLicenseInfo as gt}from"./license.js";import{refreshRevocations as Z}from"./revocations.js";import{refreshLicenseIfNeeded as ee}from"./license-refresh.js";import{activationSatisfied as ht,activationGateResult as wt}from"./activation.js";import{WyrmAnalytics as St}from"./analytics.js";import{WyrmCloudBackup as Rt}from"./cloud-backup.js";import{CloudSyncManager as vt}from"./cloud-sync.js";import{FailurePatterns as kt}from"./failure-patterns.js";import{AgentPresence as bt}from"./presence.js";import{Causality as Et}from"./causality.js";import{wireTruthAutoCascade as Dt}from"./truth-cascade.js";import{SymbolGraph as Ct}from"./symbols.js";import{HourLedger as Tt}from"./hours.js";import{ToolAnalytics as Ot}from"./tool-analytics.js";import{Rehydration as xt}from"./rehydration.js";import{AuditLog as Mt,loadAuditSignerFromEnv as Wt}from"./audit.js";import{retryableWriteCause as Pt,busyErrorResponse as At}from"./sqlite-busy.js";import{SubAgent as It}from"./sub-agent.js";import{Federation as Nt}from"./federation.js";import{Goals as Lt}from"./goals.js";import{OutboundMcpClient as Yt}from"./mcp-client.js";import{AgentLoop as jt}from"./agent-loop.js";import{makeInternalDispatch as Ft}from"./internal-dispatch.js";import{createUsageTracker as Bt}from"./usage-tracker.js";import{AgentDaemon as Kt}from"./agent-daemon.js";import{emitStartupVersionBanner as Ut}from"./version-check.js";import{resolveProfile as te,filterByProfile as re}from"./tool-profiles.js";import{annotateTools as Gt,elideDefaultAnnotations as Ht}from"./tool-annotations.js";import{applyDeprecationNotices as qt,noteDeprecatedToolInvocation as Vt,isHardCliExile as $t,cliExileRedirectResponse as Jt}from"./deprecations.js";import{goldenCapture as y}from"./golden.js";import{makeEstimator as zt}from"./token-budget.js";import{makeRunBudgetedContextBuild as Qt}from"./context-build-budgeted.js";import{assembleThread as Xt}from"./thread-assemble.js";import{getThread as Zt}from"./thread-store.js";import{renderThreadForContext as oe}from"./handlers/thread.js";import{makeRunCompanionBuddy as er}from"./buddy-runner.js";import{loadWeightsFromEnv as tr}from"./context-ranking.js";import{SessionSeen as rr}from"./session-seen.js";import{recordServed as or}from"./served-records.js";import{DesignSystem as sr}from"./design.js";import{fileURLToPath as nr}from"url";import{dirname as ar,join as se}from"path";import{readFileSync as ir,existsSync as cr}from"fs";const mr=137;let I=null;function lr(){return I||(I=new sr(r.getDatabase())),I}const pr=zt(),ur=tr();let N=null;function ne(){return N||(N=new rr(r.getDatabase())),N}const T=(()=>{try{const e=ar(nr(import.meta.url));for(const t of[se(e,"..","package.json"),se(e,"..","..","package.json")])if(cr(t)){const o=JSON.parse(ir(t,"utf-8")).version;if(typeof o=="string")return o}}catch{}return"unknown"})(),r=new Pe(Ae()),_r=new nt(r),ae=new ut(r.getDatabase()),R=new _t(r.getDatabase()),v=new ft(r.getDatabase()),L=new yt(r.getDatabase()),Y=new kt(r.getDatabase()),j=new bt(r.getDatabase()),F=new Et(r.getDatabase());Dt(v,F);const B=new Ct(r.getDatabase()),fr=new Tt(r.getDatabase()),k=new Ot(r.getDatabase()),yr=Qt({groundTruths:v,scaffoldLib:L,memory:R,toolAnalytics:k,sessionSeen:ne,tokenEstimator:pr,rankWeights:ur,threadText:e=>{try{return oe(Xt(r.getDatabase(),e))}catch{try{const t=Zt(r.getDatabase(),e);return t?oe(t):""}catch{return""}}}}),ie=new xt(r.getDatabase()),dr=new Mt(r.getDatabase(),Wt()),gr=new It(r.getDatabase()),ce=new Nt(r.getDatabase()),me=new Lt(r.getDatabase()),le={projects:r,goals:me,getActor:je,store:r,raw:()=>r.getDatabase(),memory:R,truths:v,scaffolds:L,failures:Y,presence:j,rehydration:ie,graph:ae,symbols:B,vectors:()=>b,indexing:()=>G,cache:w,decrypt:e=>U.maybeDecrypt(e),clientSupportsResources:()=>{const e=c.getClientCapabilities()?.experimental;return!!e&&"resources"in e}},K=new Yt(r.getDatabase()),hr=er({db:r,mcpClient:K,version:T}),wr=new Kt(r.getDatabase()),Sr=Ft({db:r,failures:Y,symbols:B,rehydration:ie,causality:F,presence:j,federation:ce,memory:R,groundTruths:v}),Rr=new jt(r.getDatabase(),K,Sr);if(process.env.WYRM_ENCRYPTION_KEY)try{lt(process.env.WYRM_ENCRYPTION_KEY)}catch(e){console.error("Wyrm: Failed to initialize encryption:",e)}const U=mt();let b=null,G=null;{const e=pt(r,R,U);b=e.vectorStore,G=e.indexingPipeline}const vr=ct({autoOrchestrateEnabled:!0,minConfidenceThreshold:65,maxParallelAgents:6,defaultHaikuBoosting:!0,trackMetrics:!0});dt();const O=gt();O.tier!=="free"&&console.error(`Wyrm: Licensed, ${O.tier} tier (expires: ${O.expiresAt||"never"})`);const kr=!!O.key&&!/^(0|false|no|off)$/i.test(process.env.WYRM_LICENSE_REFRESH??"");kr&&(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=it(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(D=>D.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{at(t)}catch{}}}catch{}const H=new St(r.getDatabase()),pe=new Rt;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 br}from"url";import{dirname as Er,join as ue}from"path";const Dr=br(import.meta.url),_e=Er(Dr),Cr=new vt(ue(_e,"cloud-sync-entrypoint.js")),Tr=new ot(ue(_e,"replication-daemon-entrypoint.js")),{trackUsage:d,getUsageStats:Or,usageLog:xr}=Bt(H),Mr=new Map;function Wr(e,t=!1){return{content:[{type:"text",text:e}]}}const Pr=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 Ar(e,t){return!(!Pr.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"]),E=new ze,c=new we({name:"wyrm",version:T},{capabilities:{tools:{},prompts:{},resources:{},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}},instructions:st}),ye={...le,db:r,sync:_r,graph:ae,memory:R,groundTruths:v,scaffoldLib:L,failures:Y,presence:j,causality:F,symbols:B,hours:fr,toolAnalytics:k,auditLog:dr,subAgent:gr,federation:ce,goals:me,mcpClient:K,agentDaemon:wr,agentLoop:Rr,analytics:H,cloudBackup:pe,cloudSyncManager:Cr,replicationManager:Tr,orchestrator:vr,server:c,wyrmCrypto:U,get vectorStore(){return b},get indexingPipeline(){return G},setVectorStore:e=>{b=e},WYRM_PACKAGE_VERSION:T,WYRM_TOOL_COUNT:mr,toolCounts:()=>({active:re([...W(),...P()],te()).length,full:W().length+P().length}),WRITE_TOOLS:fe,usageLog:xr,responseFingerprints:Mr,designSystem:lr,sessionSeen:ne,cachedResponse:Wr,getUsageStats:Or,runCompanionBuddy:hr,runBudgetedContextBuild:yr};c.setRequestHandler(Me,async()=>{const e=[...W(),...P()],t=te();return{tools:Ye(Le(qt(Ht(Gt(re(e,t))))))}}),c.setRequestHandler(Te,async()=>({prompts:[...He()]})),c.setRequestHandler(Ce,async e=>{const t=e.params.arguments??{},o=J({transport:"mcp",args:t,meta:e.params._meta,clientName:c.getClientVersion()?.name});return z(o,()=>Ge(e.params.name,t,le))}),c.setRequestHandler(Oe,async()=>({resources:qe()})),c.setRequestHandler(xe,async()=>({resourceTemplates:Ve()})),c.setRequestHandler(We,async e=>{const t=e.params.uri;try{const o=$e(t,ye),{nextCursor:l,...i}=o;return l?{contents:[i],_meta:{"wyrm/nextCursor":l}}:{contents:[i]}}catch(o){throw o instanceof Je?new Error(o.message):o}}),Ze(c,E),c.setRequestHandler(De,async e=>{const{name:t,arguments:o}=e.params;if(!ht())return wt();const l=J({transport:"mcp",args:o??{},meta:e.params._meta,clientName:c.getClientVersion()?.name});Vt(t);const i=performance.now(),x=JSON.stringify(o||{}),m=A(x);let a,_,g=null;try{const s=Be(t,o??{});s.via?.kind==="cli-exile"&&(g=s.via),{tool:a,args:_}=Ue(s.tool,s.args),Ke(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&&$t(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=Jt(g.name);return y({tool:t,args:o,meta:e.params._meta,response:n,outcome:"soft_error",ms:s,dispatch:"switch"}),n}const S=Qe(c.getClientCapabilities()?.tasks,e.params),D=rt(E,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(D!==null)return D;const de=a===t?x:JSON.stringify(_),M=Ar(a,_??{})?Ne(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"}),et(E,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 C;const ge=_||{};try{const s=await z(l,async()=>{const q=h.get(a);return q?await Xe(a,S,E,()=>Fe(M,()=>q(ge,ye))):{kind:"inline",result:{content:[{type:"text",text:`Unknown tool: ${a}`}],isError:!0}}}),{wireValue:n,payload:p}=tt(E,s);C=p;const u=Math.round(performance.now()-i),f=JSON.stringify(C),he=A(f);return or(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:!C?.isError,latency_ms:u}),y({tool:t,args:o,meta:e.params._meta,response:C,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=Pt(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=At(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: ${Ie(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 Ir(){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,process.env,{vectors:()=>b}),Ut(r.getDatabase(),T).catch(()=>{})}Ir().catch(console.error);export{ns as classifyCapture};
package/dist/indexer.js CHANGED
@@ -1,4 +1,4 @@
1
- class a{db;vectorStore;timer=null;processing=!1;batchSize;maxRetries;intervalMs;contentResolver;constructor(t,s,n,e){this.db=t,this.vectorStore=s,this.contentResolver=n,this.batchSize=e?.batchSize??10,this.maxRetries=e?.maxRetries??3,this.intervalMs=e?.intervalMs??5e3,this.ensureTable()}updateStore(t){this.vectorStore=t}ensureTable(){this.db.exec(`
1
+ const u=3,a=`
2
2
  CREATE TABLE IF NOT EXISTS indexing_queue (
3
3
  id INTEGER PRIMARY KEY AUTOINCREMENT,
4
4
  content_type TEXT NOT NULL,
@@ -13,7 +13,7 @@ class a{db;vectorStore;timer=null;processing=!1;batchSize;maxRetries;intervalMs;
13
13
  );
14
14
  CREATE INDEX IF NOT EXISTS idx_iq_status ON indexing_queue(status);
15
15
  CREATE INDEX IF NOT EXISTS idx_iq_content ON indexing_queue(content_type, content_id);
16
- `)}enqueue(t,s,n){this.db.prepare(`
16
+ `,c=`
17
17
  INSERT INTO indexing_queue (content_type, content_id, project_id, status, retry_count)
18
18
  VALUES (?, ?, ?, 'pending', 0)
19
19
  ON CONFLICT(content_type, content_id) DO UPDATE SET
@@ -21,9 +21,9 @@ class a{db;vectorStore;timer=null;processing=!1;batchSize;maxRetries;intervalMs;
21
21
  retry_count = 0,
22
22
  error_message = NULL,
23
23
  processed_at = NULL
24
- `).run(t,s,n)}async processBatch(){if(this.processing)return 0;this.processing=!0;try{this.db.prepare("UPDATE indexing_queue SET status = 'pending' WHERE status = 'processing'").run();const t=this.db.prepare(`
24
+ `;function E(i,e){i.exec(a);const s=i.prepare(c);return i.transaction(()=>{for(const n of e)s.run(n.contentType,n.contentId,n.projectId)})(),e.length}class d{db;vectorStore;timer=null;processing=!1;batchSize;maxRetries;intervalMs;contentResolver;constructor(e,s,n,t){this.db=e,this.vectorStore=s,this.contentResolver=n,this.batchSize=t?.batchSize??10,this.maxRetries=t?.maxRetries??3,this.intervalMs=t?.intervalMs??5e3,this.ensureTable()}updateStore(e){this.vectorStore=e}ensureTable(){this.db.exec(a)}enqueue(e,s,n){this.db.prepare(c).run(e,s,n)}async processBatch(){if(this.processing)return 0;this.processing=!0;try{this.db.prepare("UPDATE indexing_queue SET status = 'pending' WHERE status = 'processing'").run();const e=this.db.prepare(`
25
25
  SELECT * FROM indexing_queue
26
26
  WHERE status = 'pending' AND retry_count < ?
27
27
  ORDER BY created_at ASC
28
28
  LIMIT ?
29
- `).all(this.maxRetries,this.batchSize);if(t.length===0)return 0;const s=t.map(e=>e.id);this.db.prepare(`UPDATE indexing_queue SET status = 'processing' WHERE id IN (${s.map(()=>"?").join(",")})`).run(...s);let n=0;for(const e of t)try{const r=this.contentResolver(e.content_type,e.content_id);if(r===null){this.db.prepare("UPDATE indexing_queue SET status = 'skipped', processed_at = datetime('now'), error_message = 'Content not found or encrypted' WHERE id = ?").run(e.id);continue}await this.vectorStore.addVector(r,e.content_type,e.content_id,e.project_id)?this.db.prepare("UPDATE indexing_queue SET status = 'done', processed_at = datetime('now') WHERE id = ?").run(e.id):this.db.prepare("UPDATE indexing_queue SET status = 'failed', retry_count = retry_count + 1, error_message = 'Provider returned null' WHERE id = ?").run(e.id),n++}catch(r){const i=r instanceof Error?r.message:String(r);this.db.prepare("UPDATE indexing_queue SET status = 'failed', retry_count = retry_count + 1, error_message = ? WHERE id = ?").run(i,e.id)}return this.db.prepare("UPDATE indexing_queue SET status = 'pending' WHERE status = 'failed' AND retry_count < ?").run(this.maxRetries),n}finally{this.processing=!1}}start(){this.timer||(this.timer=setInterval(()=>{this.processBatch().catch(()=>{})},this.intervalMs))}stop(){this.timer&&(clearInterval(this.timer),this.timer=null)}getStats(){const t=this.db.prepare("SELECT status, COUNT(*) as cnt FROM indexing_queue GROUP BY status").all(),s={pending:0,processing:0,done:0,failed:0,skipped:0,total:0};for(const n of t)s[n.status]=n.cnt,s.total+=n.cnt;return s}clearCompleted(){return this.db.prepare("DELETE FROM indexing_queue WHERE status IN ('done', 'skipped')").run().changes}isProcessing(){return this.processing}isRunning(){return this.timer!==null}}export{a as IndexingPipeline};
29
+ `).all(this.maxRetries,this.batchSize);if(e.length===0)return 0;const s=e.map(t=>t.id);this.db.prepare(`UPDATE indexing_queue SET status = 'processing' WHERE id IN (${s.map(()=>"?").join(",")})`).run(...s);let n=0;for(const t of e)try{const r=this.contentResolver(t.content_type,t.content_id);if(r===null){this.db.prepare("UPDATE indexing_queue SET status = 'skipped', processed_at = datetime('now'), error_message = 'Content not found or encrypted' WHERE id = ?").run(t.id);continue}await this.vectorStore.addVector(r,t.content_type,t.content_id,t.project_id)?this.db.prepare("UPDATE indexing_queue SET status = 'done', processed_at = datetime('now') WHERE id = ?").run(t.id):this.db.prepare("UPDATE indexing_queue SET status = 'failed', retry_count = retry_count + 1, error_message = 'Provider returned null' WHERE id = ?").run(t.id),n++}catch(r){const o=r instanceof Error?r.message:String(r);this.db.prepare("UPDATE indexing_queue SET status = 'failed', retry_count = retry_count + 1, error_message = ? WHERE id = ?").run(o,t.id)}return this.db.prepare("UPDATE indexing_queue SET status = 'pending' WHERE status = 'failed' AND retry_count < ?").run(this.maxRetries),n}finally{this.processing=!1}}start(){this.timer||(this.timer=setInterval(()=>{this.processBatch().catch(()=>{})},this.intervalMs))}stop(){this.timer&&(clearInterval(this.timer),this.timer=null)}getStats(){const e=this.db.prepare("SELECT status, COUNT(*) as cnt FROM indexing_queue GROUP BY status").all(),s={pending:0,processing:0,done:0,failed:0,skipped:0,total:0};for(const n of e)s[n.status]=n.cnt,s.total+=n.cnt;return s}clearCompleted(){return this.db.prepare("DELETE FROM indexing_queue WHERE status IN ('done', 'skipped')").run().changes}isProcessing(){return this.processing}isRunning(){return this.timer!==null}}export{d as IndexingPipeline,u as QUEUE_MAX_RETRIES,E as enqueueForIndexing};