@agimon-ai/log-sink-mcp 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +47 -362
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +47 -47
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/node-B4WmY501.cjs +2 -0
- package/dist/node-B4WmY501.cjs.map +1 -0
- package/dist/{node-Bu3xSfYZ.mjs → node-BFbuDeng.mjs} +2 -2
- package/dist/node-BFbuDeng.mjs.map +1 -0
- package/dist/stdio-Cfkj76pe.cjs +264 -0
- package/dist/stdio-Cfkj76pe.cjs.map +1 -0
- package/dist/stdio-WJN_EbJO.mjs +264 -0
- package/dist/stdio-WJN_EbJO.mjs.map +1 -0
- package/dist/telemetry/node.cjs +1 -1
- package/dist/telemetry/node.mjs +1 -1
- package/package.json +27 -26
- package/dist/node-Bu3xSfYZ.mjs.map +0 -1
- package/dist/node-fq51Liy5.cjs +0 -2
- package/dist/node-fq51Liy5.cjs.map +0 -1
- package/dist/stdio-mBddGYtL.mjs +0 -264
- package/dist/stdio-mBddGYtL.mjs.map +0 -1
- package/dist/stdio-mMKO_6bH.cjs +0 -264
- package/dist/stdio-mMKO_6bH.cjs.map +0 -1
- /package/dist/{chunk-DjWAcSYV.cjs → chunk-Bmb41Sf3.cjs} +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -1,320 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const e=require(`./chunk-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
padding: 1.5rem;
|
|
30
|
-
margin-bottom: 1.5rem;
|
|
31
|
-
border-radius: 8px;
|
|
32
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.controls-section {
|
|
36
|
-
background-color: #fff;
|
|
37
|
-
padding: 1rem;
|
|
38
|
-
margin-bottom: 1rem;
|
|
39
|
-
border-radius: 8px;
|
|
40
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
41
|
-
display: flex;
|
|
42
|
-
gap: 1rem;
|
|
43
|
-
align-items: center;
|
|
44
|
-
flex-wrap: wrap;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.input-field {
|
|
48
|
-
padding: 0.5rem 0.75rem;
|
|
49
|
-
border: 1px solid #ddd;
|
|
50
|
-
border-radius: 4px;
|
|
51
|
-
font-size: 14px;
|
|
52
|
-
flex: 1;
|
|
53
|
-
min-width: 200px;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.input-field:focus {
|
|
57
|
-
outline: none;
|
|
58
|
-
border-color: #2196f3;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.select-field {
|
|
62
|
-
padding: 0.5rem 0.75rem;
|
|
63
|
-
border: 1px solid #ddd;
|
|
64
|
-
border-radius: 4px;
|
|
65
|
-
font-size: 14px;
|
|
66
|
-
background-color: #fff;
|
|
67
|
-
cursor: pointer;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.select-field:focus {
|
|
71
|
-
outline: none;
|
|
72
|
-
border-color: #2196f3;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.btn {
|
|
76
|
-
padding: 0.5rem 1rem;
|
|
77
|
-
border: none;
|
|
78
|
-
border-radius: 4px;
|
|
79
|
-
font-size: 14px;
|
|
80
|
-
cursor: pointer;
|
|
81
|
-
background-color: #2196f3;
|
|
82
|
-
color: white;
|
|
83
|
-
transition: background-color 0.2s;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.btn:hover {
|
|
87
|
-
background-color: #1976d2;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.btn:disabled {
|
|
91
|
-
background-color: #ccc;
|
|
92
|
-
cursor: not-allowed;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.table-container {
|
|
96
|
-
background-color: #fff;
|
|
97
|
-
border-radius: 8px;
|
|
98
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
99
|
-
overflow: hidden;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.log-table {
|
|
103
|
-
width: 100%;
|
|
104
|
-
border-collapse: collapse;
|
|
105
|
-
table-layout: fixed;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
.log-table th {
|
|
109
|
-
background-color: #f8f9fa;
|
|
110
|
-
padding: 0.75rem;
|
|
111
|
-
text-align: left;
|
|
112
|
-
font-weight: 600;
|
|
113
|
-
border-bottom: 2px solid #dee2e6;
|
|
114
|
-
position: sticky;
|
|
115
|
-
top: 0;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.log-table th:nth-child(1) {
|
|
119
|
-
width: 18%;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.log-table th:nth-child(2) {
|
|
123
|
-
width: 10%;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.log-table th:nth-child(3) {
|
|
127
|
-
width: 22%;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.log-table th:nth-child(4) {
|
|
131
|
-
width: 50%;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
.log-table td {
|
|
135
|
-
padding: 0.75rem;
|
|
136
|
-
border-bottom: 1px solid #dee2e6;
|
|
137
|
-
vertical-align: top;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.log-table tr:hover {
|
|
141
|
-
background-color: #f8f9fa;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
.level-trace {
|
|
145
|
-
color: #9e9e9e;
|
|
146
|
-
font-weight: 600;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
.level-debug {
|
|
150
|
-
color: #2196f3;
|
|
151
|
-
font-weight: 600;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.level-info {
|
|
155
|
-
color: #4caf50;
|
|
156
|
-
font-weight: 600;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.level-warn {
|
|
160
|
-
color: #ff9800;
|
|
161
|
-
font-weight: 600;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
.level-error {
|
|
165
|
-
color: #f44336;
|
|
166
|
-
font-weight: 600;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
.level-fatal {
|
|
170
|
-
color: #d32f2f;
|
|
171
|
-
font-weight: 600;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
.stats-container {
|
|
175
|
-
display: flex;
|
|
176
|
-
gap: 1.5rem;
|
|
177
|
-
margin-bottom: 1rem;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.stat-card {
|
|
181
|
-
background-color: #fff;
|
|
182
|
-
padding: 1rem;
|
|
183
|
-
border-radius: 8px;
|
|
184
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
185
|
-
flex: 1;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.stat-card h3 {
|
|
189
|
-
font-size: 0.875rem;
|
|
190
|
-
color: #666;
|
|
191
|
-
margin-bottom: 0.5rem;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
.stat-card .value {
|
|
195
|
-
font-size: 1.5rem;
|
|
196
|
-
font-weight: 700;
|
|
197
|
-
color: #333;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
.trace-link {
|
|
201
|
-
color: #2196f3;
|
|
202
|
-
text-decoration: underline;
|
|
203
|
-
cursor: pointer;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
.trace-link:hover {
|
|
207
|
-
color: #1976d2;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
.message-cell {
|
|
211
|
-
max-width: 600px;
|
|
212
|
-
word-wrap: break-word;
|
|
213
|
-
white-space: pre-wrap;
|
|
214
|
-
font-family: 'Courier New', monospace;
|
|
215
|
-
font-size: 13px;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
.timestamp-cell {
|
|
219
|
-
white-space: nowrap;
|
|
220
|
-
font-size: 12px;
|
|
221
|
-
color: #666;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.service-cell {
|
|
225
|
-
font-weight: 500;
|
|
226
|
-
color: #555;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/* Pagination styles */
|
|
230
|
-
.pagination-container {
|
|
231
|
-
display: flex;
|
|
232
|
-
justify-content: center;
|
|
233
|
-
align-items: center;
|
|
234
|
-
gap: 1rem;
|
|
235
|
-
padding: 1rem;
|
|
236
|
-
background-color: #f8f9fa;
|
|
237
|
-
border-top: 1px solid #dee2e6;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
.pagination-btn {
|
|
241
|
-
padding: 0.5rem 1rem;
|
|
242
|
-
border: 1px solid #ddd;
|
|
243
|
-
border-radius: 4px;
|
|
244
|
-
font-size: 14px;
|
|
245
|
-
cursor: pointer;
|
|
246
|
-
background-color: #fff;
|
|
247
|
-
color: #333;
|
|
248
|
-
transition: background-color 0.2s, border-color 0.2s;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
.pagination-btn:hover:not(:disabled) {
|
|
252
|
-
background-color: #e9ecef;
|
|
253
|
-
border-color: #adb5bd;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
.pagination-btn:disabled {
|
|
257
|
-
background-color: #f8f9fa;
|
|
258
|
-
color: #adb5bd;
|
|
259
|
-
cursor: not-allowed;
|
|
260
|
-
border-color: #dee2e6;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
.page-info {
|
|
264
|
-
font-size: 14px;
|
|
265
|
-
color: #666;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/* Two-row log entry styles */
|
|
269
|
-
.log-entry-group {
|
|
270
|
-
border-bottom: 2px solid #dee2e6;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
.log-entry-group:last-child {
|
|
274
|
-
border-bottom: none;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
.metadata-row td {
|
|
278
|
-
padding: 0.5rem 0.75rem;
|
|
279
|
-
padding-bottom: 0.25rem;
|
|
280
|
-
border-bottom: none;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
.message-row td {
|
|
284
|
-
padding: 0.25rem 0.75rem;
|
|
285
|
-
padding-bottom: 0.75rem;
|
|
286
|
-
border-bottom: none;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
.message-full-cell {
|
|
290
|
-
font-family: 'Courier New', monospace;
|
|
291
|
-
font-size: 13px;
|
|
292
|
-
white-space: pre-wrap;
|
|
293
|
-
word-wrap: break-word;
|
|
294
|
-
background-color: #f8f9fa;
|
|
295
|
-
padding: 0.5rem 0.75rem;
|
|
296
|
-
border-radius: 4px;
|
|
297
|
-
color: #333;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
.attributes-row td {
|
|
301
|
-
padding: 0.25rem 0.75rem;
|
|
302
|
-
padding-bottom: 0.75rem;
|
|
303
|
-
border-bottom: none;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
.attributes-cell {
|
|
307
|
-
font-family: 'Courier New', monospace;
|
|
308
|
-
font-size: 12px;
|
|
309
|
-
white-space: pre-wrap;
|
|
310
|
-
word-wrap: break-word;
|
|
311
|
-
background-color: #e8f4fc;
|
|
312
|
-
padding: 0.5rem 0.75rem;
|
|
313
|
-
border-radius: 4px;
|
|
314
|
-
color: #555;
|
|
315
|
-
margin-top: 0.25rem;
|
|
316
|
-
}
|
|
317
|
-
`;function fe(e){let t=e.toLowerCase();return t===`trace`?C:t===`debug`?w:t===`info`?T:t===`warn`?E:t===`error`?D:t===`fatal`?O:``}function pe(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 me({logs:e}){return(0,h.jsx)(`div`,{class:`table-container`,children:(0,h.jsxs)(`table`,{class:S,children:[(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{children:[(0,h.jsx)(`th`,{children:`Timestamp`}),(0,h.jsx)(`th`,{children:`Level`}),(0,h.jsx)(`th`,{children:`Service`}),(0,h.jsx)(`th`,{children:`Trace ID`})]})}),e.map(e=>{let t=pe(e.metadata);return(0,h.jsxs)(`tbody`,{class:j,children:[(0,h.jsxs)(`tr`,{class:M,children:[(0,h.jsx)(`td`,{class:oe,children:y(e.timestamp)}),(0,h.jsx)(`td`,{class:fe(e.level),children:e.level.toUpperCase()}),(0,h.jsx)(`td`,{class:se,children:e.service}),(0,h.jsx)(`td`,{children:e.traceId?(0,h.jsxs)(`span`,{class:A,onclick:`dashboard.filterByTrace('${e.traceId}')`,children:[e.traceId.slice(0,8),`...`]}):(0,h.jsx)(`span`,{children:`-`})})]}),(0,h.jsx)(`tr`,{class:N,children:(0,h.jsxs)(`td`,{colspan:4,class:P,children:[(0,h.jsx)(`div`,{children:e.message}),t&&(0,h.jsx)(`pre`,{class:F,children:JSON.stringify(t,null,2)})]})})]},e.id)})]})})}function he(){return(0,h.jsx)(`input`,{id:`search-input`,type:`text`,class:`input-field`,placeholder:`Search logs...`,oninput:`dashboard.handleSearchInput(event)`})}function ge({services:e}){return(0,h.jsxs)(`select`,{id:`service-select`,class:`select-field`,onchange:`dashboard.handleServiceChange(event)`,children:[(0,h.jsx)(`option`,{value:``,children:`All Services`}),e.map(e=>(0,h.jsx)(`option`,{value:e,children:e},e))]})}function _e({stats:e}){return(0,h.jsxs)(`div`,{class:`stats-container`,children:[(0,h.jsxs)(`div`,{class:k,children:[(0,h.jsx)(`h3`,{children:`Total Logs`}),(0,h.jsx)(`div`,{class:`value`,children:e.totalLogs.toLocaleString()})]}),(0,h.jsxs)(`div`,{class:k,children:[(0,h.jsx)(`h3`,{children:`Errors`}),(0,h.jsx)(`div`,{class:`value`,children:e.errors.toLocaleString()})]}),(0,h.jsxs)(`div`,{class:k,children:[(0,h.jsx)(`h3`,{children:`Services`}),(0,h.jsx)(`div`,{class:`value`,children:e.services})]})]})}function ve({initialLogs:e,services:t,stats:n}){return(0,h.jsxs)(`div`,{class:`dashboard-container`,children:[(0,h.jsxs)(`div`,{class:`dashboard-header`,children:[(0,h.jsx)(`h1`,{children:`Log Dashboard`}),(0,h.jsx)(`p`,{children:`Real-time log streaming with auto-refresh (3 seconds)`})]}),(0,h.jsx)(_e,{stats:n}),(0,h.jsxs)(`div`,{class:`controls-section`,children:[(0,h.jsx)(he,{}),(0,h.jsx)(ge,{services:t}),(0,h.jsx)(`button`,{id:`refresh-btn`,class:`btn`,onclick:`dashboard.manualRefresh()`,children:`Refresh Now`})]}),(0,h.jsx)(me,{logs:e}),(0,h.jsxs)(`div`,{id:`pagination-controls`,class:`pagination-container`,children:[(0,h.jsx)(`button`,{id:`prev-btn`,class:le,onclick:`dashboard.prevPage()`,disabled:!0,children:`Previous`}),(0,h.jsx)(`span`,{id:`page-info`,class:`page-info`,children:`Page 1`}),(0,h.jsx)(`button`,{id:`next-btn`,class:le,onclick:`dashboard.nextPage()`,children:`Next`})]}),(0,h.jsx)(`script`,{children:(0,m.raw)(`
|
|
2
|
+
const e=require(`./chunk-Bmb41Sf3.cjs`),t=require(`./stdio-Cfkj76pe.cjs`);let n=require(`zod`),r=require(`node:fs`),i=require(`node:fs/promises`);i=e.t(i);let a=require(`node:path`),o=require(`node:url`),s=require(`@agimon-ai/foundation-port-registry`),c=require(`@agimon-ai/foundation-process-registry`),l=require(`commander`),u=require(`@hono/node-server`),d=require(`hono`),f=require(`hono-rate-limiter`),p=require(`hono/cors`),m=require(`hono/html`),h=require(`hono/jsx/jsx-runtime`),g=function(e){return e.TRACE=`trace`,e.DEBUG=`debug`,e.INFO=`info`,e.WARN=`warn`,e.ERROR=`error`,e.FATAL=`fatal`,e}({});const _=[g.ERROR,g.FATAL];function v(e){let t=e.trim();if(!t)return null;try{return JSON.parse(t)}catch{return null}}function y(e){if(e==null)return`unknown`;if(typeof e==`string`)return e;try{return JSON.stringify(e,null,2)}catch{return String(e)}}function b(e){return e.hook_event_name===`PostToolUseFailure`?`Current tool failure:\n- Tool: ${e.tool_name??`unknown tool`}\n- Error: ${y(e.error)}`:null}function x(e,t,n){let r=new Map;for(let t of e){let e=`${t.service}::${t.level}::${t.error_type??``}::${t.error_message??t.message}`,i=new Date(Number(t.created_at)*1e3).toISOString();r.has(e)||r.set(e,{key:e,count:0,service:t.service,level:t.level,errorType:t.error_type,errorMessage:t.error_message,message:t.message,firstSeen:i,lastSeen:i,traceIds:new Set,examples:[]});let a=r.get(e);a.count+=1,a.lastSeen=i,t.trace_id&&a.traceIds.add(t.trace_id),a.examples.length<n&&a.examples.push({id:t.id,timestamp:i,traceId:t.trace_id})}return Array.from(r.values()).sort((e,t)=>t.count-e.count||t.lastSeen.localeCompare(e.lastSeen)).slice(0,t)}function ee(e,t,n,r){let i=x(e,n,r),a=[];a.push(`Recent log errors (${e.length} new):`),t.tool_name&&a.push(`- Triggered after tool: ${t.tool_name}`);for(let[e,t]of i.entries()){a.push(`${e+1}. ${t.service} [${t.level}] x${t.count} ${t.errorType?`(${t.errorType}) `:``}${t.errorMessage??t.message}`),a.push(` First seen: ${t.firstSeen}`),a.push(` Last seen: ${t.lastSeen}`),t.traceIds.size>0&&a.push(` Trace IDs: ${Array.from(t.traceIds).slice(0,3).join(`, `)}`);for(let e of t.examples)a.push(` Example: ${e.timestamp} id=${e.id}${e.traceId?` trace=${e.traceId}`:``}`)}if(t.hook_event_name===`PostToolUseFailure`){let e=b(t);e&&a.push(``,e)}return a.join(`
|
|
3
|
+
`)}function S(e){if(e.session_id?.trim())return(0,s.normalizeRepositoryPath)(t.p(e.cwd?.trim()||process.cwd()))}async function te(e,n){if(n.dbPath)return(0,r.existsSync)(n.dbPath)?n.dbPath:void 0;let i=process.env,a=S(e);if(!a)return;let o=new s.PortRegistryService(i.PORT_REGISTRY_PATH??s.DEFAULT_REGISTRY_PATH);try{let e=await o.getPort({repositoryPath:a,serviceName:`log-sink-mcp-http`,serviceType:`tool`,environment:i.NODE_ENV||`development`}),t=e.record?.metadata?.dbPath;if(e.success&&typeof t==`string`&&t&&(0,r.existsSync)(t))return t}catch{}let c=t.f(e.cwd??process.cwd());return(0,r.existsSync)(c)?c:void 0}async function ne(e,t,n,r,i){let a=e.getSqliteClient(),o=Math.floor((Date.now()-n*60*1e3)/1e3),s=``;if(t){let e=a.prepare(`
|
|
4
|
+
SELECT id, created_at
|
|
5
|
+
FROM logs
|
|
6
|
+
WHERE id = ?
|
|
7
|
+
LIMIT 1
|
|
8
|
+
`).all(t)[0];e&&(o=Number(e.created_at),s=e.id)}let c=a.prepare(`
|
|
9
|
+
SELECT
|
|
10
|
+
id,
|
|
11
|
+
created_at,
|
|
12
|
+
level,
|
|
13
|
+
message,
|
|
14
|
+
service,
|
|
15
|
+
trace_id,
|
|
16
|
+
span_id,
|
|
17
|
+
parent_span_id,
|
|
18
|
+
error_type,
|
|
19
|
+
error_message
|
|
20
|
+
FROM logs
|
|
21
|
+
WHERE level IN (?, ?)
|
|
22
|
+
AND (
|
|
23
|
+
created_at > ?
|
|
24
|
+
OR (created_at = ? AND id > ?)
|
|
25
|
+
)
|
|
26
|
+
ORDER BY created_at ASC, id ASC
|
|
27
|
+
LIMIT ?
|
|
28
|
+
`).all(..._,o,o,s,Math.max(r*i*2,r*3));return c.length===0?{rows:[]}:{rows:c,nextCheckpoint:c[c.length-1]}}async function re(e,n={}){let r=S(e),i=e.session_id?.trim();if(!r||!i)return null;let a=await te(e,n);if(!a)return null;let o=new t.d;try{await o.initializeDatabase(a);let{rows:t,nextCheckpoint:s}=await ne(o,await o.getHookCheckpoint(i,r),n.lookbackMinutes??10,n.maxGroups??5,n.maxExamplesPerGroup??3),c=b(e);if(t.length===0)return c?{hookSpecificOutput:{hookEventName:e.hook_event_name??`PostToolUse`,additionalContext:c}}:null;let l=ee(t,e,n.maxGroups??5,n.maxExamplesPerGroup??3);return await o.setHookCheckpoint(i,r,s?.id??t[t.length-1].id),{hookSpecificOutput:{hookEventName:e.hook_event_name??`PostToolUse`,additionalContext:c?`${l}\n\n${c}`:l}}}finally{await o.disconnect().catch(()=>void 0)}}const ie=new l.Command(`claude-hook`).alias(`hook`).description(`Emit additional Claude Code context from recent log errors`).option(`--db-path <path>`,`Path to the SQLite database file`).option(`--lookback-minutes <minutes>`,`Initial monitoring window in minutes`,`10`).option(`--max-groups <count>`,`Maximum number of grouped errors to include`,`5`).option(`--max-examples-per-group <count>`,`Maximum number of example errors to include per group`,`3`).action(async e=>{try{let t=v((0,r.readFileSync)(0,`utf-8`));t||process.exit(0);let n=await re(t,{dbPath:e.dbPath,lookbackMinutes:e.lookbackMinutes?Number.parseInt(e.lookbackMinutes,10):10,maxGroups:e.maxGroups?Number.parseInt(e.maxGroups,10):5,maxExamplesPerGroup:e.maxExamplesPerGroup?Number.parseInt(e.maxExamplesPerGroup,10):3});n||process.exit(0),process.stdout.write(`${JSON.stringify(n)}\n`),process.exit(0)}catch(e){process.stderr.write(`Error running Claude hook: ${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}}),ae=n.z.object({service:n.z.string().optional(),level:n.z.string().optional(),traceId:n.z.string().optional(),search:n.z.string().optional(),limit:n.z.coerce.number().min(1).max(1e3).default(25),offset:n.z.coerce.number().min(0).default(0)});function oe(e){let n=new d.Hono,r=e.get(t.m.LogQueryService),i=e.get(t.m.LogSearchService);return n.get(`/logs`,async e=>{try{let{service:t,level:n,traceId:a,search:o,limit:s,offset:c}=ae.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(`,`):[g.INFO,g.WARN,g.ERROR,g.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 se(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 C=`log-table`,w=`level-trace`,T=`level-debug`,E=`level-info`,D=`level-warn`,O=`level-error`,k=`level-fatal`,A=`stat-card`,j=`trace-link`,M=`timestamp-cell`,N=`service-cell`,P=`pagination-btn`,F=`log-entry-group`,ce=`metadata-row`,I=`message-row`,L=`message-full-cell`;function le(e){let t=e.toLowerCase();return t===`trace`?w:t===`debug`?T:t===`info`?E:t===`warn`?D:t===`error`?O:t===`fatal`?k:``}function ue(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 de({logs:e}){return(0,h.jsx)(`div`,{class:`table-container`,children:(0,h.jsxs)(`table`,{class:C,children:[(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{children:[(0,h.jsx)(`th`,{children:`Timestamp`}),(0,h.jsx)(`th`,{children:`Level`}),(0,h.jsx)(`th`,{children:`Service`}),(0,h.jsx)(`th`,{children:`Trace ID`})]})}),e.map(e=>{let t=ue(e.metadata);return(0,h.jsxs)(`tbody`,{class:F,children:[(0,h.jsxs)(`tr`,{class:ce,children:[(0,h.jsx)(`td`,{class:M,children:se(e.timestamp)}),(0,h.jsx)(`td`,{class:le(e.level),children:e.level.toUpperCase()}),(0,h.jsx)(`td`,{class:N,children:e.service}),(0,h.jsx)(`td`,{children:e.traceId?(0,h.jsxs)(`span`,{class:j,onclick:`dashboard.filterByTrace('${e.traceId}')`,children:[e.traceId.slice(0,8),`...`]}):(0,h.jsx)(`span`,{children:`-`})})]}),(0,h.jsx)(`tr`,{class:I,children:(0,h.jsxs)(`td`,{colspan:4,class:L,children:[(0,h.jsx)(`div`,{children:e.message}),t&&(0,h.jsx)(`pre`,{class:`attributes-cell`,children:JSON.stringify(t,null,2)})]})})]},e.id)})]})})}function fe(){return(0,h.jsx)(`input`,{id:`search-input`,type:`text`,class:`input-field`,placeholder:`Search logs...`,oninput:`dashboard.handleSearchInput(event)`})}function pe({services:e}){return(0,h.jsxs)(`select`,{id:`service-select`,class:`select-field`,onchange:`dashboard.handleServiceChange(event)`,children:[(0,h.jsx)(`option`,{value:``,children:`All Services`}),e.map(e=>(0,h.jsx)(`option`,{value:e,children:e},e))]})}function me({stats:e}){return(0,h.jsxs)(`div`,{class:`stats-container`,children:[(0,h.jsxs)(`div`,{class:A,children:[(0,h.jsx)(`h3`,{children:`Total Logs`}),(0,h.jsx)(`div`,{class:`value`,children:e.totalLogs.toLocaleString()})]}),(0,h.jsxs)(`div`,{class:A,children:[(0,h.jsx)(`h3`,{children:`Errors`}),(0,h.jsx)(`div`,{class:`value`,children:e.errors.toLocaleString()})]}),(0,h.jsxs)(`div`,{class:A,children:[(0,h.jsx)(`h3`,{children:`Services`}),(0,h.jsx)(`div`,{class:`value`,children:e.services})]})]})}function he({initialLogs:e,services:t,stats:n}){return(0,h.jsxs)(`div`,{class:`dashboard-container`,children:[(0,h.jsxs)(`div`,{class:`dashboard-header`,children:[(0,h.jsx)(`h1`,{children:`Log Dashboard`}),(0,h.jsx)(`p`,{children:`Real-time log streaming with auto-refresh (3 seconds)`})]}),(0,h.jsx)(me,{stats:n}),(0,h.jsxs)(`div`,{class:`controls-section`,children:[(0,h.jsx)(fe,{}),(0,h.jsx)(pe,{services:t}),(0,h.jsx)(`button`,{type:`button`,id:`refresh-btn`,class:`btn`,onclick:`dashboard.manualRefresh()`,children:`Refresh Now`})]}),(0,h.jsx)(de,{logs:e}),(0,h.jsxs)(`div`,{id:`pagination-controls`,class:`pagination-container`,children:[(0,h.jsx)(`button`,{type:`button`,id:`prev-btn`,class:P,onclick:`dashboard.prevPage()`,disabled:!0,children:`Previous`}),(0,h.jsx)(`span`,{id:`page-info`,class:`page-info`,children:`Page 1`}),(0,h.jsx)(`button`,{type:`button`,id:`next-btn`,class:P,onclick:`dashboard.nextPage()`,children:`Next`})]}),(0,h.jsx)(`script`,{children:(0,m.raw)(`
|
|
318
29
|
class DashboardManager {
|
|
319
30
|
constructor() {
|
|
320
31
|
this.filters = {
|
|
@@ -384,7 +95,7 @@ class DashboardManager {
|
|
|
384
95
|
}
|
|
385
96
|
|
|
386
97
|
updateLogTable(logs) {
|
|
387
|
-
const table = document.querySelector('.${
|
|
98
|
+
const table = document.querySelector('.${C}');
|
|
388
99
|
if (!table) return;
|
|
389
100
|
|
|
390
101
|
// Remove existing tbody elements (except thead)
|
|
@@ -396,26 +107,26 @@ class DashboardManager {
|
|
|
396
107
|
const levelClass = this.getLevelClass(log.level);
|
|
397
108
|
const timestamp = this.formatTimestamp(log.timestamp);
|
|
398
109
|
const traceIdHtml = log.traceId
|
|
399
|
-
? \`<span class="${
|
|
110
|
+
? \`<span class="${j}" onclick="dashboard.filterByTrace('\${log.traceId}')">\${log.traceId.slice(0, 8)}...</span>\`
|
|
400
111
|
: '<span>-</span>';
|
|
401
112
|
|
|
402
113
|
// Get display attributes (filter out trace/span IDs)
|
|
403
114
|
const displayAttrs = this.getDisplayAttributes(log.metadata);
|
|
404
115
|
const attrsHtml = displayAttrs
|
|
405
|
-
? \`<pre class="
|
|
116
|
+
? \`<pre class="attributes-cell">\${this.escapeHtml(JSON.stringify(displayAttrs, null, 2))}</pre>\`
|
|
406
117
|
: '';
|
|
407
118
|
|
|
408
119
|
const tbody = document.createElement('tbody');
|
|
409
|
-
tbody.className = '${
|
|
120
|
+
tbody.className = '${F}';
|
|
410
121
|
tbody.innerHTML = \`
|
|
411
|
-
<tr class="${
|
|
412
|
-
<td class="${
|
|
122
|
+
<tr class="${ce}">
|
|
123
|
+
<td class="${M}">\${timestamp}</td>
|
|
413
124
|
<td class="\${levelClass}">\${log.level.toUpperCase()}</td>
|
|
414
|
-
<td class="${
|
|
125
|
+
<td class="${N}">\${log.service}</td>
|
|
415
126
|
<td>\${traceIdHtml}</td>
|
|
416
127
|
</tr>
|
|
417
|
-
<tr class="${
|
|
418
|
-
<td colspan="4" class="${
|
|
128
|
+
<tr class="${I}">
|
|
129
|
+
<td colspan="4" class="${L}">
|
|
419
130
|
<div>\${this.escapeHtml(log.message)}</div>
|
|
420
131
|
\${attrsHtml}
|
|
421
132
|
</td>
|
|
@@ -448,12 +159,12 @@ class DashboardManager {
|
|
|
448
159
|
|
|
449
160
|
getLevelClass(level) {
|
|
450
161
|
const classes = {
|
|
451
|
-
trace: '${
|
|
452
|
-
debug: '${
|
|
453
|
-
info: '${
|
|
454
|
-
warn: '${
|
|
455
|
-
error: '${
|
|
456
|
-
fatal: '${
|
|
162
|
+
trace: '${w}',
|
|
163
|
+
debug: '${T}',
|
|
164
|
+
info: '${E}',
|
|
165
|
+
warn: '${D}',
|
|
166
|
+
error: '${O}',
|
|
167
|
+
fatal: '${k}',
|
|
457
168
|
};
|
|
458
169
|
return classes[level.toLowerCase()] || '';
|
|
459
170
|
}
|
|
@@ -556,7 +267,7 @@ const dashboard = new DashboardManager();
|
|
|
556
267
|
window.addEventListener('beforeunload', () => {
|
|
557
268
|
dashboard.stopAutoRefresh();
|
|
558
269
|
});
|
|
559
|
-
`)})]})}function
|
|
270
|
+
`)})]})}function R({title:e,children:t}){return(0,h.jsxs)(`html`,{lang:`en`,children:[(0,h.jsxs)(`head`,{children:[(0,h.jsx)(`meta`,{charset:`UTF-8`}),(0,h.jsx)(`meta`,{name:`viewport`,content:`width=device-width, initial-scale=1.0`}),(0,h.jsx)(`title`,{children:e}),(0,h.jsx)(`style`,{children:(0,m.raw)(`
|
|
560
271
|
* {
|
|
561
272
|
margin: 0;
|
|
562
273
|
padding: 0;
|
|
@@ -871,35 +582,9 @@ window.addEventListener('beforeunload', () => {
|
|
|
871
582
|
color: #555;
|
|
872
583
|
margin-top: 0.25rem;
|
|
873
584
|
}
|
|
874
|
-
`)})]}),(0,h.jsx)(`body`,{children:t})]})}function ye(e){let n=new u.Hono,r=e.get(t.m.LogQueryService);return n.get(`/`,async e=>{try{let t=await r.getActiveServices(),n=await r.getStatistics(),i=await r.filterByLevel([g.INFO,g.WARN,g.ERROR,g.FATAL],100),a={totalLogs:n.reduce((e,t)=>e+t.count,0),errors:n.filter(e=>e.level===`error`||e.level===`fatal`).reduce((e,t)=>e+t.count,0),services:new Set(n.map(e=>e.service)).size};return e.html((0,h.jsx)(I,{title:`Log Dashboard`,children:(0,h.jsx)(ve,{initialLogs:i,services:t,stats:a})}))}catch(t){return console.error(`Failed to render dashboard:`,t),e.html((0,h.jsx)(I,{title:`Log Dashboard - Error`,children:(0,h.jsxs)(`div`,{style:`padding: 2rem; text-align: center;`,children:[(0,h.jsx)(`h1`,{children:`Failed to load dashboard`}),(0,h.jsx)(`p`,{children:t instanceof Error?t.message:String(t)}),(0,h.jsx)(`a`,{href:`/`,style:`color: #2196f3; text-decoration: underline;`,children:`Retry`})]})}),500)}}),n}const L=5*1024*1024,be=1e3,R=2e3,xe=200,z=8e3,Se=p.z.object({timestamp:p.z.string().datetime().optional(),level:p.z.enum([`trace`,`debug`,`info`,`warn`,`error`,`fatal`]),message:p.z.string().min(1).max(z),traceId:p.z.string().regex(/^[0-9a-f]{32}$/i,`traceId must be 32 hex characters`).optional(),spanId:p.z.string().regex(/^[0-9a-f]{16}$/i,`spanId must be 16 hex characters`).optional(),parentSpanId:p.z.string().regex(/^[0-9a-f]{16}$/i,`parentSpanId must be 16 hex characters`).optional(),service:p.z.string().min(1).max(200),hostname:p.z.string().max(255).optional(),pid:p.z.number().int().nonnegative().optional(),metadata:p.z.record(p.z.string(),p.z.unknown()).optional(),errorType:p.z.string().max(255).optional(),errorMessage:p.z.string().max(8e3).optional(),errorStack:p.z.string().max(32e3).optional()}),Ce=p.z.object({logs:p.z.array(Se).min(1).max(1e3)});function B(e){if(!e||!/^\d+$/.test(e))throw Error(`OTLP timestamp must be a numeric unix-nanoseconds string`);let t=Number(BigInt(e)/BigInt(1e6));return new Date(t)}function V(e,t){return typeof e==`string`&&RegExp(`^[0-9a-f]{${t}}$`,`i`).test(e)}function H(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<=0?null:t>L?`Request body exceeds ${L} bytes`:null}async function U(e){try{return await e.req.json()}catch(e){throw Error(`Invalid JSON body: ${e instanceof Error?e.message:String(e)}`)}}function we(e){if(!Array.isArray(e.resourceSpans)||e.resourceSpans.length===0)throw Error(`Invalid OTLP trace request: missing resourceSpans`);let t=0;for(let n of e.resourceSpans){if(!Array.isArray(n.scopeSpans))throw Error(`Invalid OTLP trace request: scopeSpans must be an array`);for(let e of n.scopeSpans){if(!Array.isArray(e.spans))throw Error(`Invalid OTLP trace request: spans must be an array`);for(let n of e.spans){if(t+=1,t>R)throw Error(`OTLP trace request exceeds ${R} spans`);if(!V(n.traceId,32))throw Error(`Invalid OTLP trace request: traceId must be 32 hex characters`);if(!V(n.spanId,16))throw Error(`Invalid OTLP trace request: spanId must be 16 hex characters`);if(n.parentSpanId&&!V(n.parentSpanId,16))throw Error(`Invalid OTLP trace request: parentSpanId must be 16 hex characters`);if(!n.name||n.name.length>z)throw Error(`Invalid OTLP trace request: span name is missing or too long`);B(n.startTimeUnixNano)}}}}function Te(e){if(!Array.isArray(e.resourceLogs)||e.resourceLogs.length===0)throw Error(`Invalid OTLP logs request: missing resourceLogs`);let t=0;for(let n of e.resourceLogs){if(!Array.isArray(n.scopeLogs))throw Error(`Invalid OTLP logs request: scopeLogs must be an array`);for(let e of n.scopeLogs){if(!Array.isArray(e.logRecords))throw Error(`Invalid OTLP logs request: logRecords must be an array`);for(let n of e.logRecords){if(t+=1,t>R)throw Error(`OTLP logs request exceeds ${R} log records`);if(n.traceId&&!V(n.traceId,32))throw Error(`Invalid OTLP logs request: traceId must be 32 hex characters`);if(n.spanId&&!V(n.spanId,16))throw Error(`Invalid OTLP logs request: spanId must be 16 hex characters`);if(n.severityText&&n.severityText.length>32)throw Error(`Invalid OTLP logs request: severityText is too long`);B(n.timeUnixNano)}}}}function Ee(e){return(e.resource?.attributes?.find(e=>e.key===`service.name`))?.value?.stringValue||`unknown-service`}function W(e,t){let n=e?.find(e=>e.key===t);if(!n)return;let{value:r}=n;if(r.stringValue!==void 0)return r.stringValue;if(r.intValue!==void 0)return r.intValue;if(r.doubleValue!==void 0)return String(r.doubleValue);if(r.boolValue!==void 0)return String(r.boolValue)}function De(e){return(e.resource?.attributes?.find(e=>e.key===`service.name`))?.value?.stringValue||`unknown-service`}function Oe(e){return e===void 0?`info`:e<=4?`trace`:e<=8?`debug`:e<=12?`info`:e<=16?`warn`:e<=20?`error`:`fatal`}function ke(e,t){let n=B(e.timeUnixNano),r=e.severityText?.toLowerCase()||Oe(e.severityNumber),i=``;if(e.body?.stringValue)i=e.body.stringValue;else if(e.body?.kvlistValue){let t={};for(let n of e.body.kvlistValue.values){let e=n.value.stringValue??n.value.intValue??n.value.doubleValue??n.value.boolValue;t[n.key]=e}i=JSON.stringify(t)}let a={},o=null,s=null,c=null;if(e.attributes)for(let t of e.attributes){let e=t.value.stringValue??t.value.intValue??t.value.doubleValue??t.value.boolValue;t.key===`exception.type`?o=String(e):t.key===`exception.message`?s=String(e):t.key===`exception.stacktrace`?c=String(e):a[t.key]=e}return{timestamp:n,level:r,message:i||`[LOG] ${t}`,traceId:e.traceId??null,spanId:e.spanId??null,parentSpanId:null,service:t,hostname:null,pid:null,metadata:Object.keys(a).length>0?a:null,errorType:o,errorMessage:s,errorStack:c}}function Ae(e,t){let n=B(e.startTimeUnixNano),r=e.status?.code,i=`info`;r===2?i=`error`:r===1&&(i=`info`);let a=W(e.attributes,`exception.type`),o=W(e.attributes,`exception.message`),s=W(e.attributes,`exception.stacktrace`),c={};if(e.attributes)for(let t of e.attributes){let e=t.value.stringValue??t.value.intValue??t.value.doubleValue??t.value.boolValue;c[t.key]=e}return c.spanName=e.name,c.spanKind=e.kind,e.status?.message&&(c.statusMessage=e.status.message),{timestamp:n,level:i,message:`[SPAN] ${e.name}`,traceId:e.traceId,spanId:e.spanId,parentSpanId:e.parentSpanId??null,service:t,hostname:null,pid:null,metadata:c,errorType:a??null,errorMessage:o??null,errorStack:s??null}}function je(e){let n=new u.Hono,r=e.get(t.m.LogStorageService);n.use(`*`,(0,d.cors)({origin:e=>e??null,credentials:!0,allowMethods:[`GET`,`POST`,`OPTIONS`],allowHeaders:[`Content-Type`,`Accept`,`Authorization`]})),n.get(`/health`,async e=>{try{return e.json({status:`healthy`,service:`log-sink-mcp-http`,serviceName:`log-sink-mcp-http`,timestamp:new Date().toISOString()})}catch(t){return e.json({status:`unhealthy`,error:t instanceof Error?t.message:String(t)},503)}});let i=(0,f.rateLimiter)({windowMs:60*1e3,limit:100,standardHeaders:`draft-6`,keyGenerator:e=>e.req.header(`x-forwarded-for`)||e.req.header(`x-real-ip`)||`unknown`});n.post(`/logs`,i,async e=>{try{let t=H(e.req.header(`content-length`));if(t)return e.json({success:!1,error:t},413);let n=await U(e),i=Ce.safeParse(n);if(!i.success)return e.json({success:!1,error:`Validation failed`,details:i.error.issues},400);let{logs:a}=i.data,o=a.map(e=>({...e,timestamp:e.timestamp?new Date(e.timestamp):new Date})),s=await r.insertBatch(o);return e.json({success:!0,count:s.length,message:`Successfully inserted ${s.length} logs`},201)}catch(t){let n=t instanceof Error?t.message:String(t);return n.startsWith(`Invalid JSON body`)?e.json({success:!1,error:n},400):(console.error(`Failed to insert logs:`,t),e.json({success:!1,error:`Failed to insert logs`},500))}}),n.post(`/v1/traces`,i,async e=>{try{let t=H(e.req.header(`content-length`));if(t)return e.json({success:!1,error:t},413);let n=await U(e);we(n);let i=[];for(let e of n.resourceSpans){let t=Ee(e);for(let n of e.scopeSpans)for(let e of n.spans){let n=Ae(e,t);i.push(n)}}let a=await r.insertBatch(i);return e.json({success:!0,count:a.length,message:`Successfully inserted ${a.length} trace spans as logs`},201)}catch(t){let n=t instanceof Error?t.message:String(t);return n.startsWith(`Invalid JSON body`)||n.startsWith(`Invalid OTLP`)||n.startsWith(`OTLP`)?e.json({success:!1,error:n},400):(console.error(`Failed to insert OTLP traces:`,t),e.json({success:!1,error:`Failed to insert OTLP traces`},500))}}),n.post(`/v1/logs`,i,async e=>{try{let t=H(e.req.header(`content-length`));if(t)return e.json({success:!1,error:t},413);let n=await U(e);Te(n);let i=[];for(let e of n.resourceLogs){let t=De(e);for(let n of e.scopeLogs)for(let e of n.logRecords){let n=ke(e,t);i.push(n)}}let a=await r.insertBatch(i);return e.json({success:!0,count:a.length,message:`Successfully inserted ${a.length} OTLP logs`},201)}catch(t){let n=t instanceof Error?t.message:String(t);return n.startsWith(`Invalid JSON body`)||n.startsWith(`Invalid OTLP`)||n.startsWith(`OTLP`)?e.json({success:!1,error:n},400):(console.error(`Failed to insert OTLP logs:`,t),e.json({success:!1,error:`Failed to insert OTLP logs`},500))}});let a=v(e);n.route(`/api`,a);let o=ye(e);return n.route(`/`,o),n}const Me=256*1024*1024,Ne=.9,Pe=300*1e3,Fe=1e3;function G(e,t){if(e===void 0||e===``)return t;let n=Number.parseInt(e,10);if(!Number.isFinite(n)||n<=0)throw Error(`Invalid database retention value: ${e}`);return n}function K(e={}){let t=G(e.dbMaxBytes??process.env.LOG_SINK_DB_MAX_BYTES,268435456),n=G(e.dbTargetBytes??process.env.LOG_SINK_DB_TARGET_BYTES,Math.floor(t*.9));return{maxBytes:t,targetBytes:Math.min(n,t),intervalMs:G(e.dbRetentionIntervalMs??process.env.LOG_SINK_DB_RETENTION_INTERVAL_MS,3e5),batchSize:G(e.dbRetentionBatchSize??process.env.LOG_SINK_DB_RETENTION_BATCH_SIZE,1e3)}}const Ie=String(o.DEFAULT_PORT_RANGE.min),Le=t.f(),Re=new a.Command(`http-serve`).description(`Start HTTP server for log ingestion with configurable port, database path, and in-memory mode`).option(`-p, --port <port>`,`Port to listen on`,Ie).option(`--db-path <path>`,`Path to SQLite database file`,Le).option(`--in-memory`,`Use in-memory database (for testing)`,!1).option(`--db-max-bytes <bytes>`,`Maximum SQLite database size before trimming`).option(`--db-target-bytes <bytes>`,`Target SQLite database size after trimming`).option(`--db-retention-interval-ms <ms>`,`How often to check database size`,`300000`).option(`--db-retention-batch-size <count>`,`Number of oldest log rows to delete per trim batch`,`1000`).option(`--registry-path <path>`,`Custom registry path or directory for service discovery`).action(async e=>{let n;try{let r=Number.parseInt(e.port,10),i={min:o.DEFAULT_PORT_RANGE.min,max:Math.max(o.DEFAULT_PORT_RANGE.max??4999,r)},a=process.env.NODE_ENV||`development`,l=t.p(process.cwd()),u=`log-sink-mcp-http`;e.registryPath&&(process.env.PORT_REGISTRY_PATH=e.registryPath,process.env.PROCESS_REGISTRY_PATH=(0,s.resolveSiblingRegistryPath)(e.registryPath,`processes.json`)??process.env.PROCESS_REGISTRY_PATH);let d=new o.PortRegistryService(process.env.PORT_REGISTRY_PATH),f=t.u(),p=f.get(t.m.LogStorageService),m=f.get(t.m.LogRetentionService);await p.initializeDatabase(e.dbPath,e.inMemory);let h=m.startSizeRetentionMonitor(K({dbMaxBytes:e.dbMaxBytes,dbTargetBytes:e.dbTargetBytes,dbRetentionIntervalMs:e.dbRetentionIntervalMs,dbRetentionBatchSize:e.dbRetentionBatchSize})),g=je(f),_=await d.reservePort({repositoryPath:l,serviceName:u,serviceType:`tool`,environment:a,preferredPort:r,pid:process.pid,host:`127.0.0.1`,force:!0,portRange:i,metadata:{healthCheckUrl:`http://localhost:${r}/health`,dbPath:e.dbPath}});if(!_.success||!_.record)throw Error(_.error||`Failed to reserve service in global registry`);let v=_.record.port;if(v!==r){let t=await d.reservePort({repositoryPath:l,serviceName:u,serviceType:`tool`,environment:a,preferredPort:v,pid:process.pid,host:`127.0.0.1`,force:!0,portRange:i,metadata:{healthCheckUrl:`http://localhost:${v}/health`,dbPath:e.dbPath}});if(!t.success||!t.record)throw Error(t.error||`Failed to update service metadata in registry`);_=t}if(!_.record)throw Error(`Port reservation lost before startup`);let y=_.record.port;n=await(0,s.createProcessLease)({repositoryPath:l,serviceName:u,serviceType:`tool`,environment:a,pid:process.pid,port:y,host:`127.0.0.1`,command:process.argv[1],args:process.argv.slice(2),metadata:{dbPath:e.dbPath,transport:`http`}});let b;try{b=(0,c.serve)({fetch:g.fetch,port:y})}catch(e){try{await n.release({kill:!1})}catch{}throw e}let x=async()=>{try{b.close();try{await n?.release({kill:!1})}catch{}h(),await p.disconnect(),process.exit(0)}catch{process.exit(1)}};process.on(`SIGINT`,()=>x()),process.on(`SIGTERM`,()=>x())}catch{try{await n?.release({kill:!1})}catch{}process.exit(1)}}),ze=10,Be=5,Ve=3,He=[g.ERROR,g.FATAL],Ue=`log-sink-mcp-http`;function We(e){let t=e.trim();if(!t)return null;try{return JSON.parse(t)}catch{return null}}function Ge(e){if(e==null)return`unknown`;if(typeof e==`string`)return e;try{return JSON.stringify(e,null,2)}catch{return String(e)}}function q(e){return e.hook_event_name===`PostToolUseFailure`?`Current tool failure:\n- Tool: ${e.tool_name??`unknown tool`}\n- Error: ${Ge(e.error)}`:null}function Ke(e,t,n){let r=new Map;for(let t of e){let e=`${t.service}::${t.level}::${t.error_type??``}::${t.error_message??t.message}`,i=new Date(Number(t.created_at)*1e3).toISOString();r.has(e)||r.set(e,{key:e,count:0,service:t.service,level:t.level,errorType:t.error_type,errorMessage:t.error_message,message:t.message,firstSeen:i,lastSeen:i,traceIds:new Set,examples:[]});let a=r.get(e);a.count+=1,a.lastSeen=i,t.trace_id&&a.traceIds.add(t.trace_id),a.examples.length<n&&a.examples.push({id:t.id,timestamp:i,traceId:t.trace_id})}return Array.from(r.values()).sort((e,t)=>t.count-e.count||t.lastSeen.localeCompare(e.lastSeen)).slice(0,t)}function qe(e,t,n,r){let i=Ke(e,n,r),a=[];a.push(`Recent log errors (${e.length} new):`),t.tool_name&&a.push(`- Triggered after tool: ${t.tool_name}`);for(let[e,t]of i.entries()){a.push(`${e+1}. ${t.service} [${t.level}] x${t.count} ${t.errorType?`(${t.errorType}) `:``}${t.errorMessage??t.message}`),a.push(` First seen: ${t.firstSeen}`),a.push(` Last seen: ${t.lastSeen}`),t.traceIds.size>0&&a.push(` Trace IDs: ${Array.from(t.traceIds).slice(0,3).join(`, `)}`);for(let e of t.examples)a.push(` Example: ${e.timestamp} id=${e.id}${e.traceId?` trace=${e.traceId}`:``}`)}if(t.hook_event_name===`PostToolUseFailure`){let e=q(t);e&&a.push(``,e)}return a.join(`
|
|
875
|
-
`)}function
|
|
876
|
-
SELECT id, created_at
|
|
877
|
-
FROM logs
|
|
878
|
-
WHERE id = ?
|
|
879
|
-
LIMIT 1
|
|
880
|
-
`).all(t)[0];e&&(o=Number(e.created_at),s=e.id)}let c=a.prepare(`
|
|
881
|
-
SELECT
|
|
882
|
-
id,
|
|
883
|
-
created_at,
|
|
884
|
-
level,
|
|
885
|
-
message,
|
|
886
|
-
service,
|
|
887
|
-
trace_id,
|
|
888
|
-
span_id,
|
|
889
|
-
parent_span_id,
|
|
890
|
-
error_type,
|
|
891
|
-
error_message
|
|
892
|
-
FROM logs
|
|
893
|
-
WHERE level IN (?, ?)
|
|
894
|
-
AND (
|
|
895
|
-
created_at > ?
|
|
896
|
-
OR (created_at = ? AND id > ?)
|
|
897
|
-
)
|
|
898
|
-
ORDER BY created_at ASC, id ASC
|
|
899
|
-
LIMIT ?
|
|
900
|
-
`).all(...He,o,o,s,Math.max(r*i*2,r*3));return c.length===0?{rows:[]}:{rows:c,nextCheckpoint:c[c.length-1]}}async function Xe(e,n={}){let r=J(e),i=e.session_id?.trim();if(!r||!i)return null;let a=await Je(e,n);if(!a)return null;let o=new t.d;try{await o.initializeDatabase(a);let{rows:t,nextCheckpoint:s}=await Ye(o,await o.getHookCheckpoint(i,r),n.lookbackMinutes??10,n.maxGroups??5,n.maxExamplesPerGroup??3),c=q(e);if(t.length===0)return c?{hookSpecificOutput:{hookEventName:e.hook_event_name??`PostToolUse`,additionalContext:c}}:null;let l=qe(t,e,n.maxGroups??5,n.maxExamplesPerGroup??3);return await o.setHookCheckpoint(i,r,s?.id??t[t.length-1].id),{hookSpecificOutput:{hookEventName:e.hook_event_name??`PostToolUse`,additionalContext:c?`${l}\n\n${c}`:l}}}finally{await o.disconnect().catch(()=>void 0)}}const Ze=new a.Command(`claude-hook`).alias(`hook`).description(`Emit additional Claude Code context from recent log errors`).option(`--db-path <path>`,`Path to the SQLite database file`).option(`--lookback-minutes <minutes>`,`Initial monitoring window in minutes`,`10`).option(`--max-groups <count>`,`Maximum number of grouped errors to include`,`5`).option(`--max-examples-per-group <count>`,`Maximum number of example errors to include per group`,`3`).action(async e=>{try{let t=We((0,n.readFileSync)(0,`utf-8`));t||process.exit(0);let r=await Xe(t,{dbPath:e.dbPath,lookbackMinutes:e.lookbackMinutes?Number.parseInt(e.lookbackMinutes,10):10,maxGroups:e.maxGroups?Number.parseInt(e.maxGroups,10):5,maxExamplesPerGroup:e.maxExamplesPerGroup?Number.parseInt(e.maxExamplesPerGroup,10):3});r||process.exit(0),process.stdout.write(`${JSON.stringify(r)}\n`),process.exit(0)}catch(e){process.stderr.write(`Error running Claude hook: ${e instanceof Error?e.message:String(e)}\n`),process.exit(1)}}),Qe=t.f(),Y=new Set(Object.values(g)),$e=new Set([`level`,`service`,`both`]),et={stdout:e=>console.log(e),stderr:e=>console.error(e)};function X(e){let t=Number.parseInt(e,10);if(!Number.isInteger(t)||t<=0)throw new a.InvalidArgumentError(`Expected a positive integer.`);return t}function tt(e){if(!$e.has(e))throw new a.InvalidArgumentError(`Expected one of: 'level', 'service', 'both'.`);return e}function Z(e){if(!(!e||e.length===0))return e.map(e=>{if(!Y.has(e))throw new a.InvalidArgumentError(`Invalid log level '${e}'. Expected one of: ${Array.from(Y).join(`, `)}`);return e})}function nt(e){return e.content.map(e=>e.type===`text`?e.text:JSON.stringify(e)).join(`
|
|
901
|
-
`)}function Q(e){return e.option(`--db-path <path>`,`Path to SQLite database file`,Qe).option(`--in-memory`,`Use in-memory database`,!1)}async function rt(e,n){let r=t.u(),i=r.get(t.m.LogStorageService);await i.initializeDatabase(e.dbPath,e.inMemory);try{return await n(r)}finally{await i.disconnect()}}async function it(e,t,n,r=et){try{let i=await rt(e,async e=>t(e).execute(n)),a=nt(i);return i.isError?(r.stderr(a),1):(r.stdout(a),0)}catch(e){return r.stderr(`Error executing logs command: ${e instanceof Error?e.message:String(e)}`),1}}async function $(e,t,n){let r=await it(e,t,n);r!==0&&process.exit(r)}function at(e,t){if(!(!e&&!t)){if(!e||!t)throw new a.InvalidArgumentError(`Provide both --start-time and --end-time together.`);return{start:e,end:t}}}function ot(){let e=new a.Command(`logs`).description(`Run log analysis commands that mirror MCP tool capabilities`),n=Q(new a.Command(`query`).alias(`query-logs`).description(`Query and filter log entries by level, trace ID, service, or time range`).option(`--level <level...>`,`Log level(s) to filter by`).option(`--trace-id <traceId>`,`Trace ID to filter by`).option(`--service <service...>`,`Service name(s) to filter by`).option(`--start-time <iso8601>`,`Start time for log range (ISO 8601)`).option(`--end-time <iso8601>`,`End time for log range (ISO 8601)`).option(`--limit <number>`,`Maximum number of log entries to return`,X).action(async e=>{await $(e,e=>new t.i(e),{level:Z(e.level),traceId:e.traceId,service:e.service,startTime:e.startTime,endTime:e.endTime,limit:e.limit})})),r=Q(new a.Command(`search`).alias(`search-logs`).description(`Search log entries with full-text search and optional filters`).argument(`<search-query>`,`FTS5 search query`).option(`--mode <mode>`,`Search strategy: fts, semantic, or hybrid`,`hybrid`).option(`--service <service...>`,`Service name(s) to filter by`).option(`--level <level...>`,`Log level(s) to filter by`).option(`--start-time <iso8601>`,`Start time for log range (ISO 8601)`).option(`--end-time <iso8601>`,`End time for log range (ISO 8601)`).option(`--limit <number>`,`Maximum number of search results to return`,X).action(async(e,n)=>{await $(n,e=>new t.r(e),{searchQuery:e,mode:n.mode,service:n.service,level:Z(n.level),startTime:n.startTime,endTime:n.endTime,limit:n.limit})})),i=Q(new a.Command(`trace`).alias(`get-trace-timeline`).description(`Get the complete trace timeline for a trace ID`).argument(`<trace-id>`,`Trace ID to inspect`).action(async(e,n)=>{await $(n,e=>new t.a(e),{traceId:e})})),o=Q(new a.Command(`analyze-errors`).alias(`errors`).description(`Analyze error patterns and group similar errors`).option(`--trace-id <traceId>`,`Optional trace ID to scope the analysis`).option(`--start-time <iso8601>`,`Start time for error analysis (ISO 8601)`).option(`--end-time <iso8601>`,`End time for error analysis (ISO 8601)`).option(`--limit <number>`,`Maximum number of error entries to analyze`,X).action(async e=>{await $(e,e=>new t.l(e),{traceId:e.traceId,timeRange:at(e.startTime,e.endTime),limit:e.limit})})),s=Q(new a.Command(`stats`).alias(`get-log-stats`).description(`Get aggregated log statistics grouped by level, service, or both`).option(`--start-time <iso8601>`,`Start time for statistics (ISO 8601)`).option(`--end-time <iso8601>`,`End time for statistics (ISO 8601)`).option(`--group-by <groupBy>`,`Group statistics by level, service, or both`,tt).action(async e=>{await $(e,e=>new t.s(e),{startTime:e.startTime,endTime:e.endTime,groupBy:e.groupBy})})),c=Q(new a.Command(`services`).alias(`get-services`).description(`Get the list of unique services present in the log database`).action(async e=>{await $(e,e=>new t.o(e),{})})),l=Q(new a.Command(`clear`).alias(`clear-logs`).description(`Clear all logs from the database`).action(async e=>{await $(e,e=>new t.c(e),{})}));return e.addCommand(n).addCommand(r).addCommand(i).addCommand(o).addCommand(s).addCommand(c).addCommand(l)}const st=ot();function ct(){return t.f()}const lt=new a.Command(`mcp-serve`).description(`Start MCP server with stdio transport`).option(`--cleanup`,`Stop HTTP server on MCP server shutdown`,!1).option(`--db-path <path>`,`Path to SQLite database file`,ct()).option(`--in-memory`,`Use in-memory database (for testing)`,!1).option(`--db-max-bytes <bytes>`,`Maximum SQLite database size before trimming`).option(`--db-target-bytes <bytes>`,`Target SQLite database size after trimming`).option(`--db-retention-interval-ms <ms>`,`How often to check database size`,`300000`).option(`--db-retention-batch-size <count>`,`Number of oldest log rows to delete per trim batch`,`1000`).option(`--registry-path <path>`,`Custom registry path or directory for service discovery`).option(`--registry-dir <path>`,`Custom registry directory for service discovery`).action(async e=>{let n;try{let r=e.registryPath||e.registryDir;r&&(process.env.PORT_REGISTRY_PATH=r,process.env.PROCESS_REGISTRY_PATH=(0,s.resolveSiblingRegistryPath)(r,`processes.json`)??process.env.PROCESS_REGISTRY_PATH);let i=t.u(),a=i.get(t.m.LogStorageService),o=i.get(t.m.LogRetentionService),c=i.get(t.m.HttpServerManager);await a.initializeDatabase(e.dbPath,e.inMemory);let l=o.startSizeRetentionMonitor(K({dbMaxBytes:e.dbMaxBytes,dbTargetBytes:e.dbTargetBytes,dbRetentionIntervalMs:e.dbRetentionIntervalMs,dbRetentionBatchSize:e.dbRetentionBatchSize})),u=new t.t(t.n(i));n=await(0,s.createProcessLease)({repositoryPath:process.cwd(),serviceName:`log-sink-mcp-mcp-serve`,serviceType:`tool`,environment:process.env.NODE_ENV||`development`,pid:process.pid,host:`127.0.0.1`,command:process.argv[1],args:process.argv.slice(2),metadata:{transport:`stdio`,command:`mcp-serve`}});let d=c.ensureRunning(void 0,e.dbPath),f;d.then(t=>{t.running&&(f=c.startHealthMonitor(e.dbPath))}).catch(()=>void 0);let p=async t=>{console.error(`\nReceived ${t}, shutting down gracefully...`);try{f?.(),await u.stop(),e.cleanup&&(await d.catch(()=>({running:!1}))).running&&(await c.stop(),console.error(`HTTP server stopped`)),l(),await a.disconnect(),await n?.release(),process.exit(0)}catch(e){console.error(`Error during shutdown:`,e),process.exit(1)}};process.on(`SIGINT`,()=>p(`SIGINT`)),process.on(`SIGTERM`,()=>p(`SIGTERM`)),await u.start()}catch(e){await n?.release().catch(()=>void 0),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),ut=new a.Command(`start`).description(`Start HTTP and/or MCP servers with singleton coordination`).option(`--mcp-only`,`Start only the MCP server (stdio transport)`,!1).option(`--http-only`,`Start only the HTTP server`,!1).option(`-p, --port <port>`,`Port for HTTP server`,String(o.DEFAULT_PORT_RANGE.min)).option(`--db-path <path>`,`Path to SQLite database file`,t.f()).option(`--in-memory`,`Use in-memory database (for testing)`,!1).option(`--db-max-bytes <bytes>`,`Maximum SQLite database size before trimming`).option(`--db-target-bytes <bytes>`,`Target SQLite database size after trimming`).option(`--db-retention-interval-ms <ms>`,`How often to check database size`,`300000`).option(`--db-retention-batch-size <count>`,`Number of oldest log rows to delete per trim batch`,`1000`).option(`--registry-path <path>`,`Custom registry path or directory for service discovery`).option(`--registry-dir <path>`,`Custom registry directory for service discovery`).action(async e=>{let n;try{let r=e.registryPath||e.registryDir;r&&(process.env.PORT_REGISTRY_PATH=r,process.env.PROCESS_REGISTRY_PATH=(0,s.resolveSiblingRegistryPath)(r,`processes.json`)??process.env.PROCESS_REGISTRY_PATH),e.dbMaxBytes&&(process.env.LOG_SINK_DB_MAX_BYTES=e.dbMaxBytes),e.dbTargetBytes&&(process.env.LOG_SINK_DB_TARGET_BYTES=e.dbTargetBytes),e.dbRetentionIntervalMs&&(process.env.LOG_SINK_DB_RETENTION_INTERVAL_MS=e.dbRetentionIntervalMs),e.dbRetentionBatchSize&&(process.env.LOG_SINK_DB_RETENTION_BATCH_SIZE=e.dbRetentionBatchSize);let i=t.u(),a=i.get(t.m.LogStorageService);await a.initializeDatabase(e.dbPath,e.inMemory);let o=Number.parseInt(e.port,10),c=!e.mcpOnly,l=!e.httpOnly,u=i.get(t.m.LogRetentionService),d=l?u.startSizeRetentionMonitor(K({dbMaxBytes:e.dbMaxBytes,dbTargetBytes:e.dbTargetBytes,dbRetentionIntervalMs:e.dbRetentionIntervalMs,dbRetentionBatchSize:e.dbRetentionBatchSize})):()=>void 0;if(console.log(`🚀 Starting log-sink-mcp services...`),console.log(` Database: ${e.inMemory?`In-Memory`:e.dbPath}`),c){let n=await i.get(t.m.HttpServerManager).ensureRunning(o,e.dbPath);n.running?(console.log(`✓ HTTP Server: Running on http://localhost:${n.port} (PID: ${n.pid})`),console.log(` Health check: http://localhost:${n.port}/health`),console.log(` Log ingestion: POST http://localhost:${n.port}/logs`)):(console.error(`✗ HTTP Server failed to start: ${n.error}`),l||process.exit(1))}if(l){n=await(0,s.createProcessLease)({repositoryPath:process.cwd(),serviceName:`log-sink-mcp-start`,serviceType:`tool`,environment:process.env.NODE_ENV||`development`,pid:process.pid,host:`127.0.0.1`,command:process.argv[1],args:process.argv.slice(2),metadata:{transport:`stdio`,command:`start`}}),console.log(`✓ MCP Server: Starting with stdio transport...`);let e=new t.t(t.n(i));await e.start(),console.log(`✓ MCP Server: Ready for connections`);let r=async r=>{console.log(`\n\n${r} received. Shutting down gracefully...`);try{await e.stop(),console.log(`✓ MCP server stopped`),c&&(await i.get(t.m.HttpServerManager).stop(),console.log(`✓ HTTP server stopped`)),d(),await a.disconnect(),console.log(`✓ Database disconnected`),await n?.release(),console.log(`✓ Process registry entry released`),console.log(`Goodbye! 👋`),process.exit(0)}catch(e){console.error(`Error during shutdown:`,e),process.exit(1)}};process.on(`SIGINT`,()=>r(`SIGINT`)),process.on(`SIGTERM`,()=>r(`SIGTERM`)),console.log(`
|
|
585
|
+
`)})]}),(0,h.jsx)(`body`,{children:t})]})}function ge(e){let n=new d.Hono,r=e.get(t.m.LogQueryService);return n.get(`/`,async e=>{try{let t=await r.getActiveServices(),n=await r.getStatistics(),i=await r.filterByLevel([g.INFO,g.WARN,g.ERROR,g.FATAL],100),a={totalLogs:n.reduce((e,t)=>e+t.count,0),errors:n.filter(e=>e.level===`error`||e.level===`fatal`).reduce((e,t)=>e+t.count,0),services:new Set(n.map(e=>e.service)).size};return e.html((0,h.jsx)(R,{title:`Log Dashboard`,children:(0,h.jsx)(he,{initialLogs:i,services:t,stats:a})}))}catch(t){return console.error(`Failed to render dashboard:`,t),e.html((0,h.jsx)(R,{title:`Log Dashboard - Error`,children:(0,h.jsxs)(`div`,{style:`padding: 2rem; text-align: center;`,children:[(0,h.jsx)(`h1`,{children:`Failed to load dashboard`}),(0,h.jsx)(`p`,{children:t instanceof Error?t.message:String(t)}),(0,h.jsx)(`a`,{href:`/`,style:`color: #2196f3; text-decoration: underline;`,children:`Retry`})]})}),500)}}),n}const z=5*1024*1024,B=2e3,V=8e3,_e=n.z.object({timestamp:n.z.string().datetime().optional(),level:n.z.enum([`trace`,`debug`,`info`,`warn`,`error`,`fatal`]),message:n.z.string().min(1).max(V),traceId:n.z.string().regex(/^[0-9a-f]{32}$/i,`traceId must be 32 hex characters`).optional(),spanId:n.z.string().regex(/^[0-9a-f]{16}$/i,`spanId must be 16 hex characters`).optional(),parentSpanId:n.z.string().regex(/^[0-9a-f]{16}$/i,`parentSpanId must be 16 hex characters`).optional(),service:n.z.string().min(1).max(200),hostname:n.z.string().max(255).optional(),pid:n.z.number().int().nonnegative().optional(),metadata:n.z.record(n.z.string(),n.z.unknown()).optional(),errorType:n.z.string().max(255).optional(),errorMessage:n.z.string().max(8e3).optional(),errorStack:n.z.string().max(32e3).optional()}),ve=n.z.object({logs:n.z.array(_e).min(1).max(1e3)});function H(e){if(!e||!/^\d+$/.test(e))throw Error(`OTLP timestamp must be a numeric unix-nanoseconds string`);let t=Number(BigInt(e)/BigInt(1e6));return new Date(t)}function U(e,t){return typeof e==`string`&&RegExp(`^[0-9a-f]{${t}}$`,`i`).test(e)}function W(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<=0?null:t>z?`Request body exceeds ${z} bytes`:null}async function G(e){try{return await e.req.json()}catch(e){throw Error(`Invalid JSON body: ${e instanceof Error?e.message:String(e)}`)}}function ye(e){if(!Array.isArray(e.resourceSpans)||e.resourceSpans.length===0)throw Error(`Invalid OTLP trace request: missing resourceSpans`);let t=0;for(let n of e.resourceSpans){if(!Array.isArray(n.scopeSpans))throw Error(`Invalid OTLP trace request: scopeSpans must be an array`);for(let e of n.scopeSpans){if(!Array.isArray(e.spans))throw Error(`Invalid OTLP trace request: spans must be an array`);for(let n of e.spans){if(t+=1,t>B)throw Error(`OTLP trace request exceeds ${B} spans`);if(!U(n.traceId,32))throw Error(`Invalid OTLP trace request: traceId must be 32 hex characters`);if(!U(n.spanId,16))throw Error(`Invalid OTLP trace request: spanId must be 16 hex characters`);if(n.parentSpanId&&!U(n.parentSpanId,16))throw Error(`Invalid OTLP trace request: parentSpanId must be 16 hex characters`);if(!n.name||n.name.length>V)throw Error(`Invalid OTLP trace request: span name is missing or too long`);H(n.startTimeUnixNano)}}}}function be(e){if(!Array.isArray(e.resourceLogs)||e.resourceLogs.length===0)throw Error(`Invalid OTLP logs request: missing resourceLogs`);let t=0;for(let n of e.resourceLogs){if(!Array.isArray(n.scopeLogs))throw Error(`Invalid OTLP logs request: scopeLogs must be an array`);for(let e of n.scopeLogs){if(!Array.isArray(e.logRecords))throw Error(`Invalid OTLP logs request: logRecords must be an array`);for(let n of e.logRecords){if(t+=1,t>B)throw Error(`OTLP logs request exceeds ${B} log records`);if(n.traceId&&!U(n.traceId,32))throw Error(`Invalid OTLP logs request: traceId must be 32 hex characters`);if(n.spanId&&!U(n.spanId,16))throw Error(`Invalid OTLP logs request: spanId must be 16 hex characters`);if(n.severityText&&n.severityText.length>32)throw Error(`Invalid OTLP logs request: severityText is too long`);H(n.timeUnixNano)}}}}function xe(e){return(e.resource?.attributes?.find(e=>e.key===`service.name`))?.value?.stringValue||`unknown-service`}function K(e,t){let n=e?.find(e=>e.key===t);if(!n)return;let{value:r}=n;if(r.stringValue!==void 0)return r.stringValue;if(r.intValue!==void 0)return r.intValue;if(r.doubleValue!==void 0)return String(r.doubleValue);if(r.boolValue!==void 0)return String(r.boolValue)}function Se(e){return(e.resource?.attributes?.find(e=>e.key===`service.name`))?.value?.stringValue||`unknown-service`}function Ce(e){return e===void 0?`info`:e<=4?`trace`:e<=8?`debug`:e<=12?`info`:e<=16?`warn`:e<=20?`error`:`fatal`}function we(e,t){let n=H(e.timeUnixNano),r=e.severityText?.toLowerCase()||Ce(e.severityNumber),i=``;if(e.body?.stringValue)i=e.body.stringValue;else if(e.body?.kvlistValue){let t={};for(let n of e.body.kvlistValue.values){let e=n.value.stringValue??n.value.intValue??n.value.doubleValue??n.value.boolValue;t[n.key]=e}i=JSON.stringify(t)}let a={},o=null,s=null,c=null;if(e.attributes)for(let t of e.attributes){let e=t.value.stringValue??t.value.intValue??t.value.doubleValue??t.value.boolValue;t.key===`exception.type`?o=String(e):t.key===`exception.message`?s=String(e):t.key===`exception.stacktrace`?c=String(e):a[t.key]=e}return{timestamp:n,level:r,message:i||`[LOG] ${t}`,traceId:e.traceId??null,spanId:e.spanId??null,parentSpanId:null,service:t,hostname:null,pid:null,metadata:Object.keys(a).length>0?a:null,errorType:o,errorMessage:s,errorStack:c}}function Te(e,t){let n=H(e.startTimeUnixNano),r=e.status?.code,i=`info`;r===2?i=`error`:r===1&&(i=`info`);let a=K(e.attributes,`exception.type`),o=K(e.attributes,`exception.message`),s=K(e.attributes,`exception.stacktrace`),c={};if(e.attributes)for(let t of e.attributes){let e=t.value.stringValue??t.value.intValue??t.value.doubleValue??t.value.boolValue;c[t.key]=e}return c.spanName=e.name,c.spanKind=e.kind,e.status?.message&&(c.statusMessage=e.status.message),{timestamp:n,level:i,message:`[SPAN] ${e.name}`,traceId:e.traceId,spanId:e.spanId,parentSpanId:e.parentSpanId??null,service:t,hostname:null,pid:null,metadata:c,errorType:a??null,errorMessage:o??null,errorStack:s??null}}function Ee(e){let n=new d.Hono,r=e.get(t.m.LogStorageService);n.use(`*`,(0,p.cors)({origin:e=>e??null,credentials:!0,allowMethods:[`GET`,`POST`,`OPTIONS`],allowHeaders:[`Content-Type`,`Accept`,`Authorization`]})),n.get(`/health`,async e=>{try{return e.json({status:`healthy`,service:`log-sink-mcp-http`,serviceName:`log-sink-mcp-http`,timestamp:new Date().toISOString()})}catch(t){return e.json({status:`unhealthy`,error:t instanceof Error?t.message:String(t)},503)}});let i=(0,f.rateLimiter)({windowMs:60*1e3,limit:100,standardHeaders:`draft-6`,keyGenerator:e=>e.req.header(`x-forwarded-for`)||e.req.header(`x-real-ip`)||`unknown`});n.post(`/logs`,i,async e=>{try{let t=W(e.req.header(`content-length`));if(t)return e.json({success:!1,error:t},413);let n=await G(e),i=ve.safeParse(n);if(!i.success)return e.json({success:!1,error:`Validation failed`,details:i.error.issues},400);let{logs:a}=i.data,o=a.map(e=>({...e,timestamp:e.timestamp?new Date(e.timestamp):new Date})),s=await r.insertBatch(o);return e.json({success:!0,count:s.length,message:`Successfully inserted ${s.length} logs`},201)}catch(t){let n=t instanceof Error?t.message:String(t);return n.startsWith(`Invalid JSON body`)?e.json({success:!1,error:n},400):(console.error(`Failed to insert logs:`,t),e.json({success:!1,error:`Failed to insert logs`},500))}}),n.post(`/v1/traces`,i,async e=>{try{let t=W(e.req.header(`content-length`));if(t)return e.json({success:!1,error:t},413);let n=await G(e);ye(n);let i=[];for(let e of n.resourceSpans){let t=xe(e);for(let n of e.scopeSpans)for(let e of n.spans){let n=Te(e,t);i.push(n)}}let a=await r.insertBatch(i);return e.json({success:!0,count:a.length,message:`Successfully inserted ${a.length} trace spans as logs`},201)}catch(t){let n=t instanceof Error?t.message:String(t);return n.startsWith(`Invalid JSON body`)||n.startsWith(`Invalid OTLP`)||n.startsWith(`OTLP`)?e.json({success:!1,error:n},400):(console.error(`Failed to insert OTLP traces:`,t),e.json({success:!1,error:`Failed to insert OTLP traces`},500))}}),n.post(`/v1/logs`,i,async e=>{try{let t=W(e.req.header(`content-length`));if(t)return e.json({success:!1,error:t},413);let n=await G(e);be(n);let i=[];for(let e of n.resourceLogs){let t=Se(e);for(let n of e.scopeLogs)for(let e of n.logRecords){let n=we(e,t);i.push(n)}}let a=await r.insertBatch(i);return e.json({success:!0,count:a.length,message:`Successfully inserted ${a.length} OTLP logs`},201)}catch(t){let n=t instanceof Error?t.message:String(t);return n.startsWith(`Invalid JSON body`)||n.startsWith(`Invalid OTLP`)||n.startsWith(`OTLP`)?e.json({success:!1,error:n},400):(console.error(`Failed to insert OTLP logs:`,t),e.json({success:!1,error:`Failed to insert OTLP logs`},500))}});let a=oe(e);n.route(`/api`,a);let o=ge(e);return n.route(`/`,o),n}function q(e,t){if(e===void 0||e===``)return t;let n=Number.parseInt(e,10);if(!Number.isFinite(n)||n<=0)throw Error(`Invalid database retention value: ${e}`);return n}function J(e={}){let t=q(e.dbMaxBytes??process.env.LOG_SINK_DB_MAX_BYTES,268435456),n=q(e.dbTargetBytes??process.env.LOG_SINK_DB_TARGET_BYTES,Math.floor(t*.9));return{maxBytes:t,targetBytes:Math.min(n,t),intervalMs:q(e.dbRetentionIntervalMs??process.env.LOG_SINK_DB_RETENTION_INTERVAL_MS,3e5),batchSize:q(e.dbRetentionBatchSize??process.env.LOG_SINK_DB_RETENTION_BATCH_SIZE,1e3)}}const De=String(s.DEFAULT_PORT_RANGE.min),Oe=t.f(),ke=new l.Command(`http-serve`).description(`Start HTTP server for log ingestion with configurable port, database path, and in-memory mode`).option(`-p, --port <port>`,`Port to listen on`,De).option(`--db-path <path>`,`Path to SQLite database file`,Oe).option(`--in-memory`,`Use in-memory database (for testing)`,!1).option(`--db-max-bytes <bytes>`,`Maximum SQLite database size before trimming`).option(`--db-target-bytes <bytes>`,`Target SQLite database size after trimming`).option(`--db-retention-interval-ms <ms>`,`How often to check database size`,`300000`).option(`--db-retention-batch-size <count>`,`Number of oldest log rows to delete per trim batch`,`1000`).option(`--registry-path <path>`,`Custom registry path or directory for service discovery`).action(async e=>{let n;try{let r=Number.parseInt(e.port,10),i={min:s.DEFAULT_PORT_RANGE.min,max:Math.max(s.DEFAULT_PORT_RANGE.max??4999,r)},a=process.env.NODE_ENV||`development`,o=t.p(process.cwd()),l=`log-sink-mcp-http`;e.registryPath&&(process.env.PORT_REGISTRY_PATH=e.registryPath,process.env.PROCESS_REGISTRY_PATH=(0,c.resolveSiblingRegistryPath)(e.registryPath,`processes.json`)??process.env.PROCESS_REGISTRY_PATH);let d=new s.PortRegistryService(process.env.PORT_REGISTRY_PATH),f=t.u(),p=f.get(t.m.LogStorageService),m=f.get(t.m.LogRetentionService);await p.initializeDatabase(e.dbPath,e.inMemory);let h=m.startSizeRetentionMonitor(J({dbMaxBytes:e.dbMaxBytes,dbTargetBytes:e.dbTargetBytes,dbRetentionIntervalMs:e.dbRetentionIntervalMs,dbRetentionBatchSize:e.dbRetentionBatchSize})),g=Ee(f),_=await d.reservePort({repositoryPath:o,serviceName:l,serviceType:`tool`,environment:a,preferredPort:r,pid:process.pid,host:`127.0.0.1`,force:!0,portRange:i,metadata:{healthCheckUrl:`http://localhost:${r}/health`,dbPath:e.dbPath}});if(!_.success||!_.record)throw Error(_.error||`Failed to reserve service in global registry`);let v=_.record.port;if(v!==r){let t=await d.reservePort({repositoryPath:o,serviceName:l,serviceType:`tool`,environment:a,preferredPort:v,pid:process.pid,host:`127.0.0.1`,force:!0,portRange:i,metadata:{healthCheckUrl:`http://localhost:${v}/health`,dbPath:e.dbPath}});if(!t.success||!t.record)throw Error(t.error||`Failed to update service metadata in registry`);_=t}if(!_.record)throw Error(`Port reservation lost before startup`);let y=_.record.port;n=await(0,c.createProcessLease)({repositoryPath:o,serviceName:l,serviceType:`tool`,environment:a,pid:process.pid,port:y,host:`127.0.0.1`,command:process.argv[1],args:process.argv.slice(2),metadata:{dbPath:e.dbPath,transport:`http`}});let b;try{b=(0,u.serve)({fetch:g.fetch,port:y})}catch(e){try{await n.release({kill:!1})}catch{}throw e}let x=async()=>{try{b.close();try{await n?.release({kill:!1})}catch{}h(),await p.disconnect(),process.exit(0)}catch{process.exit(1)}};process.on(`SIGINT`,()=>x()),process.on(`SIGTERM`,()=>x())}catch{try{await n?.release({kill:!1})}catch{}process.exit(1)}}),Ae=t.f(),Y=new Set(Object.values(g)),je=new Set([`level`,`service`,`both`]),Me={stdout:e=>console.log(e),stderr:e=>console.error(e)};function X(e){let t=Number.parseInt(e,10);if(!Number.isInteger(t)||t<=0)throw new l.InvalidArgumentError(`Expected a positive integer.`);return t}function Ne(e){if(!je.has(e))throw new l.InvalidArgumentError(`Expected one of: 'level', 'service', 'both'.`);return e}function Z(e){if(!(!e||e.length===0))return e.map(e=>{if(!Y.has(e))throw new l.InvalidArgumentError(`Invalid log level '${e}'. Expected one of: ${Array.from(Y).join(`, `)}`);return e})}function Pe(e){return e.content.map(e=>e.type===`text`?e.text:JSON.stringify(e)).join(`
|
|
586
|
+
`)}function Q(e){return e.option(`--db-path <path>`,`Path to SQLite database file`,Ae).option(`--in-memory`,`Use in-memory database`,!1)}async function Fe(e,n){let r=t.u(),i=r.get(t.m.LogStorageService);await i.initializeDatabase(e.dbPath,e.inMemory);try{return await n(r)}finally{await i.disconnect()}}async function Ie(e,t,n,r=Me){try{let i=await Fe(e,async e=>t(e).execute(n)),a=Pe(i);return i.isError?(r.stderr(a),1):(r.stdout(a),0)}catch(e){return r.stderr(`Error executing logs command: ${e instanceof Error?e.message:String(e)}`),1}}async function $(e,t,n){let r=await Ie(e,t,n);r!==0&&process.exit(r)}function Le(e,t){if(!(!e&&!t)){if(!e||!t)throw new l.InvalidArgumentError(`Provide both --start-time and --end-time together.`);return{start:e,end:t}}}function Re(){let e=new l.Command(`logs`).description(`Run log analysis commands that mirror MCP tool capabilities`),n=Q(new l.Command(`query`).alias(`query-logs`).description(`Query and filter log entries by level, trace ID, service, or time range`).option(`--level <level...>`,`Log level(s) to filter by`).option(`--trace-id <traceId>`,`Trace ID to filter by`).option(`--service <service...>`,`Service name(s) to filter by`).option(`--start-time <iso8601>`,`Start time for log range (ISO 8601)`).option(`--end-time <iso8601>`,`End time for log range (ISO 8601)`).option(`--limit <number>`,`Maximum number of log entries to return`,X).action(async e=>{await $(e,e=>new t.i(e),{level:Z(e.level),traceId:e.traceId,service:e.service,startTime:e.startTime,endTime:e.endTime,limit:e.limit})})),r=Q(new l.Command(`search`).alias(`search-logs`).description(`Search log entries with full-text search and optional filters`).argument(`<search-query>`,`FTS5 search query`).option(`--mode <mode>`,`Search strategy: fts, semantic, or hybrid`,`hybrid`).option(`--service <service...>`,`Service name(s) to filter by`).option(`--level <level...>`,`Log level(s) to filter by`).option(`--start-time <iso8601>`,`Start time for log range (ISO 8601)`).option(`--end-time <iso8601>`,`End time for log range (ISO 8601)`).option(`--limit <number>`,`Maximum number of search results to return`,X).action(async(e,n)=>{await $(n,e=>new t.r(e),{searchQuery:e,mode:n.mode,service:n.service,level:Z(n.level),startTime:n.startTime,endTime:n.endTime,limit:n.limit})})),i=Q(new l.Command(`trace`).alias(`get-trace-timeline`).description(`Get the complete trace timeline for a trace ID`).argument(`<trace-id>`,`Trace ID to inspect`).action(async(e,n)=>{await $(n,e=>new t.a(e),{traceId:e})})),a=Q(new l.Command(`analyze-errors`).alias(`errors`).description(`Analyze error patterns and group similar errors`).option(`--trace-id <traceId>`,`Optional trace ID to scope the analysis`).option(`--start-time <iso8601>`,`Start time for error analysis (ISO 8601)`).option(`--end-time <iso8601>`,`End time for error analysis (ISO 8601)`).option(`--limit <number>`,`Maximum number of error entries to analyze`,X).action(async e=>{await $(e,e=>new t.l(e),{traceId:e.traceId,timeRange:Le(e.startTime,e.endTime),limit:e.limit})})),o=Q(new l.Command(`stats`).alias(`get-log-stats`).description(`Get aggregated log statistics grouped by level, service, or both`).option(`--start-time <iso8601>`,`Start time for statistics (ISO 8601)`).option(`--end-time <iso8601>`,`End time for statistics (ISO 8601)`).option(`--group-by <groupBy>`,`Group statistics by level, service, or both`,Ne).action(async e=>{await $(e,e=>new t.s(e),{startTime:e.startTime,endTime:e.endTime,groupBy:e.groupBy})})),s=Q(new l.Command(`services`).alias(`get-services`).description(`Get the list of unique services present in the log database`).action(async e=>{await $(e,e=>new t.o(e),{})})),c=Q(new l.Command(`clear`).alias(`clear-logs`).description(`Clear all logs from the database`).action(async e=>{await $(e,e=>new t.c(e),{})}));return e.addCommand(n).addCommand(r).addCommand(i).addCommand(a).addCommand(o).addCommand(s).addCommand(c)}const ze=Re();function Be(){return t.f()}const Ve=new l.Command(`mcp-serve`).description(`Start MCP server with stdio transport`).option(`--cleanup`,`Stop HTTP server on MCP server shutdown`,!1).option(`--db-path <path>`,`Path to SQLite database file`,Be()).option(`--in-memory`,`Use in-memory database (for testing)`,!1).option(`--db-max-bytes <bytes>`,`Maximum SQLite database size before trimming`).option(`--db-target-bytes <bytes>`,`Target SQLite database size after trimming`).option(`--db-retention-interval-ms <ms>`,`How often to check database size`,`300000`).option(`--db-retention-batch-size <count>`,`Number of oldest log rows to delete per trim batch`,`1000`).option(`--registry-path <path>`,`Custom registry path or directory for service discovery`).option(`--registry-dir <path>`,`Custom registry directory for service discovery`).action(async e=>{let n;try{let r=e.registryPath||e.registryDir;r&&(process.env.PORT_REGISTRY_PATH=r,process.env.PROCESS_REGISTRY_PATH=(0,c.resolveSiblingRegistryPath)(r,`processes.json`)??process.env.PROCESS_REGISTRY_PATH);let i=t.u(),a=i.get(t.m.LogStorageService),o=i.get(t.m.LogRetentionService),s=i.get(t.m.HttpServerManager);await a.initializeDatabase(e.dbPath,e.inMemory);let l=o.startSizeRetentionMonitor(J({dbMaxBytes:e.dbMaxBytes,dbTargetBytes:e.dbTargetBytes,dbRetentionIntervalMs:e.dbRetentionIntervalMs,dbRetentionBatchSize:e.dbRetentionBatchSize})),u=new t.t(t.n(i));n=await(0,c.createProcessLease)({repositoryPath:process.cwd(),serviceName:`log-sink-mcp-mcp-serve`,serviceType:`tool`,environment:process.env.NODE_ENV||`development`,pid:process.pid,host:`127.0.0.1`,command:process.argv[1],args:process.argv.slice(2),metadata:{transport:`stdio`,command:`mcp-serve`}});let d=s.ensureRunning(void 0,e.dbPath),f;d.then(t=>{t.running&&(f=s.startHealthMonitor(e.dbPath))}).catch(()=>void 0);let p=async t=>{console.error(`\nReceived ${t}, shutting down gracefully...`);try{f?.(),await u.stop(),e.cleanup&&(await d.catch(()=>({running:!1}))).running&&(await s.stop(),console.error(`HTTP server stopped`)),l(),await a.disconnect(),await n?.release(),process.exit(0)}catch(e){console.error(`Error during shutdown:`,e),process.exit(1)}};process.on(`SIGINT`,()=>p(`SIGINT`)),process.on(`SIGTERM`,()=>p(`SIGTERM`)),await u.start()}catch(e){await n?.release().catch(()=>void 0),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),He=new l.Command(`start`).description(`Start HTTP and/or MCP servers with singleton coordination`).option(`--mcp-only`,`Start only the MCP server (stdio transport)`,!1).option(`--http-only`,`Start only the HTTP server`,!1).option(`-p, --port <port>`,`Port for HTTP server`,String(s.DEFAULT_PORT_RANGE.min)).option(`--db-path <path>`,`Path to SQLite database file`,t.f()).option(`--in-memory`,`Use in-memory database (for testing)`,!1).option(`--db-max-bytes <bytes>`,`Maximum SQLite database size before trimming`).option(`--db-target-bytes <bytes>`,`Target SQLite database size after trimming`).option(`--db-retention-interval-ms <ms>`,`How often to check database size`,`300000`).option(`--db-retention-batch-size <count>`,`Number of oldest log rows to delete per trim batch`,`1000`).option(`--registry-path <path>`,`Custom registry path or directory for service discovery`).option(`--registry-dir <path>`,`Custom registry directory for service discovery`).action(async e=>{let n;try{let r=e.registryPath||e.registryDir;r&&(process.env.PORT_REGISTRY_PATH=r,process.env.PROCESS_REGISTRY_PATH=(0,c.resolveSiblingRegistryPath)(r,`processes.json`)??process.env.PROCESS_REGISTRY_PATH),e.dbMaxBytes&&(process.env.LOG_SINK_DB_MAX_BYTES=e.dbMaxBytes),e.dbTargetBytes&&(process.env.LOG_SINK_DB_TARGET_BYTES=e.dbTargetBytes),e.dbRetentionIntervalMs&&(process.env.LOG_SINK_DB_RETENTION_INTERVAL_MS=e.dbRetentionIntervalMs),e.dbRetentionBatchSize&&(process.env.LOG_SINK_DB_RETENTION_BATCH_SIZE=e.dbRetentionBatchSize);let i=t.u(),a=i.get(t.m.LogStorageService);await a.initializeDatabase(e.dbPath,e.inMemory);let o=Number.parseInt(e.port,10),s=!e.mcpOnly,l=!e.httpOnly,u=i.get(t.m.LogRetentionService),d=l?u.startSizeRetentionMonitor(J({dbMaxBytes:e.dbMaxBytes,dbTargetBytes:e.dbTargetBytes,dbRetentionIntervalMs:e.dbRetentionIntervalMs,dbRetentionBatchSize:e.dbRetentionBatchSize})):()=>void 0;if(console.log(`🚀 Starting log-sink-mcp services...`),console.log(` Database: ${e.inMemory?`In-Memory`:e.dbPath}`),s){let n=await i.get(t.m.HttpServerManager).ensureRunning(o,e.dbPath);n.running?(console.log(`✓ HTTP Server: Running on http://localhost:${n.port} (PID: ${n.pid})`),console.log(` Health check: http://localhost:${n.port}/health`),console.log(` Log ingestion: POST http://localhost:${n.port}/logs`)):(console.error(`✗ HTTP Server failed to start: ${n.error}`),l||process.exit(1))}if(l){n=await(0,c.createProcessLease)({repositoryPath:process.cwd(),serviceName:`log-sink-mcp-start`,serviceType:`tool`,environment:process.env.NODE_ENV||`development`,pid:process.pid,host:`127.0.0.1`,command:process.argv[1],args:process.argv.slice(2),metadata:{transport:`stdio`,command:`start`}}),console.log(`✓ MCP Server: Starting with stdio transport...`);let e=new t.t(t.n(i));await e.start(),console.log(`✓ MCP Server: Ready for connections`);let r=async r=>{console.log(`\n\n${r} received. Shutting down gracefully...`);try{await e.stop(),console.log(`✓ MCP server stopped`),s&&(await i.get(t.m.HttpServerManager).stop(),console.log(`✓ HTTP server stopped`)),d(),await a.disconnect(),console.log(`✓ Database disconnected`),await n?.release(),console.log(`✓ Process registry entry released`),console.log(`Goodbye! 👋`),process.exit(0)}catch(e){console.error(`Error during shutdown:`,e),process.exit(1)}};process.on(`SIGINT`,()=>r(`SIGINT`)),process.on(`SIGTERM`,()=>r(`SIGTERM`)),console.log(`
|
|
902
587
|
Press Ctrl+C to stop the server`)}else console.log(`
|
|
903
|
-
✓ HTTP server started in background`),console.log(`Use "log-sink-mcp stop" to stop the HTTP server`),n&&await n.release().catch(()=>void 0),process.exit(0)}catch(e){n&&await n.release().catch(()=>void 0),console.error(`Error starting services:`,e),process.exit(1)}}),
|
|
904
|
-
`),console.log(`─`.repeat(50));let e=await t.u().get(t.m.HttpServerManager).getStatus();e.running?(console.log(`HTTP Server: 🟢 Running`),console.log(` PID: ${e.pid}`),console.log(` Port: ${e.port}`),console.log(` Health: http://localhost:${e.port}/health`)):(console.log(`HTTP Server: 🔴 Not Running`),e.error&&console.log(` Error: ${e.error}`)),console.log(``);try{let e=t.f(),n=((await
|
|
588
|
+
✓ HTTP server started in background`),console.log(`Use "log-sink-mcp stop" to stop the HTTP server`),n&&await n.release().catch(()=>void 0),process.exit(0)}catch(e){n&&await n.release().catch(()=>void 0),console.error(`Error starting services:`,e),process.exit(1)}}),Ue=new l.Command(`status`).description(`Show status of HTTP server and diagnostics`).action(async()=>{try{console.log(`📊 log-sink-mcp Status
|
|
589
|
+
`),console.log(`─`.repeat(50));let e=await t.u().get(t.m.HttpServerManager).getStatus();e.running?(console.log(`HTTP Server: 🟢 Running`),console.log(` PID: ${e.pid}`),console.log(` Port: ${e.port}`),console.log(` Health: http://localhost:${e.port}/health`)):(console.log(`HTTP Server: 🔴 Not Running`),e.error&&console.log(` Error: ${e.error}`)),console.log(``);try{let e=t.f(),n=((await i.stat(e)).size/1024/1024).toFixed(2);console.log(`Database: ${e} (${n} MB)`)}catch{console.log(`Database: Not found or not accessible`)}console.log(`─`.repeat(50)),process.exit(0)}catch(e){console.error(`Error getting status:`,e),process.exit(1)}}),We=new l.Command(`stop`).description(`Stop HTTP server and clean up registry/PID files`).action(async()=>{try{console.log(`🛑 Stopping log-sink-mcp services...`),await t.u().get(t.m.HttpServerManager).stop()?(console.log(`✓ HTTP server stopped`),console.log(`✓ Registry and PID files cleaned up`)):console.log(`ℹ No HTTP server was running`),console.log(`Done! 👋`),process.exit(0)}catch(e){console.error(`Error stopping services:`,e),process.exit(1)}}),Ge=(0,a.dirname)((0,o.fileURLToPath)(require(`url`).pathToFileURL(__filename).href)),Ke=JSON.parse((0,r.readFileSync)((0,a.join)(Ge,`../package.json`),`utf-8`));async function qe(){let e=new l.Command;e.name(`log-sink-mcp`).description(`Log sink MCP server with HTTP ingestion and AI analysis`).version(Ke.version),e.addCommand(ie),e.addCommand(He),e.addCommand(We),e.addCommand(Ue),e.addCommand(ke),e.addCommand(Ve),e.addCommand(ze),await e.parseAsync(process.argv)}qe();
|
|
905
590
|
//# sourceMappingURL=cli.cjs.map
|