@agimon-ai/log-sink-mcp 0.2.7 → 0.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,7 +17,7 @@ Perfect for debugging, monitoring, and understanding application behavior throug
17
17
 
18
18
  - ✅ **HTTP Log Ingestion**: POST logs from any application via REST API
19
19
  - ✅ **7 MCP Tools**: Query, search, trace, analyze, and manage logs
20
- - ✅ **Hybrid Search**: FTS5-powered search plus local semantic retrieval across messages and errors
20
+ - ✅ **Hybrid Search**: FTS5-powered search plus optional local semantic retrieval across messages and errors
21
21
  - ✅ **Distributed Tracing**: Timeline view for trace IDs and span relationships
22
22
  - ✅ **Error Analysis**: Pattern detection and error categorization
23
23
  - ✅ **Structured Logging**: JSON metadata, trace IDs, span IDs
@@ -103,10 +103,15 @@ bun run src/cli.ts start
103
103
  # From monorepo root
104
104
  pnpm install
105
105
 
106
+ # Optional: install local embedding support for semantic search
107
+ pnpm add ruvector-onnx-embeddings-wasm
108
+
106
109
  # Or install globally
107
110
  pnpm add -g log-sink-mcp
108
111
  ```
109
112
 
113
+ If `ruvector-onnx-embeddings-wasm` is not installed, `log-sink-mcp` still starts and falls back to FTS5 search only.
114
+
110
115
  ## Quick Start
111
116
 
112
117
  ### 1. Start the Servers
package/dist/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const e=require(`./chunk-DjWAcSYV.cjs`),t=require(`./stdio-DSsKUa5U.cjs`);let n=require(`node:fs`),r=require(`node:path`);r=e.t(r);let i=require(`node:url`),a=require(`commander`),o=require(`@agimon-ai/foundation-process-registry`),s=require(`@agimon-ai/foundation-port-registry`),c=require(`@hono/node-server`),l=require(`node:fs/promises`);l=e.t(l);let u=require(`node:os`),d=require(`hono`),f=require(`hono/cors`),p=require(`hono-rate-limiter`),m=require(`zod`),h=require(`hono/html`),g=require(`hono/jsx/jsx-runtime`),_=function(e){return e.TRACE=`trace`,e.DEBUG=`debug`,e.INFO=`info`,e.WARN=`warn`,e.ERROR=`error`,e.FATAL=`fatal`,e}({});const v=m.z.object({service:m.z.string().optional(),level:m.z.string().optional(),traceId:m.z.string().optional(),search:m.z.string().optional(),limit:m.z.coerce.number().min(1).max(1e3).default(25),offset:m.z.coerce.number().min(0).default(0)});function y(e){let n=new d.Hono,r=e.get(t.d.LogQueryService),i=e.get(t.d.LogSearchService);return n.get(`/logs`,async e=>{try{let{service:t,level:n,traceId:a,search:o,limit:s,offset:c}=v.parse({service:e.req.query(`service`),level:e.req.query(`level`),traceId:e.req.query(`traceId`),search:e.req.query(`search`),limit:e.req.query(`limit`),offset:e.req.query(`offset`)}),l,u=0;if(o){let e={};t&&(e.service=t),n&&(e.level=n);let r=await i.searchLogsPaginated(o,{...e,offset:c},s);l=r.results,u=r.total}else{let e=n?n.split(`,`):[_.INFO,_.WARN,_.ERROR,_.FATAL],i=await r.queryLogs({level:e,service:t||void 0,traceId:a||void 0,limit:s,offset:c});l=i.logs,u=i.total}return e.json({logs:l,total:u,hasMore:c+s<u})}catch(t){return console.error(`Failed to query logs:`,t),e.json({error:`Failed to query logs`,message:t instanceof Error?t.message:String(t)},500)}}),n.get(`/services`,async e=>{try{let t=await r.getActiveServices();return e.json({services:t,total:t.length})}catch(t){return console.error(`Failed to get services:`,t),e.json({error:`Failed to get services`,message:t instanceof Error?t.message:String(t)},500)}}),n.get(`/stats`,async e=>{try{let t=await r.getStatistics(),n=t.reduce((e,t)=>e+t.count,0),i=t.filter(e=>e.level===`error`||e.level===`fatal`).reduce((e,t)=>e+t.count,0),a=new Set(t.map(e=>e.service)).size;return e.json({totalLogs:n,errors:i,services:a,breakdown:t})}catch(t){return console.error(`Failed to get statistics:`,t),e.json({error:`Failed to get statistics`,message:t instanceof Error?t.message:String(t)},500)}}),n}function b(e){return e.toLocaleString(`en-US`,{year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1})}const x=`dashboard-container`,ee=`dashboard-header`,te=`controls-section`,S=`input-field`,ne=`select-field`,re=`btn`,ie=`table-container`,C=`log-table`,w=`level-trace`,T=`level-debug`,E=`level-info`,D=`level-warn`,O=`level-error`,k=`level-fatal`,ae=`stats-container`,A=`stat-card`,j=`trace-link`,M=`timestamp-cell`,N=`service-cell`,oe=`pagination-container`,P=`pagination-btn`,se=`page-info`,F=`log-entry-group`,I=`metadata-row`,L=`message-row`,R=`message-full-cell`,z=`attributes-cell`,ce=`
2
+ const e=require(`./chunk-DjWAcSYV.cjs`),t=require(`./stdio-Ivxk7vaP.cjs`);let n=require(`node:fs`),r=require(`node:path`);r=e.t(r);let i=require(`node:url`),a=require(`commander`),o=require(`@agimon-ai/foundation-process-registry`),s=require(`@agimon-ai/foundation-port-registry`),c=require(`@hono/node-server`),l=require(`node:fs/promises`);l=e.t(l);let u=require(`node:os`),d=require(`hono`),f=require(`hono/cors`),p=require(`hono-rate-limiter`),m=require(`zod`),h=require(`hono/html`),g=require(`hono/jsx/jsx-runtime`),_=function(e){return e.TRACE=`trace`,e.DEBUG=`debug`,e.INFO=`info`,e.WARN=`warn`,e.ERROR=`error`,e.FATAL=`fatal`,e}({});const v=m.z.object({service:m.z.string().optional(),level:m.z.string().optional(),traceId:m.z.string().optional(),search:m.z.string().optional(),limit:m.z.coerce.number().min(1).max(1e3).default(25),offset:m.z.coerce.number().min(0).default(0)});function y(e){let n=new d.Hono,r=e.get(t.d.LogQueryService),i=e.get(t.d.LogSearchService);return n.get(`/logs`,async e=>{try{let{service:t,level:n,traceId:a,search:o,limit:s,offset:c}=v.parse({service:e.req.query(`service`),level:e.req.query(`level`),traceId:e.req.query(`traceId`),search:e.req.query(`search`),limit:e.req.query(`limit`),offset:e.req.query(`offset`)}),l,u=0;if(o){let e={};t&&(e.service=t),n&&(e.level=n);let r=await i.searchLogsPaginated(o,{...e,offset:c},s);l=r.results,u=r.total}else{let e=n?n.split(`,`):[_.INFO,_.WARN,_.ERROR,_.FATAL],i=await r.queryLogs({level:e,service:t||void 0,traceId:a||void 0,limit:s,offset:c});l=i.logs,u=i.total}return e.json({logs:l,total:u,hasMore:c+s<u})}catch(t){return console.error(`Failed to query logs:`,t),e.json({error:`Failed to query logs`,message:t instanceof Error?t.message:String(t)},500)}}),n.get(`/services`,async e=>{try{let t=await r.getActiveServices();return e.json({services:t,total:t.length})}catch(t){return console.error(`Failed to get services:`,t),e.json({error:`Failed to get services`,message:t instanceof Error?t.message:String(t)},500)}}),n.get(`/stats`,async e=>{try{let t=await r.getStatistics(),n=t.reduce((e,t)=>e+t.count,0),i=t.filter(e=>e.level===`error`||e.level===`fatal`).reduce((e,t)=>e+t.count,0),a=new Set(t.map(e=>e.service)).size;return e.json({totalLogs:n,errors:i,services:a,breakdown:t})}catch(t){return console.error(`Failed to get statistics:`,t),e.json({error:`Failed to get statistics`,message:t instanceof Error?t.message:String(t)},500)}}),n}function b(e){return e.toLocaleString(`en-US`,{year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1})}const x=`dashboard-container`,ee=`dashboard-header`,te=`controls-section`,S=`input-field`,ne=`select-field`,re=`btn`,ie=`table-container`,C=`log-table`,w=`level-trace`,T=`level-debug`,E=`level-info`,D=`level-warn`,O=`level-error`,k=`level-fatal`,ae=`stats-container`,A=`stat-card`,j=`trace-link`,M=`timestamp-cell`,N=`service-cell`,oe=`pagination-container`,P=`pagination-btn`,se=`page-info`,F=`log-entry-group`,I=`metadata-row`,L=`message-row`,R=`message-full-cell`,z=`attributes-cell`,ce=`
3
3
  * {
4
4
  margin: 0;
5
5
  padding: 0;
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{a as e,c as t,d as n,i as r,l as i,n as a,o,r as s,s as c,t as l,u}from"./stdio-CEcpbT-x.mjs";import{existsSync as d,readFileSync as f}from"node:fs";import p,{dirname as m,join as h}from"node:path";import{fileURLToPath as g}from"node:url";import{Command as _,InvalidArgumentError as v}from"commander";import{ProcessRegistryService as y}from"@agimon-ai/foundation-process-registry";import{PortRegistryService as ee}from"@agimon-ai/foundation-port-registry";import{serve as te}from"@hono/node-server";import*as b from"node:fs/promises";import{tmpdir as x}from"node:os";import{Hono as S}from"hono";import{cors as C}from"hono/cors";import{rateLimiter as ne}from"hono-rate-limiter";import{z as w}from"zod";import{raw as re}from"hono/html";import{jsx as T,jsxs as E}from"hono/jsx/jsx-runtime";let D=function(e){return e.TRACE=`trace`,e.DEBUG=`debug`,e.INFO=`info`,e.WARN=`warn`,e.ERROR=`error`,e.FATAL=`fatal`,e}({});const ie=w.object({service:w.string().optional(),level:w.string().optional(),traceId:w.string().optional(),search:w.string().optional(),limit:w.coerce.number().min(1).max(1e3).default(25),offset:w.coerce.number().min(0).default(0)});function ae(e){let t=new S,r=e.get(n.LogQueryService),i=e.get(n.LogSearchService);return t.get(`/logs`,async e=>{try{let{service:t,level:n,traceId:a,search:o,limit:s,offset:c}=ie.parse({service:e.req.query(`service`),level:e.req.query(`level`),traceId:e.req.query(`traceId`),search:e.req.query(`search`),limit:e.req.query(`limit`),offset:e.req.query(`offset`)}),l,u=0;if(o){let e={};t&&(e.service=t),n&&(e.level=n);let r=await i.searchLogsPaginated(o,{...e,offset:c},s);l=r.results,u=r.total}else{let e=n?n.split(`,`):[D.INFO,D.WARN,D.ERROR,D.FATAL],i=await r.queryLogs({level:e,service:t||void 0,traceId:a||void 0,limit:s,offset:c});l=i.logs,u=i.total}return e.json({logs:l,total:u,hasMore:c+s<u})}catch(t){return console.error(`Failed to query logs:`,t),e.json({error:`Failed to query logs`,message:t instanceof Error?t.message:String(t)},500)}}),t.get(`/services`,async e=>{try{let t=await r.getActiveServices();return e.json({services:t,total:t.length})}catch(t){return console.error(`Failed to get services:`,t),e.json({error:`Failed to get services`,message:t instanceof Error?t.message:String(t)},500)}}),t.get(`/stats`,async e=>{try{let t=await r.getStatistics(),n=t.reduce((e,t)=>e+t.count,0),i=t.filter(e=>e.level===`error`||e.level===`fatal`).reduce((e,t)=>e+t.count,0),a=new Set(t.map(e=>e.service)).size;return e.json({totalLogs:n,errors:i,services:a,breakdown:t})}catch(t){return console.error(`Failed to get statistics:`,t),e.json({error:`Failed to get statistics`,message:t instanceof Error?t.message:String(t)},500)}}),t}function oe(e){return e.toLocaleString(`en-US`,{year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1})}const O=`log-table`,se=`level-trace`,ce=`level-debug`,le=`level-info`,ue=`level-warn`,k=`level-error`,A=`level-fatal`,j=`stat-card`,M=`trace-link`,N=`timestamp-cell`,P=`service-cell`,F=`pagination-btn`,I=`log-entry-group`,L=`metadata-row`,R=`message-row`,z=`message-full-cell`,B=`attributes-cell`;function de(e){let t=e.toLowerCase();return t===`trace`?se:t===`debug`?ce:t===`info`?le:t===`warn`?ue:t===`error`?k:t===`fatal`?A:``}function fe(e){if(!e||typeof e!=`object`)return null;let t=e,n={};for(let[e,r]of Object.entries(t))e===`trace.id`||e===`span.id`||(n[e]=r);return Object.keys(n).length>0?n:null}function pe({logs:e}){return T(`div`,{class:`table-container`,children:E(`table`,{class:O,children:[T(`thead`,{children:E(`tr`,{children:[T(`th`,{children:`Timestamp`}),T(`th`,{children:`Level`}),T(`th`,{children:`Service`}),T(`th`,{children:`Trace ID`})]})}),e.map(e=>{let t=fe(e.metadata);return E(`tbody`,{class:I,children:[E(`tr`,{class:L,children:[T(`td`,{class:N,children:oe(e.timestamp)}),T(`td`,{class:de(e.level),children:e.level.toUpperCase()}),T(`td`,{class:P,children:e.service}),T(`td`,{children:e.traceId?E(`span`,{class:M,onclick:`dashboard.filterByTrace('${e.traceId}')`,children:[e.traceId.slice(0,8),`...`]}):T(`span`,{children:`-`})})]}),T(`tr`,{class:R,children:E(`td`,{colspan:4,class:z,children:[T(`div`,{children:e.message}),t&&T(`pre`,{class:B,children:JSON.stringify(t,null,2)})]})})]},e.id)})]})})}function me(){return T(`input`,{id:`search-input`,type:`text`,class:`input-field`,placeholder:`Search logs...`,oninput:`dashboard.handleSearchInput(event)`})}function he({services:e}){return E(`select`,{id:`service-select`,class:`select-field`,onchange:`dashboard.handleServiceChange(event)`,children:[T(`option`,{value:``,children:`All Services`}),e.map(e=>T(`option`,{value:e,children:e},e))]})}function ge({stats:e}){return E(`div`,{class:`stats-container`,children:[E(`div`,{class:j,children:[T(`h3`,{children:`Total Logs`}),T(`div`,{class:`value`,children:e.totalLogs.toLocaleString()})]}),E(`div`,{class:j,children:[T(`h3`,{children:`Errors`}),T(`div`,{class:`value`,children:e.errors.toLocaleString()})]}),E(`div`,{class:j,children:[T(`h3`,{children:`Services`}),T(`div`,{class:`value`,children:e.services})]})]})}function _e({initialLogs:e,services:t,stats:n}){return E(`div`,{class:`dashboard-container`,children:[E(`div`,{class:`dashboard-header`,children:[T(`h1`,{children:`Log Dashboard`}),T(`p`,{children:`Real-time log streaming with auto-refresh (3 seconds)`})]}),T(ge,{stats:n}),E(`div`,{class:`controls-section`,children:[T(me,{}),T(he,{services:t}),T(`button`,{id:`refresh-btn`,class:`btn`,onclick:`dashboard.manualRefresh()`,children:`Refresh Now`})]}),T(pe,{logs:e}),E(`div`,{id:`pagination-controls`,class:`pagination-container`,children:[T(`button`,{id:`prev-btn`,class:F,onclick:`dashboard.prevPage()`,disabled:!0,children:`Previous`}),T(`span`,{id:`page-info`,class:`page-info`,children:`Page 1`}),T(`button`,{id:`next-btn`,class:F,onclick:`dashboard.nextPage()`,children:`Next`})]}),T(`script`,{children:re(`
2
+ import{a as e,c as t,d as n,i as r,l as i,n as a,o,r as s,s as c,t as l,u}from"./stdio-DXi11KM4.mjs";import{existsSync as d,readFileSync as f}from"node:fs";import p,{dirname as m,join as h}from"node:path";import{fileURLToPath as g}from"node:url";import{Command as _,InvalidArgumentError as v}from"commander";import{ProcessRegistryService as y}from"@agimon-ai/foundation-process-registry";import{PortRegistryService as ee}from"@agimon-ai/foundation-port-registry";import{serve as te}from"@hono/node-server";import*as b from"node:fs/promises";import{tmpdir as x}from"node:os";import{Hono as S}from"hono";import{cors as C}from"hono/cors";import{rateLimiter as ne}from"hono-rate-limiter";import{z as w}from"zod";import{raw as re}from"hono/html";import{jsx as T,jsxs as E}from"hono/jsx/jsx-runtime";let D=function(e){return e.TRACE=`trace`,e.DEBUG=`debug`,e.INFO=`info`,e.WARN=`warn`,e.ERROR=`error`,e.FATAL=`fatal`,e}({});const ie=w.object({service:w.string().optional(),level:w.string().optional(),traceId:w.string().optional(),search:w.string().optional(),limit:w.coerce.number().min(1).max(1e3).default(25),offset:w.coerce.number().min(0).default(0)});function ae(e){let t=new S,r=e.get(n.LogQueryService),i=e.get(n.LogSearchService);return t.get(`/logs`,async e=>{try{let{service:t,level:n,traceId:a,search:o,limit:s,offset:c}=ie.parse({service:e.req.query(`service`),level:e.req.query(`level`),traceId:e.req.query(`traceId`),search:e.req.query(`search`),limit:e.req.query(`limit`),offset:e.req.query(`offset`)}),l,u=0;if(o){let e={};t&&(e.service=t),n&&(e.level=n);let r=await i.searchLogsPaginated(o,{...e,offset:c},s);l=r.results,u=r.total}else{let e=n?n.split(`,`):[D.INFO,D.WARN,D.ERROR,D.FATAL],i=await r.queryLogs({level:e,service:t||void 0,traceId:a||void 0,limit:s,offset:c});l=i.logs,u=i.total}return e.json({logs:l,total:u,hasMore:c+s<u})}catch(t){return console.error(`Failed to query logs:`,t),e.json({error:`Failed to query logs`,message:t instanceof Error?t.message:String(t)},500)}}),t.get(`/services`,async e=>{try{let t=await r.getActiveServices();return e.json({services:t,total:t.length})}catch(t){return console.error(`Failed to get services:`,t),e.json({error:`Failed to get services`,message:t instanceof Error?t.message:String(t)},500)}}),t.get(`/stats`,async e=>{try{let t=await r.getStatistics(),n=t.reduce((e,t)=>e+t.count,0),i=t.filter(e=>e.level===`error`||e.level===`fatal`).reduce((e,t)=>e+t.count,0),a=new Set(t.map(e=>e.service)).size;return e.json({totalLogs:n,errors:i,services:a,breakdown:t})}catch(t){return console.error(`Failed to get statistics:`,t),e.json({error:`Failed to get statistics`,message:t instanceof Error?t.message:String(t)},500)}}),t}function oe(e){return e.toLocaleString(`en-US`,{year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1})}const O=`log-table`,se=`level-trace`,ce=`level-debug`,le=`level-info`,ue=`level-warn`,k=`level-error`,A=`level-fatal`,j=`stat-card`,M=`trace-link`,N=`timestamp-cell`,P=`service-cell`,F=`pagination-btn`,I=`log-entry-group`,L=`metadata-row`,R=`message-row`,z=`message-full-cell`,B=`attributes-cell`;function de(e){let t=e.toLowerCase();return t===`trace`?se:t===`debug`?ce:t===`info`?le:t===`warn`?ue:t===`error`?k:t===`fatal`?A:``}function fe(e){if(!e||typeof e!=`object`)return null;let t=e,n={};for(let[e,r]of Object.entries(t))e===`trace.id`||e===`span.id`||(n[e]=r);return Object.keys(n).length>0?n:null}function pe({logs:e}){return T(`div`,{class:`table-container`,children:E(`table`,{class:O,children:[T(`thead`,{children:E(`tr`,{children:[T(`th`,{children:`Timestamp`}),T(`th`,{children:`Level`}),T(`th`,{children:`Service`}),T(`th`,{children:`Trace ID`})]})}),e.map(e=>{let t=fe(e.metadata);return E(`tbody`,{class:I,children:[E(`tr`,{class:L,children:[T(`td`,{class:N,children:oe(e.timestamp)}),T(`td`,{class:de(e.level),children:e.level.toUpperCase()}),T(`td`,{class:P,children:e.service}),T(`td`,{children:e.traceId?E(`span`,{class:M,onclick:`dashboard.filterByTrace('${e.traceId}')`,children:[e.traceId.slice(0,8),`...`]}):T(`span`,{children:`-`})})]}),T(`tr`,{class:R,children:E(`td`,{colspan:4,class:z,children:[T(`div`,{children:e.message}),t&&T(`pre`,{class:B,children:JSON.stringify(t,null,2)})]})})]},e.id)})]})})}function me(){return T(`input`,{id:`search-input`,type:`text`,class:`input-field`,placeholder:`Search logs...`,oninput:`dashboard.handleSearchInput(event)`})}function he({services:e}){return E(`select`,{id:`service-select`,class:`select-field`,onchange:`dashboard.handleServiceChange(event)`,children:[T(`option`,{value:``,children:`All Services`}),e.map(e=>T(`option`,{value:e,children:e},e))]})}function ge({stats:e}){return E(`div`,{class:`stats-container`,children:[E(`div`,{class:j,children:[T(`h3`,{children:`Total Logs`}),T(`div`,{class:`value`,children:e.totalLogs.toLocaleString()})]}),E(`div`,{class:j,children:[T(`h3`,{children:`Errors`}),T(`div`,{class:`value`,children:e.errors.toLocaleString()})]}),E(`div`,{class:j,children:[T(`h3`,{children:`Services`}),T(`div`,{class:`value`,children:e.services})]})]})}function _e({initialLogs:e,services:t,stats:n}){return E(`div`,{class:`dashboard-container`,children:[E(`div`,{class:`dashboard-header`,children:[T(`h1`,{children:`Log Dashboard`}),T(`p`,{children:`Real-time log streaming with auto-refresh (3 seconds)`})]}),T(ge,{stats:n}),E(`div`,{class:`controls-section`,children:[T(me,{}),T(he,{services:t}),T(`button`,{id:`refresh-btn`,class:`btn`,onclick:`dashboard.manualRefresh()`,children:`Refresh Now`})]}),T(pe,{logs:e}),E(`div`,{id:`pagination-controls`,class:`pagination-container`,children:[T(`button`,{id:`prev-btn`,class:F,onclick:`dashboard.prevPage()`,disabled:!0,children:`Previous`}),T(`span`,{id:`page-info`,class:`page-info`,children:`Page 1`}),T(`button`,{id:`next-btn`,class:F,onclick:`dashboard.nextPage()`,children:`Next`})]}),T(`script`,{children:re(`
3
3
  class DashboardManager {
4
4
  constructor() {
5
5
  this.filters = {
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- const e=require(`./chunk-DjWAcSYV.cjs`),t=require(`./stdio-DSsKUa5U.cjs`),n=require(`./node-DNFj8zR9.cjs`);let r=require(`@opentelemetry/api`),i=require(`@opentelemetry/api-logs`);exports.StdioTransportHandler=t.t,exports.createNodeTelemetry=n.t,exports.createServer=t.n,exports.log=i.logs,exports.trace=r.trace;
1
+ const e=require(`./chunk-DjWAcSYV.cjs`),t=require(`./stdio-Ivxk7vaP.cjs`),n=require(`./node-DNFj8zR9.cjs`);let r=require(`@opentelemetry/api`),i=require(`@opentelemetry/api-logs`);exports.StdioTransportHandler=t.t,exports.createNodeTelemetry=n.t,exports.createServer=t.n,exports.log=i.logs,exports.trace=r.trace;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{n as e,t}from"./stdio-CEcpbT-x.mjs";import{n,r,t as i}from"./node-a-wBAoyd.mjs";export{t as StdioTransportHandler,i as createNodeTelemetry,e as createServer,n as log,r as trace};
1
+ import{n as e,t}from"./stdio-DXi11KM4.mjs";import{n,r,t as i}from"./node-a-wBAoyd.mjs";export{t as StdioTransportHandler,i as createNodeTelemetry,e as createServer,n as log,r as trace};
@@ -0,0 +1,245 @@
1
+ import{existsSync as e}from"node:fs";import t,{dirname as n,join as r}from"node:path";import{fileURLToPath as i}from"node:url";import{ProcessRegistryService as a}from"@agimon-ai/foundation-process-registry";import{PortRegistryService as o}from"@agimon-ai/foundation-port-registry";import{Container as s,ContainerModule as c,inject as l,injectable as u,unmanaged as d}from"inversify";import"reflect-metadata";import{spawn as f}from"node:child_process";import p,{mkdir as m,stat as h}from"node:fs/promises";import{homedir as ee,tmpdir as g}from"node:os";import{DatabaseSync as _}from"node:sqlite";import{ulid as v}from"ulidx";import*as y from"sqlite-vec";import{Server as b}from"@modelcontextprotocol/sdk/server/index.js";import{CallToolRequestSchema as x,ListToolsRequestSchema as S}from"@modelcontextprotocol/sdk/types.js";import{StdioServerTransport as C}from"@modelcontextprotocol/sdk/server/stdio.js";function w(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}let T=class{defaultTimeout=5e3;async check(e,t=this.defaultTimeout){try{let n=`http://localhost:${e}/health`,r=new AbortController,i=setTimeout(()=>r.abort(),t);try{let t=await fetch(n,{signal:r.signal,headers:{"Content-Type":`application/json`}});if(clearTimeout(i),!t.ok)return{healthy:!1,error:`HTTP error ${t.status}: ${t.statusText}`};let a=await t.json();return a.status===`healthy`?{healthy:!0,port:e,serviceName:a.serviceName??a.service}:{healthy:!1,error:`Unexpected health status: ${a.status||`unknown`}`}}catch(e){return clearTimeout(i),e instanceof Error?e.name===`AbortError`?{healthy:!1,error:`Health check timed out after ${t}ms`}:`code`in e&&e.code===`ECONNREFUSED`?{healthy:!1,error:`Connection refused - server not running`}:{healthy:!1,error:`Network error: ${e.message}`}:{healthy:!1,error:`Unknown error: ${String(e)}`}}}catch(e){return{healthy:!1,error:e instanceof Error?e.message:String(e)}}}};T=w([u()],T);const E={LogStorageService:Symbol.for(`LogStorageService`),EmbeddingService:Symbol.for(`EmbeddingService`),LogQueryService:Symbol.for(`LogQueryService`),LogSearchService:Symbol.for(`LogSearchService`),SemanticSearchService:Symbol.for(`SemanticSearchService`),LogRetentionService:Symbol.for(`LogRetentionService`),HttpServerHealthCheck:Symbol.for(`HttpServerHealthCheck`),HttpServerManager:Symbol.for(`HttpServerManager`),Database:Symbol.for(`Database`),Logger:Symbol.for(`Logger`),HttpServer:Symbol.for(`HttpServer`),McpServer:Symbol.for(`McpServer`)};function D(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function O(e,t){return function(n,r){t(n,r,e)}}const k=i(import.meta.url),A=t.dirname(k),j=[`pnpm-workspace.yaml`,`nx.json`,`.git`];function M(n=process.cwd()){let r=t.resolve(n);for(;;){for(let n of j)if(e(t.join(r,n)))return r;let n=t.dirname(r);if(n===r)return process.cwd();r=n}}function N(e,n){if(!e)return;let r=t.resolve(e);return t.extname(r)===`.json`?t.join(t.dirname(r),n):t.join(r,n)}let P=class{repositoryPath;environment;serviceName=`log-sink-mcp-http`;serviceType=`tool`;host=`127.0.0.1`;registryPath;portRegistry;processRegistry;constructor(e,n,r){this.healthCheck=e,this.repositoryPath=M(n?t.resolve(n):process.cwd()),this.environment=process.env.NODE_ENV||`development`,this.registryPath=r||process.env.PORT_REGISTRY_PATH,this.portRegistry=new o(this.registryPath),this.processRegistry=new a(N(this.registryPath,`processes.json`))}async getRegistration(){let e=await this.portRegistry.getPort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:this.serviceType,environment:this.environment});return!e.success||!e.record?null:{port:e.record.port,pid:e.record.pid,environment:e.record.environment??this.environment,host:e.record.host,metadata:e.record.metadata}}async releaseService(e){let t=await this.portRegistry.releasePort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:this.serviceType,environment:this.environment,...e?{pid:e}:{}});if(!t.success&&!t.error?.includes(`No matching registry entry`))throw Error(t.error||`Failed to release registry entry`)}async releaseProcess(e){let t=await this.processRegistry.releaseProcess({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:this.serviceType,environment:this.environment,...e?{pid:e}:{},kill:!1,releasePort:!1});if(!t.success&&!t.error?.includes(`No matching process entry`))throw Error(t.error||`Failed to release process entry`)}async findAvailablePort(e){let t=await this.portRegistry.findAvailablePort({repositoryPath:this.repositoryPath,serviceName:this.serviceName,serviceType:this.serviceType,environment:this.environment,host:this.host,preferredPort:e});if(!t.success||!t.port)throw Error(`No available port found from ${e}: ${t.error}`);return t.port}async fileExists(e){try{return await p.access(e),!0}catch{return!1}}async startHttpServer(e,n){let r=[t.resolve(A,`cli.mjs`),t.resolve(A,`..`,`dist`,`cli.mjs`),t.resolve(A,`..`,`..`,`dist`,`cli.mjs`)],i=[t.resolve(A,`..`,`cli.ts`),t.resolve(A,`..`,`..`,`src`,`cli.ts`)],a;for(let e of r)if(await this.fileExists(e)){a=e;break}let o;if(!a){for(let e of i)if(await this.fileExists(e)){o=e;break}}let s,c;if(a)s=process.execPath,c=[a,`http-serve`,`--port`,e.toString()];else if(o)s=process.execPath,c=[`--import`,`tsx`,o,`http-serve`,`--port`,e.toString()];else throw Error(`Cannot find log-sink MCP CLI in any expected location`);let l=t.resolve(n);await p.mkdir(t.dirname(l),{recursive:!0});let u=f(s,[...c,`--db-path`,l],{detached:!0,stdio:`ignore`,env:{...process.env,...this.registryPath?{PORT_REGISTRY_PATH:this.registryPath}:{},NODE_ENV:this.environment}});u.unref();let d=u.pid;if(!d)throw Error(`Failed to spawn HTTP server - no PID returned`);return d}async waitForRegisteredService(e,t,n=10,r=250){for(let i=0;i<n;i+=1){let n=await this.getRegistration();if(n?.pid===t&&n.port===e)return n;await new Promise(e=>setTimeout(e,r))}return null}async waitForServerStartup(e=4e3){await new Promise(t=>setTimeout(t,e))}async killProcess(e){try{process.kill(e,0),process.kill(e,`SIGTERM`),await new Promise(e=>setTimeout(e,1e3));try{process.kill(e,0),process.kill(e,`SIGKILL`)}catch{}}catch{}}async ensureRunning(e=3100,t=`./logs/session.db`){try{let n=await this.getRegistration();if(n){let e=await this.healthCheck.check(n.port);if(e.healthy&&e.serviceName===this.serviceName)return{running:!0,port:n.port,pid:n.pid};n.pid&&await this.killProcess(n.pid),await this.releaseProcess(n.pid),await this.releaseService(n.pid)}let r=e;for(let e=0;e<3;e+=1){let e=await this.findAvailablePort(r),n=await this.startHttpServer(e,t);await this.waitForServerStartup();let i=await this.healthCheck.check(e);if(!i.healthy||i.serviceName!==this.serviceName){await this.killProcess(n),await this.releaseProcess(n),await this.releaseService(n),r=e+1;continue}if(!await this.waitForRegisteredService(e,n)){await this.killProcess(n),await this.releaseProcess(n),await this.releaseService(n),r=e+1;continue}return{running:!0,port:e,pid:n}}return{running:!1,error:`Failed to start log-sink-mcp HTTP server after retries`}}catch(e){return{running:!1,error:e instanceof Error?e.message:String(e)}}}async stop(){try{let e=await this.getRegistration();if(!e)return!1;try{if(e.pid&&process.kill(e.pid,`SIGTERM`),await new Promise(e=>setTimeout(e,1e3)),e.pid)try{process.kill(e.pid,0),process.kill(e.pid,`SIGKILL`)}catch{}}catch{}return await this.releaseProcess(e.pid),await this.releaseService(e.pid),!0}catch(e){throw Error(`Failed to stop HTTP server: ${e instanceof Error?e.message:String(e)}`)}}async getStatus(){try{let e=await this.getRegistration();if(!e)return{running:!1,error:`No HTTP server registered`};let t=await this.healthCheck.check(e.port);return t.healthy&&t.serviceName===this.serviceName?{running:!0,port:e.port,pid:e.pid}:{running:!1,port:e.port,pid:e.pid,error:t.error}}catch(e){return{running:!1,error:e instanceof Error?e.message:String(e)}}}};P=w([u(),O(0,l(E.HttpServerHealthCheck)),O(1,d()),O(2,d()),D(`design:paramtypes`,[Object,String,String])],P);var F;let I=class{static{F=this}static DEFAULT_MODEL=`all-MiniLM-L6-v2`;static VECTOR_DIMENSION=384;static CACHE_DIR=r(ee(),`.log-sink-mcp`);embedderPromise=null;modelUnavailable=!1;loaderPromise=null;constructor(e){this.storage=e}get modelName(){return process.env.LOG_SINK_EMBEDDING_MODEL??F.DEFAULT_MODEL}async loadLoader(){return this.loaderPromise||=import(`ruvector-onnx-embeddings-wasm/loader.js`).catch(e=>{let t=e&&typeof e==`object`&&`code`in e?String(e.code):``,n=e instanceof Error?e.message:String(e);if(t===`ERR_MODULE_NOT_FOUND`||t===`MODULE_NOT_FOUND`||n.includes(`ruvector-onnx`))return null;throw e}),this.loaderPromise}async getEmbedder(){if(this.modelUnavailable)throw Error(`Embedding model is not available locally`);if(!this.embedderPromise){let e=await this.loadLoader();if(!e)throw this.modelUnavailable=!0,Error(`Embedding model support is disabled because ruvector-onnx-embeddings-wasm is not installed`);await m(F.CACHE_DIR,{recursive:!0}),this.embedderPromise=e.createEmbedder(this.modelName).catch(e=>{throw this.embedderPromise=null,this.modelUnavailable=!0,e})}return this.embedderPromise}async isAvailable(){if(this.modelUnavailable)return!1;try{return await this.getEmbedder(),!0}catch{return!1}}buildEmbeddingText(e){let t=e.metadata&&typeof e.metadata==`object`?JSON.stringify(e.metadata):e.metadata??``;return[`service: ${e.service}`,`level: ${e.level}`,`message: ${e.message}`,e.errorType?`errorType: ${e.errorType}`:null,e.errorMessage?`errorMessage: ${e.errorMessage}`:null,t?`metadata: ${t}`:null].filter(Boolean).join(`
2
+ `)}normalizeVector(e){let t=Math.sqrt(e.reduce((e,t)=>e+t*t,0));return t===0?e:e.map(e=>e/t)}toVector(e){if(e instanceof Float32Array||e instanceof Float64Array)return Array.from(e);if(Array.isArray(e)&&e.length>0&&typeof e[0]==`number`)return e;if(Array.isArray(e)&&e.length>0&&Array.isArray(e[0]))return e[0];throw Error(`Unexpected embedding output shape`)}async embedText(e){let t=await this.getEmbedder(),n=this.normalizeVector(this.toVector(t.embedOne(e)));if(n.length!==F.VECTOR_DIMENSION)throw Error(`Unexpected embedding dimension ${n.length}, expected ${F.VECTOR_DIMENSION}`);return n}async indexLogs(e){if(e.length!==0)try{let t=[];for(let n of e)t.push({log:n,embedding:await this.embedText(this.buildEmbeddingText(n))});let n=this.storage.getSqliteClient(),r=n.prepare(`
3
+ INSERT INTO log_embeddings (log_id, embedding, service, level, created_at)
4
+ VALUES (?, vec_f32(?), ?, ?, ?)
5
+ ON CONFLICT(log_id) DO UPDATE SET
6
+ embedding = excluded.embedding,
7
+ service = excluded.service,
8
+ level = excluded.level,
9
+ created_at = excluded.created_at
10
+ `);n.exec(`BEGIN`);try{for(let e of t)r.run(e.log.id,new Uint8Array(new Float32Array(e.embedding).buffer),e.log.service,e.log.level,Math.floor(e.log.createdAt.getTime()/1e3));n.exec(`COMMIT`)}catch(e){throw n.exec(`ROLLBACK`),e}}catch(e){console.warn(`Skipping semantic embedding indexing: ${e instanceof Error?e.message:String(e)}`)}}};I=F=w([u(),O(0,l(E.LogStorageService)),D(`design:paramtypes`,[Object])],I);function L(e){return e}let R=class{constructor(e){this.storage=e}async getSqlite(){return await this.storage.ensureInitialized(),this.storage.getSqliteClient()}mapRow(e){return{id:e.id,timestamp:new Date(Number(e.timestamp)*1e3),level:e.level,message:e.message,traceId:e.trace_id,spanId:e.span_id,parentSpanId:e.parent_span_id,service:e.service,hostname:e.hostname,pid:e.pid,metadata:e.metadata?JSON.parse(e.metadata):null,errorType:e.error_type,errorMessage:e.error_message,errorStack:e.error_stack,createdAt:new Date(Number(e.created_at)*1e3)}}buildWhereClause(e){let t=`WHERE 1 = 1`,n=[];if(e.level){let r=Array.isArray(e.level)?e.level:[e.level];t+=` AND level IN (${r.map(()=>`?`).join(`,`)})`,n.push(...r)}if(e.service){let r=Array.isArray(e.service)?e.service:[e.service];t+=` AND service IN (${r.map(()=>`?`).join(`,`)})`,n.push(...r)}return e.traceId&&(t+=` AND trace_id = ?`,n.push(e.traceId)),e.startTime&&(t+=` AND timestamp >= ?`,n.push(Math.floor(e.startTime.getTime()/1e3))),e.endTime&&(t+=` AND timestamp <= ?`,n.push(Math.floor(e.endTime.getTime()/1e3))),{whereSql:t,params:n}}async filterByLevel(e,t=100){try{let n=await this.getSqlite(),{whereSql:r,params:i}=this.buildWhereClause({level:e});return L(n.prepare(`
11
+ SELECT
12
+ id, timestamp, level, message, trace_id, span_id, parent_span_id,
13
+ service, hostname, pid, metadata, error_type, error_message,
14
+ error_stack, created_at
15
+ FROM logs
16
+ ${r}
17
+ ORDER BY timestamp DESC
18
+ LIMIT ?
19
+ `).all(...i,t)).map(e=>this.mapRow(e))}catch(e){throw Error(`Failed to filter by level: ${e instanceof Error?e.message:String(e)}`)}}async filterByTrace(e){try{return L((await this.getSqlite()).prepare(`
20
+ SELECT
21
+ id, timestamp, level, message, trace_id, span_id, parent_span_id,
22
+ service, hostname, pid, metadata, error_type, error_message,
23
+ error_stack, created_at
24
+ FROM logs
25
+ WHERE trace_id = ?
26
+ ORDER BY timestamp ASC
27
+ `).all(e)).map(e=>this.mapRow(e))}catch(e){throw Error(`Failed to filter by trace: ${e instanceof Error?e.message:String(e)}`)}}async filterByTimeRange(e,t){try{return L((await this.getSqlite()).prepare(`
28
+ SELECT
29
+ id, timestamp, level, message, trace_id, span_id, parent_span_id,
30
+ service, hostname, pid, metadata, error_type, error_message,
31
+ error_stack, created_at
32
+ FROM logs
33
+ WHERE timestamp >= ? AND timestamp <= ?
34
+ ORDER BY timestamp ASC
35
+ `).all(Math.floor(e.getTime()/1e3),Math.floor(t.getTime()/1e3))).map(e=>this.mapRow(e))}catch(e){throw Error(`Failed to filter by time range: ${e instanceof Error?e.message:String(e)}`)}}async filterByService(e){try{let t=await this.getSqlite(),n=Array.isArray(e)?e:[e];return L(t.prepare(`
36
+ SELECT
37
+ id, timestamp, level, message, trace_id, span_id, parent_span_id,
38
+ service, hostname, pid, metadata, error_type, error_message,
39
+ error_stack, created_at
40
+ FROM logs
41
+ WHERE service IN (${n.map(()=>`?`).join(`,`)})
42
+ ORDER BY timestamp ASC
43
+ `).all(...n)).map(e=>this.mapRow(e))}catch(e){throw Error(`Failed to filter by service: ${e instanceof Error?e.message:String(e)}`)}}async getTraceTimeline(e){try{let t=await this.filterByTrace(e),n=[];for(let e=0;e<t.length;e+=1){let r=t[e],i=t[e+1];n.push({timestamp:r.timestamp,service:r.service,spanId:r.spanId??null,parentSpanId:r.parentSpanId??null,level:r.level,message:r.message,duration:i?i.timestamp.getTime()-r.timestamp.getTime():void 0})}return n}catch(e){throw Error(`Failed to get trace timeline: ${e instanceof Error?e.message:String(e)}`)}}async getStatistics(e,t=`both`){try{let n=await this.getSqlite(),r=``,i=[];e&&(r=`WHERE timestamp >= ? AND timestamp <= ?`,i.push(Math.floor(e.start.getTime()/1e3),Math.floor(e.end.getTime()/1e3)));let a=`service, level, COUNT(*) as count`,o=`GROUP BY service, level`;return t===`level`?(a=`'' as service, level, COUNT(*) as count`,o=`GROUP BY level`):t===`service`&&(a=`service, '' as level, COUNT(*) as count`,o=`GROUP BY service`),L(n.prepare(`
44
+ SELECT ${a}
45
+ FROM logs
46
+ ${r}
47
+ ${o}
48
+ `).all(...i)).map(e=>({service:e.service,level:e.level,count:Number(e.count)}))}catch(e){throw Error(`Failed to get statistics: ${e instanceof Error?e.message:String(e)}`)}}async getActiveServices(){try{return L((await this.getSqlite()).prepare(`SELECT DISTINCT service FROM logs ORDER BY service ASC`).all()).map(e=>e.service)}catch(e){throw Error(`Failed to get active services: ${e instanceof Error?e.message:String(e)}`)}}async countByLevel(e){try{let t=await this.getSqlite(),n=Array.isArray(e)?e:[e],r=t.prepare(`
49
+ SELECT COUNT(*) as count
50
+ FROM logs
51
+ WHERE level IN (${n.map(()=>`?`).join(`,`)})
52
+ `).all(...n);return Number(L(r)[0]?.count??0)}catch(e){throw Error(`Failed to count by level: ${e instanceof Error?e.message:String(e)}`)}}async countByService(e){try{let t=await this.getSqlite(),n=Array.isArray(e)?e:[e],r=t.prepare(`
53
+ SELECT COUNT(*) as count
54
+ FROM logs
55
+ WHERE service IN (${n.map(()=>`?`).join(`,`)})
56
+ `).all(...n);return Number(L(r)[0]?.count??0)}catch(e){throw Error(`Failed to count by service: ${e instanceof Error?e.message:String(e)}`)}}async countByTrace(e){try{let t=L((await this.getSqlite()).prepare(`SELECT COUNT(*) as count FROM logs WHERE trace_id = ?`).all(e));return Number(t[0]?.count??0)}catch(e){throw Error(`Failed to count by trace: ${e instanceof Error?e.message:String(e)}`)}}async queryLogs(e){try{let t=await this.getSqlite(),{level:n,service:r,traceId:i,limit:a=25,offset:o=0}=e,s={};n&&(s.level=n),r&&(s.service=r),i&&(s.traceId=i);let{whereSql:c,params:l}=this.buildWhereClause(s),u=L(t.prepare(`
57
+ SELECT COUNT(*) as count
58
+ FROM logs
59
+ ${c}
60
+ `).all(...l));return{logs:L(t.prepare(`
61
+ SELECT
62
+ id, timestamp, level, message, trace_id, span_id, parent_span_id,
63
+ service, hostname, pid, metadata, error_type, error_message,
64
+ error_stack, created_at
65
+ FROM logs
66
+ ${c}
67
+ ORDER BY timestamp DESC
68
+ LIMIT ?
69
+ OFFSET ?
70
+ `).all(...l,a,o)).map(e=>this.mapRow(e)),total:Number(u[0]?.count??0)}}catch(e){throw Error(`Failed to query logs: ${e instanceof Error?e.message:String(e)}`)}}};R=w([u(),O(0,l(E.LogStorageService)),D(`design:paramtypes`,[Object])],R);let z=class{sizeRetentionTimer=null;sizeRetentionRunPromise=null;constructor(e){this.storage=e}async getSqlite(){return await this.storage.ensureInitialized(),this.storage.getSqliteClient()}async cleanupOldLogs(e){try{let t=await this.getSqlite(),n=new Date;n.setDate(n.getDate()-e);let r=t.prepare(`DELETE FROM logs WHERE timestamp <= ?`).run(Math.floor(n.getTime()/1e3));return Number(r.changes??0)}catch(e){throw Error(`Failed to cleanup old logs: ${e instanceof Error?e.message:String(e)}`)}}async clearAllLogs(){try{return await this.storage.deleteAllLogs()}catch(e){throw Error(`Failed to clear all logs: ${e instanceof Error?e.message:String(e)}`)}}async cleanupOversizedDatabase(e){try{if(!Number.isFinite(e.maxBytes)||e.maxBytes<=0)throw Error(`maxBytes must be a positive number`);if(!Number.isFinite(e.intervalMs)||e.intervalMs<=0)throw Error(`intervalMs must be a positive number`);let t=e.batchSize??1e3,n=Math.min(e.targetBytes??Math.floor(e.maxBytes*.9),e.maxBytes),r=await this.storage.getDatabaseSizeBytes();if(r===null||r<=e.maxBytes)return{sizeBeforeBytes:r,sizeAfterBytes:r,deletedEntries:0,iterations:0,trimmed:!1};let i=r,a=0,o=0;for(;i>n;){let e=await this.storage.deleteOldestLogs(t);if(e===0)break;a+=e,o+=1,await this.storage.compactDatabase();let n=await this.storage.getDatabaseSizeBytes();n!==null&&(i=n)}return{sizeBeforeBytes:r,sizeAfterBytes:i,deletedEntries:a,iterations:o,trimmed:a>0}}catch(e){throw Error(`Failed to cleanup oversized database: ${e instanceof Error?e.message:String(e)}`)}}startSizeRetentionMonitor(e){this.stopSizeRetentionMonitor();let t=async()=>{this.sizeRetentionRunPromise||(this.sizeRetentionRunPromise=(async()=>{try{await this.cleanupOversizedDatabase(e)}catch(e){console.warn(`Failed to run periodic database retention: ${e instanceof Error?e.message:String(e)}`)}finally{this.sizeRetentionRunPromise=null}})(),await this.sizeRetentionRunPromise)};return t(),this.sizeRetentionTimer=setInterval(()=>{t()},e.intervalMs),this.sizeRetentionTimer.unref?.(),()=>{this.stopSizeRetentionMonitor()}}stopSizeRetentionMonitor(){this.sizeRetentionTimer&&=(clearInterval(this.sizeRetentionTimer),null)}};z=w([u(),O(0,l(E.LogStorageService)),D(`design:paramtypes`,[Object])],z);function B(e){return e}let V=class{constructor(e){this.storage=e}async getSqlite(){return await this.storage.ensureInitialized(),this.storage.getSqliteClient()}buildSearchSql(e,t={}){let n=e.replace(/[^\w\s\-"*]/g,``).trim();if(!n)throw Error(`Search query is empty after sanitization`);let r=`WHERE logs_search MATCH ?`,i=[n];if(t.service){let e=Array.isArray(t.service)?t.service:[t.service];r+=` AND logs.service IN (${e.map(()=>`?`).join(`,`)})`,i.push(...e)}if(t.level){let e=Array.isArray(t.level)?t.level:[t.level];r+=` AND logs.level IN (${e.map(()=>`?`).join(`,`)})`,i.push(...e)}return t.startTime&&(r+=` AND logs.timestamp >= ?`,i.push(Math.floor(t.startTime.getTime()/1e3))),t.endTime&&(r+=` AND logs.timestamp <= ?`,i.push(Math.floor(t.endTime.getTime()/1e3))),{whereSql:r,params:i}}mapSearchRow(e){return{id:e.id,timestamp:new Date(e.timestamp*1e3),level:e.level,message:e.message,traceId:e.traceId,spanId:e.spanId,parentSpanId:e.parentSpanId,service:e.service,hostname:e.hostname,pid:e.pid,metadata:e.metadata?JSON.parse(e.metadata):null,errorType:e.errorType,errorMessage:e.errorMessage,errorStack:e.errorStack,createdAt:new Date(e.createdAt*1e3),rank:e.rank}}async searchLogs(e,t={},n=100){let{results:r}=await this.searchLogsPaginated(e,{...t,offset:0},n);return r}async searchLogsPaginated(e,t={},n=100){try{let r=await this.getSqlite(),{whereSql:i,params:a}=this.buildSearchSql(e,t),o=t.offset??0,s=`
71
+ SELECT COUNT(*) as total
72
+ FROM logs_search
73
+ JOIN logs ON logs.rowid = logs_search.rowid
74
+ ${i}
75
+ `,c=`
76
+ SELECT
77
+ logs.id as id,
78
+ logs.timestamp as timestamp,
79
+ logs.level as level,
80
+ logs.message as message,
81
+ logs.trace_id as traceId,
82
+ logs.span_id as spanId,
83
+ logs.parent_span_id as parentSpanId,
84
+ logs.service as service,
85
+ logs.hostname as hostname,
86
+ logs.pid as pid,
87
+ logs.metadata as metadata,
88
+ logs.error_type as errorType,
89
+ logs.error_message as errorMessage,
90
+ logs.error_stack as errorStack,
91
+ logs.created_at as createdAt,
92
+ logs_search.rank as rank
93
+ FROM logs_search
94
+ JOIN logs ON logs.rowid = logs_search.rowid
95
+ ${i}
96
+ ORDER BY rank
97
+ LIMIT ?
98
+ OFFSET ?
99
+ `,l=r.prepare(s).get(...a);return{results:B(r.prepare(c).all(...a,n,o)).map(e=>this.mapSearchRow(e)),total:Number(l.total??0)}}catch(e){throw Error(`Failed to search logs: ${e instanceof Error?e.message:String(e)}`)}}rankResults(e){return e.sort((e,t)=>e.rank-t.rank)}};V=w([u(),O(0,l(E.LogStorageService)),D(`design:paramtypes`,[Object])],V);function H(e){return e}let U=class{sqlite=null;embeddingWriter=null;databasePath=null;useInMemory=!1;setEmbeddingWriter(e){this.embeddingWriter=e}async initializeDatabase(e,t=!1){try{let r=t?`:memory:`:e;this.databasePath=r,this.useInMemory=t,t||await m(n(r),{recursive:!0}),this.sqlite=new _(r,{allowExtension:!0}),y.load(this.sqlite),t||this.sqlite.exec(`PRAGMA journal_mode = WAL`),this.sqlite.exec(`PRAGMA foreign_keys = ON`),this.sqlite.exec(`
100
+ CREATE TABLE IF NOT EXISTS logs (
101
+ id text PRIMARY KEY NOT NULL,
102
+ timestamp integer NOT NULL,
103
+ level text NOT NULL,
104
+ message text NOT NULL,
105
+ trace_id text,
106
+ span_id text,
107
+ parent_span_id text,
108
+ service text NOT NULL,
109
+ hostname text,
110
+ pid integer,
111
+ metadata text,
112
+ error_type text,
113
+ error_message text,
114
+ error_stack text,
115
+ created_at integer NOT NULL
116
+ )
117
+ `),this.sqlite.exec(`CREATE INDEX IF NOT EXISTS logs_timestamp_idx ON logs (timestamp)`),this.sqlite.exec(`CREATE INDEX IF NOT EXISTS logs_level_idx ON logs (level)`),this.sqlite.exec(`CREATE INDEX IF NOT EXISTS logs_trace_id_idx ON logs (trace_id)`),this.sqlite.exec(`CREATE INDEX IF NOT EXISTS logs_span_id_idx ON logs (span_id)`),this.sqlite.exec(`CREATE INDEX IF NOT EXISTS logs_parent_span_id_idx ON logs (parent_span_id)`),this.sqlite.exec(`CREATE INDEX IF NOT EXISTS logs_service_idx ON logs (service)`),this.sqlite.exec(`CREATE INDEX IF NOT EXISTS logs_error_type_idx ON logs (error_type)`),this.sqlite.exec(`
118
+ CREATE TABLE IF NOT EXISTS log_embeddings (
119
+ log_id text PRIMARY KEY NOT NULL,
120
+ embedding text NOT NULL,
121
+ service text NOT NULL,
122
+ level text NOT NULL,
123
+ created_at integer NOT NULL,
124
+ FOREIGN KEY (log_id) REFERENCES logs(id) ON DELETE CASCADE
125
+ ) STRICT
126
+ `),this.sqlite.exec(`CREATE INDEX IF NOT EXISTS log_embeddings_service_idx ON log_embeddings (service)`),this.sqlite.exec(`CREATE INDEX IF NOT EXISTS log_embeddings_level_idx ON log_embeddings (level)`),this.sqlite.exec(`CREATE INDEX IF NOT EXISTS log_embeddings_created_at_idx ON log_embeddings (created_at)`),this.sqlite.exec(`
127
+ CREATE VIRTUAL TABLE IF NOT EXISTS logs_search USING fts5(
128
+ id UNINDEXED,
129
+ message,
130
+ error_message,
131
+ content='logs',
132
+ content_rowid='rowid'
133
+ )
134
+ `),this.sqlite.exec(`
135
+ CREATE TRIGGER IF NOT EXISTS logs_ai AFTER INSERT ON logs BEGIN
136
+ INSERT INTO logs_search(rowid, id, message, error_message)
137
+ VALUES (new.rowid, new.id, new.message, new.error_message);
138
+ END;
139
+ `),this.sqlite.exec(`
140
+ CREATE TRIGGER IF NOT EXISTS logs_ad AFTER DELETE ON logs BEGIN
141
+ DELETE FROM logs_search WHERE rowid = old.rowid;
142
+ END;
143
+ `),this.sqlite.exec(`
144
+ CREATE TRIGGER IF NOT EXISTS logs_au AFTER UPDATE ON logs BEGIN
145
+ UPDATE logs_search SET message = new.message, error_message = new.error_message
146
+ WHERE rowid = new.rowid;
147
+ END;
148
+ `)}catch(e){throw Error(`Failed to initialize database: ${e instanceof Error?e.message:String(e)}`)}}getDefaultDbPath(){return r(g(),`log-sink-mcp`,`session.db`)}isInitialized(){return this.sqlite!==null}async ensureInitialized(){this.sqlite||await this.initializeDatabase(this.getDefaultDbPath())}mapRow(e){return{id:e.id,timestamp:new Date(Number(e.timestamp)*1e3),level:e.level,message:e.message,traceId:e.trace_id,spanId:e.span_id,parentSpanId:e.parent_span_id,service:e.service,hostname:e.hostname,pid:e.pid,metadata:e.metadata?JSON.parse(e.metadata):null,errorType:e.error_type,errorMessage:e.error_message,errorStack:e.error_stack,createdAt:new Date(Number(e.created_at)*1e3)}}prepareLogRecord(e){let t=new Date;return{id:e.id??v(),timestamp:e.timestamp??t,level:e.level,message:e.message,traceId:e.traceId??null,spanId:e.spanId??null,parentSpanId:e.parentSpanId??null,service:e.service,hostname:e.hostname??null,pid:e.pid??null,metadata:e.metadata??null,errorType:e.errorType??null,errorMessage:e.errorMessage??null,errorStack:e.errorStack??null,createdAt:e.createdAt??t}}getDatabaseClient(){if(!this.sqlite)throw Error(`Database not initialized. Call initializeDatabase() first.`);return this.sqlite}getSqliteClient(){if(!this.sqlite)throw Error(`Database not initialized. Call initializeDatabase() first.`);return this.sqlite}getDatabasePath(){return this.useInMemory||this.databasePath===`:memory:`?null:this.databasePath}async getDatabaseSizeBytes(){let e=this.getDatabasePath();if(!e)return null;let t=[e,`${e}-wal`,`${e}-shm`];return(await Promise.all(t.map(async e=>{try{return(await h(e)).size}catch{return 0}}))).reduce((e,t)=>e+t,0)}async deleteOldestLogs(e){try{if(!this.sqlite)throw Error(`Database not initialized`);if(!Number.isInteger(e)||e<=0)return 0;let t=this.sqlite.prepare(`
149
+ DELETE FROM logs
150
+ WHERE id IN (
151
+ SELECT id
152
+ FROM logs
153
+ ORDER BY timestamp ASC, created_at ASC, id ASC
154
+ LIMIT ?
155
+ )
156
+ `).run(e);return Number(t.changes??0)}catch(e){throw Error(`Failed to delete oldest logs: ${e instanceof Error?e.message:String(e)}`)}}async compactDatabase(){try{if(!this.sqlite)throw Error(`Database not initialized`);this.sqlite.exec(`PRAGMA wal_checkpoint(TRUNCATE)`),this.sqlite.exec(`VACUUM`)}catch(e){throw Error(`Failed to compact database: ${e instanceof Error?e.message:String(e)}`)}}async insertLog(e){try{let t=this.getSqliteClient(),n=this.prepareLogRecord(e);return t.prepare(`
157
+ INSERT INTO logs (
158
+ id, timestamp, level, message, trace_id, span_id, parent_span_id,
159
+ service, hostname, pid, metadata, error_type, error_message,
160
+ error_stack, created_at
161
+ )
162
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
163
+ `).run(n.id,Math.floor(n.timestamp.getTime()/1e3),n.level,n.message,n.traceId,n.spanId,n.parentSpanId,n.service,n.hostname,n.pid,n.metadata?JSON.stringify(n.metadata):null,n.errorType,n.errorMessage,n.errorStack,Math.floor(n.createdAt.getTime()/1e3)),await this.tryIndexEmbeddings([n]),n}catch(e){throw Error(`Failed to insert log: ${e instanceof Error?e.message:String(e)}`)}}async insertBatch(e){try{if(e.length===0)return[];let t=this.getSqliteClient(),n=e.map(e=>this.prepareLogRecord(e));t.exec(`BEGIN`);try{let e=t.prepare(`
164
+ INSERT INTO logs (
165
+ id, timestamp, level, message, trace_id, span_id, parent_span_id,
166
+ service, hostname, pid, metadata, error_type, error_message,
167
+ error_stack, created_at
168
+ )
169
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
170
+ `);for(let t of n)e.run(t.id,Math.floor(t.timestamp.getTime()/1e3),t.level,t.message,t.traceId,t.spanId,t.parentSpanId,t.service,t.hostname,t.pid,t.metadata?JSON.stringify(t.metadata):null,t.errorType,t.errorMessage,t.errorStack,Math.floor(t.createdAt.getTime()/1e3));t.exec(`COMMIT`)}catch(e){throw t.exec(`ROLLBACK`),e}return await this.tryIndexEmbeddings(n),n}catch(e){throw Error(`Failed to insert batch: ${e instanceof Error?e.message:String(e)}`)}}async tryIndexEmbeddings(e){!this.embeddingWriter||e.length===0||this.embeddingWriter(e).catch(e=>{console.warn(`Failed to index semantic embeddings: ${e instanceof Error?e.message:String(e)}`)})}async queryLogs(e={}){try{let t=this.getSqliteClient(),n=`WHERE 1 = 1`,r=[];if(e.level){let t=Array.isArray(e.level)?e.level:[e.level];t.length===1?(n+=` AND level = ?`,r.push(t[0])):(n+=` AND level IN (${t.map(()=>`?`).join(`,`)})`,r.push(...t))}if(e.service){let t=Array.isArray(e.service)?e.service:[e.service];t.length===1?(n+=` AND service = ?`,r.push(t[0])):(n+=` AND service IN (${t.map(()=>`?`).join(`,`)})`,r.push(...t))}e.traceId&&(n+=` AND trace_id = ?`,r.push(e.traceId)),e.spanId&&(n+=` AND span_id = ?`,r.push(e.spanId)),e.errorType&&(n+=` AND error_type = ?`,r.push(e.errorType)),e.startTime&&(n+=` AND timestamp >= ?`,r.push(Math.floor(e.startTime.getTime()/1e3))),e.endTime&&(n+=` AND timestamp <= ?`,r.push(Math.floor(e.endTime.getTime()/1e3)));let i=e.limit??100,a=e.offset??0;return H(t.prepare(`
171
+ SELECT
172
+ id,
173
+ timestamp,
174
+ level,
175
+ message,
176
+ trace_id,
177
+ span_id,
178
+ parent_span_id,
179
+ service,
180
+ hostname,
181
+ pid,
182
+ metadata,
183
+ error_type,
184
+ error_message,
185
+ error_stack,
186
+ created_at
187
+ FROM logs
188
+ ${n}
189
+ ORDER BY timestamp DESC
190
+ LIMIT ?
191
+ OFFSET ?
192
+ `).all(...r,i,a)).map(e=>this.mapRow(e))}catch(e){throw Error(`Failed to query logs: ${e instanceof Error?e.message:String(e)}`)}}async deleteAllLogs(){try{let e=this.getSqliteClient().prepare(`DELETE FROM logs`).run();return Number(e.changes??0)}catch(e){throw Error(`Failed to delete all logs: ${e instanceof Error?e.message:String(e)}`)}}async disconnect(){this.sqlite&&(this.sqlite.close(),this.sqlite=null,this.databasePath=null,this.useInMemory=!1)}};U=w([u()],U);function W(e){return e}let G=class{constructor(e,t,n){this.storage=e,this.searchService=t,this.embeddings=n}async isAvailable(){return this.embeddings.isAvailable()}mapRow(e){let t=1/(1+e.distance);return{id:e.id,timestamp:new Date(e.timestamp*1e3),level:e.level,message:e.message,traceId:e.traceId,spanId:e.spanId,parentSpanId:e.parentSpanId,service:e.service,hostname:e.hostname,pid:e.pid,metadata:e.metadata?JSON.parse(e.metadata):null,errorType:e.errorType,errorMessage:e.errorMessage,errorStack:e.errorStack,createdAt:new Date(e.createdAt*1e3),distance:e.distance,score:t}}mapFallbackRow(e){return{...e,distance:1/0,score:1/(1+Math.max(0,Math.abs(e.rank)))}}buildFilterSql(e={}){let t=`WHERE 1 = 1`,n=[];if(e.service){let r=Array.isArray(e.service)?e.service:[e.service];t+=` AND logs.service IN (${r.map(()=>`?`).join(`,`)})`,n.push(...r)}if(e.level){let r=Array.isArray(e.level)?e.level:[e.level];t+=` AND logs.level IN (${r.map(()=>`?`).join(`,`)})`,n.push(...r)}return e.startTime&&(t+=` AND logs.timestamp >= ?`,n.push(Math.floor(e.startTime.getTime()/1e3))),e.endTime&&(t+=` AND logs.timestamp <= ?`,n.push(Math.floor(e.endTime.getTime()/1e3))),{whereSql:t,params:n}}async indexMissingLogs(e={},t=100){let n=this.storage.getSqliteClient(),r=0;for(;;){let{whereSql:i,params:a}=this.buildFilterSql(e),o=W(n.prepare(`
193
+ SELECT
194
+ logs.id as id,
195
+ logs.timestamp as timestamp,
196
+ logs.level as level,
197
+ logs.message as message,
198
+ logs.trace_id as traceId,
199
+ logs.span_id as spanId,
200
+ logs.parent_span_id as parentSpanId,
201
+ logs.service as service,
202
+ logs.hostname as hostname,
203
+ logs.pid as pid,
204
+ logs.metadata as metadata,
205
+ logs.error_type as errorType,
206
+ logs.error_message as errorMessage,
207
+ logs.error_stack as errorStack,
208
+ logs.created_at as createdAt
209
+ FROM logs
210
+ LEFT JOIN log_embeddings ON log_embeddings.log_id = logs.id
211
+ ${i}
212
+ AND log_embeddings.log_id IS NULL
213
+ ORDER BY logs.timestamp ASC
214
+ LIMIT ?
215
+ `).all(...a,t));if(o.length===0)return r;await this.embeddings.indexLogs(o.map(e=>({id:e.id,timestamp:new Date(e.timestamp*1e3),level:e.level,message:e.message,traceId:e.traceId,spanId:e.spanId,parentSpanId:e.parentSpanId,service:e.service,hostname:e.hostname,pid:e.pid,metadata:e.metadata?JSON.parse(e.metadata):null,errorType:e.errorType,errorMessage:e.errorMessage,errorStack:e.errorStack,createdAt:new Date(e.createdAt*1e3)}))),r+=o.length}}async searchLogs(e,t={},n=100){let{results:r}=await this.searchLogsPaginated(e,{...t,offset:0},n);return r}async searchLogsPaginated(e,t={},n=100){try{if(await this.storage.ensureInitialized(),!await this.embeddings.isAvailable()){let r=await this.searchService.searchLogsPaginated(e,t,n);return{results:r.results.map(e=>this.mapFallbackRow(e)),total:r.total}}await this.indexMissingLogs(t);let r=this.storage.getSqliteClient(),i=await this.embeddings.embedText(e),a=JSON.stringify(i),{whereSql:o,params:s}=this.buildFilterSql(t),c=t.offset??0,l=`
216
+ SELECT COUNT(*) as total
217
+ FROM log_embeddings
218
+ JOIN logs ON logs.id = log_embeddings.log_id
219
+ ${o}
220
+ `,u=`
221
+ SELECT
222
+ logs.id as id,
223
+ logs.timestamp as timestamp,
224
+ logs.level as level,
225
+ logs.message as message,
226
+ logs.trace_id as traceId,
227
+ logs.span_id as spanId,
228
+ logs.parent_span_id as parentSpanId,
229
+ logs.service as service,
230
+ logs.hostname as hostname,
231
+ logs.pid as pid,
232
+ logs.metadata as metadata,
233
+ logs.error_type as errorType,
234
+ logs.error_message as errorMessage,
235
+ logs.error_stack as errorStack,
236
+ logs.created_at as createdAt,
237
+ vec_distance_cosine(log_embeddings.embedding, vec_f32(?)) as distance
238
+ FROM log_embeddings
239
+ JOIN logs ON logs.id = log_embeddings.log_id
240
+ ${o}
241
+ ORDER BY distance ASC
242
+ LIMIT ?
243
+ OFFSET ?
244
+ `,d=r.prepare(l).get(...s);return{results:W(r.prepare(u).all(a,...s,n,c)).map(e=>this.mapRow(e)),total:Number(d.total??0)}}catch(r){let i=await this.searchService.searchLogsPaginated(e,t,n);return console.warn(`Semantic search unavailable, falling back to FTS: ${r instanceof Error?r.message:String(r)}`),{results:i.results.map(e=>this.mapFallbackRow(e)),total:i.total}}}};G=w([u(),O(0,l(E.LogStorageService)),O(1,l(E.LogSearchService)),O(2,l(E.EmbeddingService)),D(`design:paramtypes`,[Object,Object,Object])],G);const te=new c(e=>{e.bind(E.LogStorageService).to(U).inSingletonScope(),e.bind(E.EmbeddingService).to(I).inSingletonScope(),e.bind(E.LogQueryService).to(R).inSingletonScope(),e.bind(E.LogSearchService).to(V).inSingletonScope(),e.bind(E.SemanticSearchService).to(G).inSingletonScope(),e.bind(E.LogRetentionService).to(z).inSingletonScope(),e.bind(E.HttpServerHealthCheck).to(T).inSingletonScope(),e.bind(E.HttpServerManager).to(P).inSingletonScope()});function K(){let e=new s;e.load(te);let t=e.get(E.LogStorageService),n=e.get(E.EmbeddingService);return t.setEmbeddingWriter(e=>n.indexLogs(e)),e}var q=class e{static TOOL_NAME=`analyze_errors`;queryService;constructor(e){this.queryService=e.get(E.LogQueryService)}getDefinition(){return{name:e.TOOL_NAME,description:`Analyze error patterns and group similar errors by type and message. Calculates error frequencies, suggests root causes, and provides debugging insights.`,inputSchema:{type:`object`,properties:{timeRange:{type:`object`,properties:{start:{type:`string`,format:`date-time`,description:`Start time for error analysis (ISO 8601 format)`},end:{type:`string`,format:`date-time`,description:`End time for error analysis (ISO 8601 format)`}},description:`Optional time range to filter errors`},traceId:{type:`string`,description:`Optional trace ID to analyze errors within a specific trace`},limit:{type:`number`,minimum:1,maximum:1e3,default:100,description:`Maximum number of error entries to analyze`}},additionalProperties:!1}}}async execute(e){try{let t=e.limit??100,n;if(e.traceId)n=(await this.queryService.filterByTrace(e.traceId)).filter(e=>e.level===`error`||e.level===`fatal`).slice(0,t);else if(e.timeRange){let r=new Date(e.timeRange.start),i=new Date(e.timeRange.end);n=(await this.queryService.filterByTimeRange(r,i)).filter(e=>e.level===`error`||e.level===`fatal`).slice(0,t)}else n=await this.queryService.filterByLevel([`error`,`fatal`],t);let r=new Map;for(let e of n){let t=`${e.errorType}::${e.errorMessage}`;r.has(t)||r.set(t,{errorType:e.errorType,errorMessage:e.errorMessage,frequency:0,services:new Set,examples:[]});let n=r.get(t);n.frequency+=1,n.services.add(e.service),n.examples.length<3&&n.examples.push({id:e.id,timestamp:e.timestamp.toISOString(),service:e.service})}let i=Array.from(r.values()).sort((e,t)=>t.frequency-e.frequency).map(e=>({errorType:e.errorType,errorMessage:e.errorMessage,frequency:e.frequency,affectedServices:Array.from(e.services),examples:e.examples}));return{content:[{type:`text`,text:JSON.stringify({totalErrorsAnalyzed:n.length,uniqueErrorPatterns:i.length,analysis:i},null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error analyzing logs: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}},J=class e{static TOOL_NAME=`clear_logs`;retentionService;constructor(e){this.retentionService=e.get(E.LogRetentionService)}getDefinition(){return{name:e.TOOL_NAME,description:`Clear all logs from the database. Returns confirmation with count of deleted entries. Use with caution - this operation cannot be undone.`,inputSchema:{type:`object`,properties:{},additionalProperties:!1}}}async execute(e){try{let e=await this.retentionService.clearAllLogs();return{content:[{type:`text`,text:JSON.stringify({success:!0,message:`All logs have been cleared`,deletedEntries:e},null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error clearing logs: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}},Y=class e{static TOOL_NAME=`get_log_stats`;queryService;constructor(e){this.queryService=e.get(E.LogQueryService)}getDefinition(){return{name:e.TOOL_NAME,description:`Get aggregated log statistics grouped by level, service, or time period. Returns counts, distributions, and trends for log analysis.`,inputSchema:{type:`object`,properties:{startTime:{type:`string`,format:`date-time`,description:`Start time for statistics (ISO 8601 format)`},endTime:{type:`string`,format:`date-time`,description:`End time for statistics (ISO 8601 format)`},groupBy:{type:`string`,enum:[`level`,`service`,`both`],default:`both`,description:`Group statistics by 'level', 'service', or 'both'`}},additionalProperties:!1}}}async execute(e){try{let t;(e.startTime||e.endTime)&&(t={start:e.startTime?new Date(e.startTime):new Date(0),end:e.endTime?new Date(e.endTime):new Date});let n=e.groupBy??`both`,r=await this.queryService.getStatistics(t,n);return{content:[{type:`text`,text:JSON.stringify({timeRange:t,groupBy:n,totalEntries:r.reduce((e,t)=>e+t.count,0),statistics:r.map(e=>({service:e.service,level:e.level,count:e.count}))},null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error getting statistics: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}},X=class e{static TOOL_NAME=`get_services`;queryService;constructor(e){this.queryService=e.get(E.LogQueryService)}getDefinition(){return{name:e.TOOL_NAME,description:`Get list of all unique services that have logged entries. Useful for discovering available services in the system.`,inputSchema:{type:`object`,properties:{},additionalProperties:!1}}}async execute(e){try{let e=await this.queryService.getActiveServices();return{content:[{type:`text`,text:JSON.stringify({count:e.length,services:e.sort()},null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error getting services: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}},Z=class e{static TOOL_NAME=`get_trace_timeline`;queryService;constructor(e){this.queryService=e.get(E.LogQueryService)}getDefinition(){return{name:e.TOOL_NAME,description:`Get complete trace timeline for a given trace ID, showing all log entries ordered by timestamp with span hierarchy visualization. Returns chronological sequence of events across services.`,inputSchema:{type:`object`,properties:{traceId:{type:`string`,description:`OTEL trace ID (32 hex characters)`}},required:[`traceId`],additionalProperties:!1}}}async execute(e){try{let t=await this.queryService.getTraceTimeline(e.traceId);return{content:[{type:`text`,text:JSON.stringify({traceId:e.traceId,count:t.length,timeline:t.map(e=>({timestamp:e.timestamp.toISOString(),service:e.service,spanId:e.spanId,parentSpanId:e.parentSpanId,level:e.level,message:e.message,duration:e.duration}))},null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error getting trace timeline: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}},Q=class e{static TOOL_NAME=`query_logs`;queryService;constructor(e){this.queryService=e.get(E.LogQueryService)}getDefinition(){return{name:e.TOOL_NAME,description:`Query and filter log entries by level, trace ID, time range, service, or other criteria. Returns filtered log entries with full metadata.`,inputSchema:{type:`object`,properties:{level:{oneOf:[{type:`string`,enum:[`trace`,`debug`,`info`,`warn`,`error`,`fatal`]},{type:`array`,items:{type:`string`,enum:[`trace`,`debug`,`info`,`warn`,`error`,`fatal`]}}],description:`Log level(s) to filter by`},traceId:{type:`string`,description:`Trace ID to filter by (OTEL format: 32 hex characters)`},service:{oneOf:[{type:`string`},{type:`array`,items:{type:`string`}}],description:`Service name(s) to filter by`},startTime:{type:`string`,format:`date-time`,description:`Start time for log range (ISO 8601 format)`},endTime:{type:`string`,format:`date-time`,description:`End time for log range (ISO 8601 format)`},limit:{type:`number`,minimum:1,maximum:1e3,default:100,description:`Maximum number of log entries to return`}},additionalProperties:!1}}}async execute(e){try{let t=e.limit??100,n;if(e.traceId)n=await this.queryService.filterByTrace(e.traceId),n=n.slice(0,t);else if(e.level)n=await this.queryService.filterByLevel(e.level,t);else if(e.service)n=await this.queryService.filterByService(e.service),n=n.slice(0,t);else if(e.startTime||e.endTime){let r=e.startTime?new Date(e.startTime):new Date(0),i=e.endTime?new Date(e.endTime):new Date;n=await this.queryService.filterByTimeRange(r,i),n=n.slice(0,t)}else n=await this.queryService.filterByLevel([`info`,`warn`,`error`,`fatal`],t);return{content:[{type:`text`,text:JSON.stringify({count:n.length,logs:n.map(e=>({id:e.id,timestamp:e.timestamp.toISOString(),level:e.level,message:e.message,service:e.service,traceId:e.traceId,spanId:e.spanId,parentSpanId:e.parentSpanId,hostname:e.hostname,pid:e.pid,metadata:e.metadata,errorType:e.errorType,errorMessage:e.errorMessage,errorStack:e.errorStack}))},null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error querying logs: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}},$=class e{static TOOL_NAME=`search_logs`;searchService;semanticSearchService;constructor(e){this.searchService=e.get(E.LogSearchService),this.semanticSearchService=e.get(E.SemanticSearchService)}getDefinition(){return{name:e.TOOL_NAME,description:`Search log entries using FTS5, local semantic embeddings, or both. Hybrid mode combines exact text and semantic similarity for better incident retrieval.`,inputSchema:{type:`object`,properties:{searchQuery:{type:`string`,description:`FTS5 search query (supports phrase queries with quotes, prefix matching with *, boolean operators AND/OR/NOT)`},mode:{type:`string`,enum:[`fts`,`semantic`,`hybrid`],default:`hybrid`,description:`Search strategy to use`},service:{oneOf:[{type:`string`},{type:`array`,items:{type:`string`}}],description:`Service name(s) to filter by`},level:{oneOf:[{type:`string`,enum:[`trace`,`debug`,`info`,`warn`,`error`,`fatal`]},{type:`array`,items:{type:`string`,enum:[`trace`,`debug`,`info`,`warn`,`error`,`fatal`]}}],description:`Log level(s) to filter by`},startTime:{type:`string`,format:`date-time`,description:`Start time for log range (ISO 8601 format)`},endTime:{type:`string`,format:`date-time`,description:`End time for log range (ISO 8601 format)`},limit:{type:`number`,minimum:1,maximum:1e3,default:100,description:`Maximum number of search results to return`}},required:[`searchQuery`],additionalProperties:!1}}}async execute(e){try{let t={},n=e.mode??`hybrid`;e.service&&(t.service=e.service),e.level&&(t.level=e.level),e.startTime&&(t.startTime=new Date(e.startTime)),e.endTime&&(t.endTime=new Date(e.endTime));let r=e.limit??100,i=n===`semantic`?await this.semanticSearchService.searchLogs(e.searchQuery,t,r):n===`fts`?await this.searchService.searchLogs(e.searchQuery,t,r):await this.searchHybrid(e.searchQuery,t,r);return{content:[{type:`text`,text:JSON.stringify({mode:n,count:i.length,query:e.searchQuery,results:i.map(e=>({score:`score`in e?e.score:this.getFallbackScore(e.rank),rank:`rank`in e?e.rank:void 0,distance:`distance`in e?e.distance:void 0,sources:`sources`in e?e.sources:void 0,id:e.id,timestamp:e.timestamp.toISOString(),level:e.level,message:e.message,service:e.service,traceId:e.traceId,spanId:e.spanId,parentSpanId:e.parentSpanId,hostname:e.hostname,pid:e.pid,metadata:e.metadata,errorType:e.errorType,errorMessage:e.errorMessage}))},null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error searching logs: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}getFallbackScore(e){return 1/(1+Math.max(0,Math.abs(e)))}async searchHybrid(e,t,n){let r=Math.max(n*2,50),i=this.searchService.searchLogs(e,t,r),a=await this.semanticSearchService.isAvailable(),o=await i;if(!a)return o;let s=await this.semanticSearchService.searchLogs(e,t,r),c=new Map;return o.forEach((e,t)=>{c.set(e.id,{result:e,score:.65*(1/(1+t)),rank:e.rank,sources:new Set([`fts`])})}),s.forEach((e,t)=>{let n=c.get(e.id),r=.35*(1/(1+t));n?(n.score+=r,n.sources.add(`semantic`),n.distance=e.distance,n.rank===void 0&&`rank`in e&&(n.rank=e.rank),n.result={...n.result,...e}):c.set(e.id,{result:e,score:r,distance:e.distance,sources:new Set([`semantic`])})}),Array.from(c.values()).sort((e,t)=>t.score-e.score).slice(0,n).map(e=>({...e.result,score:e.score,sources:Array.from(e.sources),rank:e.rank,distance:e.distance}))}};function ne(e){let t=new b({name:`log-sink-mcp`,version:`0.1.0`},{capabilities:{tools:{}}}),n=e??K(),r=new Q(n),i=new $(n),a=new Z(n),o=new q(n),s=new Y(n),c=new X(n),l=new J(n);return t.setRequestHandler(S,async()=>({tools:[r.getDefinition(),i.getDefinition(),a.getDefinition(),o.getDefinition(),s.getDefinition(),c.getDefinition(),l.getDefinition()]})),t.setRequestHandler(x,async e=>{let{name:t,arguments:n}=e.params;try{switch(t){case`query_logs`:return await r.execute(n);case`search_logs`:return await i.execute(n);case`get_trace_timeline`:return await a.execute(n);case`analyze_errors`:return await o.execute(n);case`get_log_stats`:return await s.execute(n);case`get_services`:return await c.execute(n);case`clear_logs`:return await l.execute(n);default:throw Error(`Unknown tool: ${t}`)}}catch(e){return{content:[{type:`text`,text:`Error executing tool ${t}: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}}),t}var re=class{server;transport=null;constructor(e){this.server=e}async start(){this.transport=new C,await this.server.connect(this.transport)}async stop(){this.transport&&=(await this.transport.close(),null)}};export{Z as a,J as c,E as d,Q as i,q as l,ne as n,X as o,$ as r,Y as s,re as t,K as u};
245
+ //# sourceMappingURL=stdio-DXi11KM4.mjs.map