embark-cli 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/.claude/CLAUDE.md +33 -0
  2. package/.claude/settings.local.json +32 -0
  3. package/.github/WORKFLOWS.md +147 -0
  4. package/.github/workflows/ci.yml +49 -0
  5. package/.github/workflows/publish.yml +109 -0
  6. package/.idea/embark-remote-mcp.iml +9 -0
  7. package/.idea/encodings.xml +4 -0
  8. package/.idea/indexLayout.xml +8 -0
  9. package/.idea/vcs.xml +6 -0
  10. package/.mcp.json +14 -0
  11. package/GIT_DISCOVERY.md +231 -0
  12. package/INTEGRATION_TESTING.md +243 -0
  13. package/MULTI_REPOSITORY_SEARCH.md +242 -0
  14. package/README.md +434 -0
  15. package/dist/auth/auth-helper.d.ts +3 -0
  16. package/dist/auth/auth-helper.d.ts.map +1 -0
  17. package/dist/auth/auth-helper.js +171 -0
  18. package/dist/auth/auth-helper.js.map +1 -0
  19. package/dist/auth/index.d.ts +4 -0
  20. package/dist/auth/index.d.ts.map +1 -0
  21. package/dist/auth/index.js +24 -0
  22. package/dist/auth/index.js.map +1 -0
  23. package/dist/auth/jba-login.d.ts +17 -0
  24. package/dist/auth/jba-login.d.ts.map +1 -0
  25. package/dist/auth/jba-login.js +345 -0
  26. package/dist/auth/jba-login.js.map +1 -0
  27. package/dist/auth/types.d.ts +16 -0
  28. package/dist/auth/types.d.ts.map +1 -0
  29. package/dist/auth/types.js +3 -0
  30. package/dist/auth/types.js.map +1 -0
  31. package/dist/config.d.ts +26 -0
  32. package/dist/config.d.ts.map +1 -0
  33. package/dist/config.js +54 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/embark-client.d.ts +56 -0
  36. package/dist/embark-client.d.ts.map +1 -0
  37. package/dist/embark-client.js +543 -0
  38. package/dist/embark-client.js.map +1 -0
  39. package/dist/git-utils.d.ts +47 -0
  40. package/dist/git-utils.d.ts.map +1 -0
  41. package/dist/git-utils.js +232 -0
  42. package/dist/git-utils.js.map +1 -0
  43. package/dist/handlers.d.ts +80 -0
  44. package/dist/handlers.d.ts.map +1 -0
  45. package/dist/handlers.js +301 -0
  46. package/dist/handlers.js.map +1 -0
  47. package/dist/index.d.ts +3 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +165 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/logger.d.ts +4 -0
  52. package/dist/logger.d.ts.map +1 -0
  53. package/dist/logger.js +92 -0
  54. package/dist/logger.js.map +1 -0
  55. package/dist/stats-server.d.ts +3 -0
  56. package/dist/stats-server.d.ts.map +1 -0
  57. package/dist/stats-server.js +623 -0
  58. package/dist/stats-server.js.map +1 -0
  59. package/dist/stats.d.ts +118 -0
  60. package/dist/stats.d.ts.map +1 -0
  61. package/dist/stats.js +206 -0
  62. package/dist/stats.js.map +1 -0
  63. package/dist/tools.d.ts +9 -0
  64. package/dist/tools.d.ts.map +1 -0
  65. package/dist/tools.js +62 -0
  66. package/dist/tools.js.map +1 -0
  67. package/package.json +47 -0
  68. package/test-git-discovery.mjs +322 -0
  69. package/test-multi-repo-filters.mjs +151 -0
  70. package/test-multiple-roots.mjs +436 -0
  71. package/test-roots.mjs +306 -0
  72. package/test-snippet-extraction.mjs +136 -0
  73. package/watch-logs.sh +78 -0
@@ -0,0 +1,623 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startStatsServer = startStatsServer;
7
+ const http_1 = __importDefault(require("http"));
8
+ const url_1 = require("url");
9
+ const stats_js_1 = require("./stats.js");
10
+ async function startStatsServer(port) {
11
+ const server = http_1.default.createServer((req, res) => {
12
+ if (!req.url) {
13
+ res.writeHead(400, { 'content-type': 'text/plain' });
14
+ res.end('Invalid request');
15
+ return;
16
+ }
17
+ const requestUrl = new url_1.URL(req.url, `http://localhost:${port}`);
18
+ if (requestUrl.pathname === '/stats.json') {
19
+ const summary = buildStatsSummary();
20
+ res.writeHead(200, { 'content-type': 'application/json' });
21
+ res.end(JSON.stringify(summary));
22
+ return;
23
+ }
24
+ res.writeHead(200, { 'content-type': 'text/html' });
25
+ res.end(renderHtml());
26
+ });
27
+ return await new Promise((resolve, reject) => {
28
+ const onError = (error) => {
29
+ reject(error);
30
+ };
31
+ server.once('error', onError);
32
+ server.listen(port, () => {
33
+ const actualPort = resolvePort(server.address(), port);
34
+ console.error(`[embark-mcp] Stats dashboard available at http://localhost:${actualPort}`);
35
+ console.error(`[embark-mcp] Reading stats from ${stats_js_1.STATS_DIR}`);
36
+ server.off('error', onError);
37
+ resolve(server);
38
+ });
39
+ });
40
+ }
41
+ function resolvePort(address, fallback) {
42
+ if (address && typeof address === 'object') {
43
+ return address.port;
44
+ }
45
+ return fallback;
46
+ }
47
+ function buildStatsSummary() {
48
+ const days = (0, stats_js_1.loadAllStatsDays)();
49
+ const daySummaries = days.map(summarizeDay);
50
+ const totals = daySummaries.reduce((acc, day) => {
51
+ acc.totalInitializations += day.initializationCount;
52
+ acc.totalSearches += day.searchCount;
53
+ acc.totalSemanticSearches += day.semanticSearchCount;
54
+ acc.totalDependencySearches += day.dependencySearchCount;
55
+ acc.totalEstimatedTokens += day.estimatedTokens;
56
+ acc.totalDurationMs += day.totalDurationMs;
57
+ acc.totalErrors += day.errorCount;
58
+ Object.entries(day.errorStatusCounts).forEach(([status, count]) => {
59
+ acc.errorStatusCounts[status] = (acc.errorStatusCounts[status] || 0) + count;
60
+ });
61
+ return acc;
62
+ }, {
63
+ totalInitializations: 0,
64
+ totalSearches: 0,
65
+ totalSemanticSearches: 0,
66
+ totalDependencySearches: 0,
67
+ totalEstimatedTokens: 0,
68
+ totalDurationMs: 0,
69
+ averageDurationMs: 0,
70
+ totalErrors: 0,
71
+ errorStatusCounts: {},
72
+ });
73
+ totals.averageDurationMs = totals.totalSearches === 0
74
+ ? 0
75
+ : totals.totalDurationMs / totals.totalSearches;
76
+ const allEvents = days.flatMap((day) => day.events);
77
+ const allErrorEvents = allEvents.filter((event) => event.type === 'error');
78
+ const recentEvents = allEvents
79
+ .sort((a, b) => b.timestamp.localeCompare(a.timestamp))
80
+ .slice(0, 50);
81
+ const recentErrors = allErrorEvents
82
+ .sort((a, b) => b.timestamp.localeCompare(a.timestamp))
83
+ .slice(0, 50);
84
+ const repositoryUsage = buildRepositoryUsage(allEvents);
85
+ const clientUsage = buildClientUsage(allEvents);
86
+ return {
87
+ generatedAt: new Date().toISOString(),
88
+ statsDir: stats_js_1.STATS_DIR,
89
+ days: daySummaries,
90
+ totals,
91
+ recentEvents,
92
+ repositoryUsage,
93
+ clientUsage,
94
+ recentErrors,
95
+ };
96
+ }
97
+ function summarizeDay(day) {
98
+ const searchEvents = day.events.filter((event) => event.type === 'search');
99
+ const initializationCount = day.events.filter((event) => event.type === 'initialization').length;
100
+ const semanticSearchCount = searchEvents.filter((event) => event.searchKind === 'semantic').length;
101
+ const dependencySearchCount = searchEvents.filter((event) => event.searchKind === 'dependencies').length;
102
+ const estimatedTokens = searchEvents.reduce((sum, event) => sum + (event.estimatedTokens || 0), 0);
103
+ const totalDurationMs = searchEvents.reduce((sum, event) => sum + (event.durationMs || 0), 0);
104
+ const apiEvents = day.events.filter((event) => event.type === 'api_call');
105
+ const errorEvents = day.events.filter((event) => event.type === 'error');
106
+ const errorStatusCounts = {};
107
+ const registerStatus = (status) => {
108
+ if (!status) {
109
+ return;
110
+ }
111
+ const key = status.toString();
112
+ errorStatusCounts[key] = (errorStatusCounts[key] || 0) + 1;
113
+ };
114
+ searchEvents.forEach((event) => {
115
+ if (!event.success) {
116
+ registerStatus(event.statusCode);
117
+ }
118
+ });
119
+ apiEvents.forEach((event) => {
120
+ if (!event.success) {
121
+ registerStatus(event.statusCode);
122
+ }
123
+ });
124
+ return {
125
+ date: day.date,
126
+ initializationCount,
127
+ searchCount: searchEvents.length,
128
+ semanticSearchCount,
129
+ dependencySearchCount,
130
+ estimatedTokens,
131
+ totalDurationMs,
132
+ averageDurationMs: searchEvents.length === 0 ? 0 : totalDurationMs / searchEvents.length,
133
+ errorStatusCounts,
134
+ errorCount: errorEvents.length,
135
+ };
136
+ }
137
+ function buildRepositoryUsage(allEvents) {
138
+ const repoMap = {};
139
+ const register = (repo, kind) => {
140
+ if (!repo)
141
+ return;
142
+ if (!repoMap[repo]) {
143
+ repoMap[repo] = {
144
+ repositoryUrl: repo,
145
+ searchCount: 0,
146
+ semanticCount: 0,
147
+ dependencyCount: 0,
148
+ };
149
+ }
150
+ repoMap[repo].searchCount += 1;
151
+ if (kind === 'semantic') {
152
+ repoMap[repo].semanticCount += 1;
153
+ }
154
+ else {
155
+ repoMap[repo].dependencyCount += 1;
156
+ }
157
+ };
158
+ allEvents.forEach((event) => {
159
+ if (event.type !== 'search')
160
+ return;
161
+ (event.repositoryUrls || []).forEach((repo) => register(repo, event.searchKind));
162
+ });
163
+ return Object.values(repoMap).sort((a, b) => b.searchCount - a.searchCount);
164
+ }
165
+ function buildClientUsage(allEvents) {
166
+ const clientMap = {};
167
+ const register = (event) => {
168
+ const clientType = (event.clientType || 'unknown').toLowerCase();
169
+ const label = clientType === 'unknown' ? 'unknown' : event.clientType;
170
+ if (!clientMap[label]) {
171
+ clientMap[label] = { clientType: label, eventCount: 0, searchCount: 0 };
172
+ }
173
+ clientMap[label].eventCount += 1;
174
+ if (event.type === 'search') {
175
+ clientMap[label].searchCount += 1;
176
+ }
177
+ };
178
+ allEvents.forEach(register);
179
+ return Object.values(clientMap).sort((a, b) => b.eventCount - a.eventCount);
180
+ }
181
+ function renderHtml() {
182
+ return `<!DOCTYPE html>
183
+ <html lang="en">
184
+ <head>
185
+ <meta charset="UTF-8" />
186
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
187
+ <title>Embark MCP Stats</title>
188
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
189
+ <style>
190
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; margin: 0; padding: 0; background: #0b1221; color: #f5f7ff; }
191
+ header { padding: 24px; background: linear-gradient(135deg, #1d2b53, #274060); box-shadow: 0 2px 6px rgba(0,0,0,0.4); }
192
+ h1 { margin: 0; font-size: 24px; }
193
+ main { padding: 24px; }
194
+ .grid { display: grid; gap: 16px; }
195
+ .cards { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
196
+ .card { background: #151d32; padding: 16px; border-radius: 12px; box-shadow: inset 0 0 0 1px rgba(255,255,255,0.05); }
197
+ .card h2 { margin: 0 0 8px 0; font-size: 14px; text-transform: uppercase; letter-spacing: 0.1em; color: #8aa2ff; }
198
+ .card p { margin: 0; font-size: 28px; font-weight: 600; }
199
+ section { margin-top: 32px; }
200
+ .chart-container { position: relative; background: #0f172a; border-radius: 12px; padding: 16px; height: 320px; max-height: 60vh; min-height: 200px; box-shadow: inset 0 0 0 1px rgba(255,255,255,0.05); box-sizing: border-box; overflow: hidden; }
201
+ canvas { width: 100% !important; height: 100% !important; }
202
+ .muted { color: rgba(255,255,255,0.7); font-size: 13px; margin: 8px 0 0 0; }
203
+ details summary { cursor: pointer; color: #8aa2ff; }
204
+ table { width: 100%; border-collapse: collapse; margin-top: 12px; }
205
+ th, td { padding: 8px 12px; border-bottom: 1px solid rgba(255,255,255,0.1); text-align: left; }
206
+ th { color: #8aa2ff; font-weight: 600; }
207
+ .events { max-height: 320px; overflow-y: auto; }
208
+ .event { padding: 12px; border-bottom: 1px solid rgba(255,255,255,0.08); }
209
+ .event strong { display: block; font-size: 14px; color: #8aa2ff; }
210
+ footer { padding: 16px 24px 32px; color: rgba(255,255,255,0.6); font-size: 14px; }
211
+ a { color: #8aa2ff; }
212
+ </style>
213
+ </head>
214
+ <body>
215
+ <header>
216
+ <h1>Embark MCP Stats Dashboard</h1>
217
+ <p>Live metrics for local MCP usage. Data refreshes every 15 seconds.</p>
218
+ </header>
219
+ <main>
220
+ <div class="grid cards">
221
+ <div class="card">
222
+ <h2>Total Searches</h2>
223
+ <p id="total-searches">0</p>
224
+ </div>
225
+ <div class="card">
226
+ <h2>Semantic Searches</h2>
227
+ <p id="semantic-searches">0</p>
228
+ </div>
229
+ <div class="card">
230
+ <h2>Dependency Searches</h2>
231
+ <p id="dependency-searches">0</p>
232
+ </div>
233
+ <div class="card">
234
+ <h2>Estimated Query Tokens</h2>
235
+ <p id="total-tokens">0</p>
236
+ </div>
237
+ <div class="card">
238
+ <h2>Avg Duration (ms)</h2>
239
+ <p id="avg-duration">0</p>
240
+ </div>
241
+ <div class="card">
242
+ <h2>Initializations</h2>
243
+ <p id="initializations">0</p>
244
+ </div>
245
+ <div class="card">
246
+ <h2>Error Events</h2>
247
+ <p id="total-errors">0</p>
248
+ </div>
249
+ </div>
250
+
251
+ <section>
252
+ <h2>Searches per Day</h2>
253
+ <div class="chart-container">
254
+ <canvas id="searchesChart"></canvas>
255
+ </div>
256
+ </section>
257
+
258
+ <section>
259
+ <h2>Estimated Query Tokens per Day</h2>
260
+ <p style="margin: 4px 0 12px 0; color: rgba(255,255,255,0.7); font-size: 13px;">
261
+ Rough token estimate based only on search query text (words × 1.3), not on results or API responses.
262
+ </p>
263
+ <div class="chart-container">
264
+ <canvas id="tokensChart"></canvas>
265
+ </div>
266
+ </section>
267
+
268
+ <section>
269
+ <h2>Error Counts per Day</h2>
270
+ <div class="chart-container">
271
+ <canvas id="errorsChart"></canvas>
272
+ </div>
273
+ <p id="errors-empty" class="muted"></p>
274
+ <details style="margin-top: 12px;">
275
+ <summary>Details</summary>
276
+ <div id="error-details"></div>
277
+ </details>
278
+ </section>
279
+
280
+ <section>
281
+ <h2>Searches by Repository</h2>
282
+ <p class="muted">Counts include both semantic and dependency searches. Limited to top 20 repositories.</p>
283
+ <div class="chart-container">
284
+ <canvas id="repoChart"></canvas>
285
+ </div>
286
+ <p id="repo-empty" class="muted"></p>
287
+ </section>
288
+
289
+ <section>
290
+ <h2>Client Types</h2>
291
+ <p class="muted">Counts based on initialization and search events. Set env var MCP_CLIENT to override detection.</p>
292
+ <table>
293
+ <thead>
294
+ <tr>
295
+ <th>Client</th>
296
+ <th>Total Events</th>
297
+ <th>Searches</th>
298
+ </tr>
299
+ </thead>
300
+ <tbody id="client-table-body">
301
+ <tr><td colspan="3">Loading…</td></tr>
302
+ </tbody>
303
+ </table>
304
+ </section>
305
+
306
+ <section>
307
+ <h2>Error Status Codes</h2>
308
+ <table>
309
+ <thead>
310
+ <tr>
311
+ <th>Status</th>
312
+ <th>Occurrences</th>
313
+ </tr>
314
+ </thead>
315
+ <tbody id="error-table-body">
316
+ <tr><td colspan="2">No errors recorded</td></tr>
317
+ </tbody>
318
+ </table>
319
+ </section>
320
+
321
+ <section>
322
+ <h2>Recent Events</h2>
323
+ <div class="events" id="events"></div>
324
+ </section>
325
+ </main>
326
+ <footer>
327
+ Data directory: <code id="stats-dir"></code>
328
+ </footer>
329
+ <script>
330
+ let searchChart;
331
+ let tokenChart;
332
+ let repoChart;
333
+ let errorsChart;
334
+
335
+ async function refreshStats() {
336
+ try {
337
+ const response = await fetch('/stats.json');
338
+ const data = await response.json();
339
+ renderSummary(data);
340
+ renderCharts(data);
341
+ renderRepositoryUsage(data);
342
+ renderErrorsChart(data);
343
+ renderClientUsage(data);
344
+ renderErrors(data);
345
+ renderEvents(data);
346
+ } catch (error) {
347
+ console.error('Failed to load stats', error);
348
+ }
349
+ }
350
+
351
+ function renderSummary(data) {
352
+ const totals = data.totals;
353
+ document.getElementById('total-searches').textContent = totals.totalSearches;
354
+ document.getElementById('semantic-searches').textContent = totals.totalSemanticSearches;
355
+ document.getElementById('dependency-searches').textContent = totals.totalDependencySearches;
356
+ document.getElementById('total-tokens').textContent = totals.totalEstimatedTokens;
357
+ document.getElementById('avg-duration').textContent = totals.averageDurationMs.toFixed(1);
358
+ document.getElementById('initializations').textContent = totals.totalInitializations;
359
+ document.getElementById('total-errors').textContent = totals.totalErrors;
360
+ document.getElementById('stats-dir').textContent = data.statsDir;
361
+ }
362
+
363
+ function renderCharts(data) {
364
+ const labels = data.days.map((day) => day.date);
365
+ const searchCounts = data.days.map((day) => day.searchCount);
366
+ const tokenCounts = data.days.map((day) => day.estimatedTokens);
367
+ const errorCounts = data.days.map((day) => day.errorCount);
368
+
369
+ if (searchChart) searchChart.destroy();
370
+ if (tokenChart) tokenChart.destroy();
371
+ if (errorsChart) errorsChart.destroy();
372
+
373
+ const chartOptions = {
374
+ responsive: true,
375
+ maintainAspectRatio: false,
376
+ scales: {
377
+ x: { ticks: { color: '#cbd5f5' }, grid: { color: 'rgba(255,255,255,0.05)' } },
378
+ y: { ticks: { color: '#cbd5f5' }, grid: { color: 'rgba(255,255,255,0.05)' }, beginAtZero: true }
379
+ },
380
+ plugins: { legend: { labels: { color: '#cbd5f5' } } }
381
+ };
382
+
383
+ const searchCtx = document.getElementById('searchesChart');
384
+ searchChart = new Chart(searchCtx, {
385
+ type: 'bar',
386
+ data: {
387
+ labels,
388
+ datasets: [
389
+ {
390
+ label: 'Searches',
391
+ data: searchCounts,
392
+ backgroundColor: '#4f9cff',
393
+ }
394
+ ],
395
+ },
396
+ options: chartOptions,
397
+ });
398
+
399
+ const tokensCtx = document.getElementById('tokensChart');
400
+ tokenChart = new Chart(tokensCtx, {
401
+ type: 'line',
402
+ data: {
403
+ labels,
404
+ datasets: [
405
+ {
406
+ label: 'Estimated Query Tokens',
407
+ data: tokenCounts,
408
+ borderColor: '#f87171',
409
+ backgroundColor: 'rgba(248, 113, 113, 0.2)',
410
+ tension: 0.4,
411
+ }
412
+ ],
413
+ },
414
+ options: chartOptions,
415
+ });
416
+ }
417
+
418
+ function renderErrorsChart(data) {
419
+ const labels = data.days.map((day) => day.date);
420
+ const errorCounts = data.days.map((day) => day.errorCount);
421
+ const emptyState = document.getElementById('errors-empty');
422
+
423
+ if (errorsChart) {
424
+ errorsChart.destroy();
425
+ errorsChart = null;
426
+ }
427
+
428
+ const hasErrors = errorCounts.some((count) => count > 0);
429
+ if (!hasErrors) {
430
+ emptyState.textContent = 'No errors recorded.';
431
+ return;
432
+ }
433
+ emptyState.textContent = '';
434
+
435
+ const ctx = document.getElementById('errorsChart');
436
+ errorsChart = new Chart(ctx, {
437
+ type: 'bar',
438
+ data: {
439
+ labels,
440
+ datasets: [
441
+ {
442
+ label: 'Errors',
443
+ data: errorCounts,
444
+ backgroundColor: '#fbbf24',
445
+ }
446
+ ],
447
+ },
448
+ options: {
449
+ responsive: true,
450
+ maintainAspectRatio: false,
451
+ scales: {
452
+ x: { ticks: { color: '#cbd5f5' }, grid: { color: 'rgba(255,255,255,0.05)' } },
453
+ y: { ticks: { color: '#cbd5f5' }, grid: { color: 'rgba(255,255,255,0.05)' }, beginAtZero: true }
454
+ },
455
+ plugins: { legend: { labels: { color: '#cbd5f5' } } }
456
+ },
457
+ });
458
+
459
+ renderErrorDetails(data);
460
+ }
461
+
462
+ function renderRepositoryUsage(data) {
463
+ const entries = data.repositoryUsage || [];
464
+ const emptyState = document.getElementById('repo-empty');
465
+ const top = entries.slice(0, 20);
466
+
467
+ if (repoChart) {
468
+ repoChart.destroy();
469
+ repoChart = null;
470
+ }
471
+
472
+ if (top.length === 0) {
473
+ emptyState.textContent = 'No repository searches recorded yet.';
474
+ return;
475
+ }
476
+
477
+ emptyState.textContent = '';
478
+ const labels = top.map((entry) => entry.repositoryUrl);
479
+ const counts = top.map((entry) => entry.searchCount);
480
+
481
+ const ctx = document.getElementById('repoChart');
482
+ repoChart = new Chart(ctx, {
483
+ type: 'bar',
484
+ data: {
485
+ labels,
486
+ datasets: [
487
+ {
488
+ label: 'Searches',
489
+ data: counts,
490
+ backgroundColor: '#34d399',
491
+ }
492
+ ]
493
+ },
494
+ options: {
495
+ indexAxis: 'y',
496
+ responsive: true,
497
+ maintainAspectRatio: false,
498
+ scales: {
499
+ x: { ticks: { color: '#cbd5f5' }, grid: { color: 'rgba(255,255,255,0.05)' }, beginAtZero: true },
500
+ y: { ticks: { color: '#cbd5f5' }, grid: { color: 'rgba(255,255,255,0.05)' } },
501
+ },
502
+ plugins: { legend: { labels: { color: '#cbd5f5' } } }
503
+ }
504
+ });
505
+ }
506
+
507
+ function renderClientUsage(data) {
508
+ const tbody = document.getElementById('client-table-body');
509
+ const entries = data.clientUsage || [];
510
+ if (entries.length === 0) {
511
+ tbody.innerHTML = '<tr><td colspan="3">No client events recorded.</td></tr>';
512
+ return;
513
+ }
514
+ tbody.innerHTML = '';
515
+ entries.forEach((entry) => {
516
+ const row = document.createElement('tr');
517
+ const clientCell = document.createElement('td');
518
+ clientCell.textContent = entry.clientType || 'unknown';
519
+ const eventCell = document.createElement('td');
520
+ eventCell.textContent = entry.eventCount;
521
+ const searchCell = document.createElement('td');
522
+ searchCell.textContent = entry.searchCount;
523
+ row.appendChild(clientCell);
524
+ row.appendChild(eventCell);
525
+ row.appendChild(searchCell);
526
+ tbody.appendChild(row);
527
+ });
528
+ }
529
+
530
+ function renderErrors(data) {
531
+ const tbody = document.getElementById('error-table-body');
532
+ const entries = Object.entries(data.totals.errorStatusCounts);
533
+ if (entries.length === 0) {
534
+ tbody.innerHTML = '<tr><td colspan="2">No errors recorded</td></tr>';
535
+ return;
536
+ }
537
+ tbody.innerHTML = '';
538
+ entries.forEach(([status, count]) => {
539
+ const row = document.createElement('tr');
540
+ const statusCell = document.createElement('td');
541
+ statusCell.textContent = status;
542
+ const countCell = document.createElement('td');
543
+ countCell.textContent = count;
544
+ row.appendChild(statusCell);
545
+ row.appendChild(countCell);
546
+ tbody.appendChild(row);
547
+ });
548
+ }
549
+
550
+ function renderErrorDetails(data) {
551
+ const container = document.getElementById('error-details');
552
+ const errors = data.recentErrors || [];
553
+ if (errors.length === 0) {
554
+ container.innerHTML = '<p class="muted">No error details recorded.</p>';
555
+ return;
556
+ }
557
+ container.innerHTML = '';
558
+ errors.forEach((error) => {
559
+ const div = document.createElement('div');
560
+ div.className = 'event';
561
+ const title = document.createElement('strong');
562
+ const time = new Date(error.timestamp).toLocaleString();
563
+ title.textContent = '\${time} · ' + (error.level || 'error');
564
+ const details = document.createElement('div');
565
+ const parts = [
566
+ error.message,
567
+ error.source ? 'source: ' + error.source : null,
568
+ error.context ? 'context: ' + JSON.stringify(error.context).slice(0, 400) : null,
569
+ error.clientType ? 'client: ' + error.clientType : null,
570
+ ].filter(Boolean);
571
+ details.textContent = parts.join(' | ');
572
+ div.appendChild(title);
573
+ div.appendChild(details);
574
+ container.appendChild(div);
575
+ });
576
+ }
577
+
578
+ function renderEvents(data) {
579
+ const container = document.getElementById('events');
580
+ const events = data.recentEvents || [];
581
+ if (events.length === 0) {
582
+ container.innerHTML = '<p>No events recorded yet.</p>';
583
+ return;
584
+ }
585
+ container.innerHTML = '';
586
+ events.forEach((event) => {
587
+ const div = document.createElement('div');
588
+ div.className = 'event';
589
+ const title = document.createElement('strong');
590
+ title.textContent = new Date(event.timestamp).toLocaleString() + ' · ' + event.type;
591
+ const details = document.createElement('div');
592
+ details.textContent = describeEvent(event);
593
+ div.appendChild(title);
594
+ div.appendChild(details);
595
+ container.appendChild(div);
596
+ });
597
+ }
598
+
599
+ function describeEvent(event) {
600
+ if (event.type === 'search') {
601
+ const status = event.success ? 'success' : 'failed';
602
+ return \`\${event.searchKind} :: \${event.query} (\${status}, \${event.resultCount || 0} results)\`;
603
+ }
604
+ if (event.type === 'initialization') {
605
+ return \`Initialization · version \${event.version}\`;
606
+ }
607
+ if (event.type === 'api_call') {
608
+ const status = event.success ? 'success' : \`error \${event.statusCode || 'n/a'}\`;
609
+ return \`\${event.operation} (\${status})\`;
610
+ }
611
+ if (event.type === 'multi_repo_summary') {
612
+ return \`Multi-repo search for "\${event.query}" (\${event.successfulRepositories}/\${event.repositoryCount} succeeded)\`;
613
+ }
614
+ return 'Event recorded';
615
+ }
616
+
617
+ refreshStats();
618
+ setInterval(refreshStats, 15000);
619
+ </script>
620
+ </body>
621
+ </html>`;
622
+ }
623
+ //# sourceMappingURL=stats-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-server.js","sourceRoot":"","sources":["../src/stats-server.ts"],"names":[],"mappings":"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"}