@kb-labs/studio-data-client 0.2.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/index.js ADDED
@@ -0,0 +1,3961 @@
1
+ import axios from 'axios';
2
+ import { ulid } from 'ulid';
3
+ import { z } from 'zod';
4
+ import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
5
+ import { useMemo, useState, useEffect, useRef, useCallback } from 'react';
6
+
7
+ // src/errors/kb-error.ts
8
+ var KBError = class extends Error {
9
+ constructor(code, message, status, cause) {
10
+ super(message);
11
+ this.code = code;
12
+ this.message = message;
13
+ this.status = status;
14
+ this.cause = cause;
15
+ this.name = "KBError";
16
+ }
17
+ };
18
+ var errorCodes = {
19
+ NETWORK_ERROR: "NETWORK_ERROR",
20
+ VALIDATION_ERROR: "VALIDATION_ERROR",
21
+ AUTH_ERROR: "AUTH_ERROR",
22
+ NOT_FOUND: "NOT_FOUND",
23
+ SERVER_ERROR: "SERVER_ERROR",
24
+ TIMEOUT_ERROR: "TIMEOUT_ERROR",
25
+ TIMEOUT: "TIMEOUT",
26
+ CONFLICT: "CONFLICT",
27
+ RATE_LIMIT: "RATE_LIMIT",
28
+ TOOL_ERROR: "TOOL_ERROR"
29
+ };
30
+
31
+ // src/client/error-mapper.ts
32
+ function isErrorEnvelopeResponse(obj) {
33
+ return typeof obj === "object" && obj !== null && "ok" in obj && obj.ok === false && "error" in obj && typeof obj.error === "object" && obj.error !== null && "message" in obj.error;
34
+ }
35
+ function mapFetchError(error, response) {
36
+ if (!response) {
37
+ if (error instanceof KBError) {
38
+ return error;
39
+ }
40
+ if (error instanceof TypeError && error.message.includes("fetch")) {
41
+ return new KBError(errorCodes.NETWORK_ERROR, "Network request failed", void 0, error);
42
+ }
43
+ return new KBError(errorCodes.NETWORK_ERROR, "Unknown error occurred", void 0, error);
44
+ }
45
+ const parsedBody = error;
46
+ const errorEnvelope = parsedBody && typeof parsedBody === "object" && isErrorEnvelopeResponse(parsedBody) ? parsedBody : null;
47
+ const httpError = {
48
+ status: response.status,
49
+ statusText: response.statusText,
50
+ data: parsedBody ?? null
51
+ };
52
+ const statusCode = response.status;
53
+ let errorMessage = void 0;
54
+ if (errorEnvelope !== null) {
55
+ const envelope = errorEnvelope;
56
+ errorMessage = envelope.error.message;
57
+ }
58
+ if (statusCode === 404) {
59
+ return new KBError(errorCodes.NOT_FOUND, errorMessage || "Resource not found", 404, httpError);
60
+ }
61
+ if (statusCode === 401) {
62
+ return new KBError(errorCodes.AUTH_ERROR, errorMessage || "Authentication failed", 401, httpError);
63
+ }
64
+ if (statusCode === 403) {
65
+ return new KBError(errorCodes.AUTH_ERROR, errorMessage || "Forbidden", 403, httpError);
66
+ }
67
+ if (statusCode === 409) {
68
+ return new KBError(errorCodes.CONFLICT, errorMessage || "Conflict", 409, httpError);
69
+ }
70
+ if (statusCode === 429) {
71
+ return new KBError(errorCodes.RATE_LIMIT, errorMessage || "Rate limit exceeded", 429, httpError);
72
+ }
73
+ if (statusCode >= 500) {
74
+ return new KBError(errorCodes.SERVER_ERROR, errorMessage || "Server error", statusCode, httpError);
75
+ }
76
+ return new KBError(errorCodes.NETWORK_ERROR, errorMessage || httpError.statusText || "Request failed", statusCode, httpError);
77
+ }
78
+ function mapErrorEnvelope(envelope) {
79
+ const httpError = {
80
+ status: 400,
81
+ // Default status
82
+ statusText: envelope.error.message,
83
+ data: envelope
84
+ };
85
+ const errorCode = envelope.error.code;
86
+ if (errorCode === "E_NOT_FOUND") {
87
+ return new KBError(errorCodes.NOT_FOUND, envelope.error.message, 404, httpError);
88
+ }
89
+ if (errorCode === "E_UNAUTHORIZED") {
90
+ return new KBError(errorCodes.AUTH_ERROR, envelope.error.message, 401, httpError);
91
+ }
92
+ if (errorCode === "E_FORBIDDEN") {
93
+ return new KBError(errorCodes.AUTH_ERROR, envelope.error.message, 403, httpError);
94
+ }
95
+ if (errorCode === "E_CONFLICT") {
96
+ return new KBError(errorCodes.CONFLICT, envelope.error.message, 409, httpError);
97
+ }
98
+ if (errorCode === "E_RATE_LIMIT") {
99
+ return new KBError(errorCodes.RATE_LIMIT, envelope.error.message, 429, httpError);
100
+ }
101
+ if (errorCode === "E_TIMEOUT") {
102
+ return new KBError(errorCodes.TIMEOUT, envelope.error.message, 408, httpError);
103
+ }
104
+ if (errorCode.startsWith("E_TOOL_")) {
105
+ return new KBError(errorCodes.TOOL_ERROR, envelope.error.message, 500, httpError);
106
+ }
107
+ return new KBError(errorCodes.SERVER_ERROR, envelope.error.message, 500, httpError);
108
+ }
109
+ var HttpClient = class {
110
+ client;
111
+ requestInterceptors = [];
112
+ responseInterceptors = [];
113
+ errorInterceptors = [];
114
+ baseUrl;
115
+ constructor(baseUrl = "", token) {
116
+ this.baseUrl = baseUrl;
117
+ this.client = axios.create({
118
+ baseURL: baseUrl,
119
+ headers: {
120
+ "Content-Type": "application/json",
121
+ ...token ? { Authorization: `Bearer ${token}` } : {}
122
+ }
123
+ });
124
+ this.client.interceptors.request.use((config) => {
125
+ if (!config.headers["X-Request-Id"]) {
126
+ config.headers["X-Request-Id"] = ulid();
127
+ }
128
+ return config;
129
+ });
130
+ this.client.interceptors.response.use(
131
+ (response) => {
132
+ const data = response.data;
133
+ if (data && typeof data === "object" && "ok" in data) {
134
+ if (data.ok === true && "data" in data) {
135
+ response.data = data.data;
136
+ } else if (data.ok === false && "error" in data) {
137
+ const error = mapFetchError(data.error, {
138
+ status: response.status,
139
+ statusText: response.statusText
140
+ });
141
+ return Promise.reject(error);
142
+ }
143
+ }
144
+ return response;
145
+ },
146
+ (error) => {
147
+ const kbError = mapFetchError(error.response?.data, {
148
+ status: error.response?.status ?? 500,
149
+ statusText: error.response?.statusText ?? "Unknown Error"
150
+ });
151
+ return Promise.reject(kbError);
152
+ }
153
+ );
154
+ }
155
+ addRequestInterceptor(interceptor) {
156
+ this.requestInterceptors.push(interceptor);
157
+ }
158
+ addResponseInterceptor(interceptor) {
159
+ this.responseInterceptors.push(interceptor);
160
+ }
161
+ addErrorInterceptor(interceptor) {
162
+ this.errorInterceptors.push(interceptor);
163
+ }
164
+ getBaseUrl() {
165
+ return this.baseUrl;
166
+ }
167
+ async fetch(path, options = {}) {
168
+ try {
169
+ const config = {
170
+ url: path,
171
+ ...options
172
+ };
173
+ const response = await this.client.request(config);
174
+ return response.data;
175
+ } catch (error) {
176
+ const kbError = error instanceof KBError ? error : mapFetchError(error);
177
+ throw await this.processError(kbError);
178
+ }
179
+ }
180
+ async processError(error) {
181
+ let processedError = error;
182
+ for (const interceptor of this.errorInterceptors) {
183
+ processedError = await interceptor(processedError);
184
+ }
185
+ throw processedError;
186
+ }
187
+ };
188
+
189
+ // src/client/envelope-interceptor.ts
190
+ function createEnvelopeInterceptor() {
191
+ return async (response) => {
192
+ const contentType = response.headers.get("content-type");
193
+ if (!contentType?.includes("application/json")) {
194
+ return response;
195
+ }
196
+ if (contentType.includes("text/event-stream")) {
197
+ return response;
198
+ }
199
+ const clonedResponse = response.clone();
200
+ try {
201
+ const envelope = await clonedResponse.json();
202
+ if (envelope && typeof envelope === "object" && "ok" in envelope) {
203
+ if (envelope.ok === true && "data" in envelope) {
204
+ const unwrappedData = envelope.data;
205
+ const headers = new Headers(response.headers);
206
+ headers.set("Content-Type", "application/json");
207
+ return new Response(JSON.stringify(unwrappedData), {
208
+ status: response.status,
209
+ statusText: response.statusText,
210
+ headers
211
+ });
212
+ } else if (envelope.ok === false && "error" in envelope) {
213
+ return response;
214
+ }
215
+ }
216
+ return response;
217
+ } catch (_error) {
218
+ return response;
219
+ }
220
+ };
221
+ }
222
+ function extractEnvelopeMeta(response) {
223
+ try {
224
+ const requestId = response.headers.get("X-Request-Id") || void 0;
225
+ const apiVersion = response.headers.get("X-Schema-Version") || response.headers.get("x-schema-version") || void 0;
226
+ return {
227
+ requestId: requestId || void 0,
228
+ apiVersion: apiVersion || void 0
229
+ };
230
+ } catch {
231
+ return null;
232
+ }
233
+ }
234
+
235
+ // src/contracts/common.ts
236
+ var SCHEMA_VERSION = "1.0";
237
+ var idSchema = z.string();
238
+ var isoDateSchema = z.string().datetime();
239
+ var packageRefSchema = z.object({
240
+ name: z.string(),
241
+ version: z.string().optional(),
242
+ private: z.boolean().optional(),
243
+ path: z.string().optional()
244
+ });
245
+ var runRefSchema = z.object({
246
+ id: idSchema,
247
+ startedAt: isoDateSchema,
248
+ endedAt: isoDateSchema.optional(),
249
+ status: z.enum(["pending", "ok", "warn", "fail"])
250
+ });
251
+ var actionResultSchema = z.object({
252
+ ok: z.boolean(),
253
+ message: z.string().optional(),
254
+ runId: idSchema.optional()
255
+ });
256
+ var auditSummarySchema = z.object({
257
+ ts: isoDateSchema,
258
+ totals: z.object({
259
+ packages: z.number(),
260
+ ok: z.number(),
261
+ warn: z.number(),
262
+ fail: z.number(),
263
+ durationMs: z.number()
264
+ }),
265
+ topFailures: z.array(
266
+ z.object({
267
+ pkg: z.string(),
268
+ checks: z.array(z.enum(["style", "types", "tests", "build", "devlink", "mind"]))
269
+ })
270
+ )
271
+ });
272
+ var auditCheckSchema = z.object({
273
+ id: z.enum(["style", "types", "tests", "build", "devlink", "mind"]),
274
+ ok: z.boolean(),
275
+ errors: z.number().optional(),
276
+ warnings: z.number().optional(),
277
+ meta: z.unknown().optional()
278
+ });
279
+ var auditPackageReportSchema = z.object({
280
+ pkg: packageRefSchema,
281
+ lastRun: runRefSchema,
282
+ checks: z.array(auditCheckSchema),
283
+ artifacts: z.object({
284
+ json: z.string().optional(),
285
+ md: z.string().optional(),
286
+ txt: z.string().optional(),
287
+ html: z.string().optional()
288
+ })
289
+ });
290
+ var releasePreviewSchema = z.object({
291
+ range: z.object({
292
+ from: z.string(),
293
+ to: z.string()
294
+ }),
295
+ packages: z.array(
296
+ z.object({
297
+ name: z.string(),
298
+ prev: z.string(),
299
+ next: z.string(),
300
+ bump: z.enum(["major", "minor", "patch", "none"]),
301
+ breaking: z.number().optional()
302
+ })
303
+ ),
304
+ manifestJson: z.string().optional(),
305
+ markdown: z.string().optional()
306
+ });
307
+ var healthStatusSchema = z.object({
308
+ ok: z.boolean(),
309
+ timestamp: isoDateSchema,
310
+ sources: z.array(
311
+ z.object({
312
+ name: z.string(),
313
+ ok: z.boolean(),
314
+ latency: z.number().optional(),
315
+ error: z.string().optional()
316
+ })
317
+ )
318
+ });
319
+
320
+ // src/sources/http-system-source.ts
321
+ var HttpSystemSource = class {
322
+ constructor(client) {
323
+ this.client = client;
324
+ }
325
+ async getHealth() {
326
+ const snapshot = await this.client.fetch("/observability/health");
327
+ const degraded = snapshot.status === "degraded" || snapshot.state === "partial_observability";
328
+ return {
329
+ ok: snapshot.status === "healthy",
330
+ timestamp: snapshot.observedAt,
331
+ sources: snapshot.checks.length > 0 ? snapshot.checks.map((check) => ({
332
+ name: check.id,
333
+ ok: check.status === "ok",
334
+ latency: check.latencyMs,
335
+ error: check.status === "warn" ? "system_degraded" : check.status === "error" ? check.message ?? "system_error" : void 0
336
+ })) : [
337
+ {
338
+ name: "system",
339
+ ok: snapshot.status === "healthy",
340
+ error: degraded ? "system_degraded" : void 0
341
+ }
342
+ ],
343
+ snapshot
344
+ };
345
+ }
346
+ /**
347
+ * Get ready status
348
+ */
349
+ async getReady() {
350
+ try {
351
+ return this.client.fetch("/ready");
352
+ } catch (error) {
353
+ if (error instanceof KBError && error.status === 503) {
354
+ const payload = error.cause?.data;
355
+ if (payload && typeof payload === "object" && "ready" in payload) {
356
+ return payload;
357
+ }
358
+ return {
359
+ ready: false,
360
+ reason: "unknown"
361
+ };
362
+ }
363
+ throw error;
364
+ }
365
+ }
366
+ /**
367
+ * Get info
368
+ */
369
+ async getInfo() {
370
+ const response = await this.client.fetch("/info");
371
+ return response.data;
372
+ }
373
+ /**
374
+ * Get capabilities
375
+ */
376
+ async getCapabilities() {
377
+ const response = await this.client.fetch("/info/capabilities");
378
+ return response.data;
379
+ }
380
+ /**
381
+ * Get config (redacted)
382
+ */
383
+ async getConfig() {
384
+ const response = await this.client.fetch("/info/config");
385
+ return response.data;
386
+ }
387
+ /**
388
+ * Get all registered API routes
389
+ */
390
+ async getRoutes() {
391
+ return this.client.fetch("/routes");
392
+ }
393
+ /**
394
+ * Get the base URL of the API
395
+ */
396
+ getBaseUrl() {
397
+ return this.client.getBaseUrl();
398
+ }
399
+ };
400
+
401
+ // src/sources/http-workflow-source.ts
402
+ function buildQuery(params) {
403
+ if (!params || Object.keys(params).length === 0) {
404
+ return "";
405
+ }
406
+ const query = new URLSearchParams();
407
+ if (params.status) {
408
+ query.set("status", params.status);
409
+ }
410
+ if (typeof params.limit === "number" && !Number.isNaN(params.limit)) {
411
+ query.set("limit", String(params.limit));
412
+ }
413
+ const qs = query.toString();
414
+ return qs ? `?${qs}` : "";
415
+ }
416
+ var HttpWorkflowSource = class {
417
+ constructor(client) {
418
+ this.client = client;
419
+ }
420
+ async listRuns(filters) {
421
+ const query = buildQuery(filters);
422
+ return this.client.fetch(`/plugins/workflow/runs${query}`);
423
+ }
424
+ async getRun(runId) {
425
+ try {
426
+ const response = await this.client.fetch(
427
+ `/plugins/workflow/runs/${encodeURIComponent(runId)}`
428
+ );
429
+ return response.run;
430
+ } catch (error) {
431
+ if (error instanceof KBError && error.status === 404) {
432
+ return null;
433
+ }
434
+ throw error;
435
+ }
436
+ }
437
+ async cancelRun(runId) {
438
+ await this.client.fetch(
439
+ `/plugins/workflow/workflows/runs/${encodeURIComponent(runId)}/cancel`,
440
+ { method: "POST" }
441
+ );
442
+ const run = await this.getRun(runId);
443
+ if (!run) {
444
+ return { id: runId, status: "cancelled" };
445
+ }
446
+ return run;
447
+ }
448
+ async runWorkflow(params) {
449
+ const response = await this.client.fetch(
450
+ `/plugins/workflow/workflows/${encodeURIComponent(params.spec.name)}/run`,
451
+ {
452
+ method: "POST",
453
+ data: {
454
+ input: params.metadata
455
+ }
456
+ }
457
+ );
458
+ return response.run;
459
+ }
460
+ async listEvents(runId, options = {}) {
461
+ const params = new URLSearchParams();
462
+ if (options.cursor) {
463
+ params.set("cursor", options.cursor);
464
+ }
465
+ if (typeof options.limit === "number" && !Number.isNaN(options.limit)) {
466
+ params.set("limit", String(options.limit));
467
+ }
468
+ const query = params.toString();
469
+ return this.client.fetch(
470
+ `/workflows/runs/${runId}/events${query ? `?${query}` : ""}`
471
+ );
472
+ }
473
+ // 🆕 NEW methods for UI
474
+ async getStats() {
475
+ return this.client.fetch("/plugins/workflow/stats");
476
+ }
477
+ async listWorkflows(filters) {
478
+ const params = new URLSearchParams();
479
+ if (typeof filters?.limit === "number" && !Number.isNaN(filters.limit)) {
480
+ params.set("limit", String(filters.limit));
481
+ }
482
+ const query = params.toString();
483
+ return this.client.fetch(
484
+ `/plugins/workflow/workflows${query ? `?${query}` : ""}`
485
+ );
486
+ }
487
+ async getWorkflow(workflowId) {
488
+ try {
489
+ return await this.client.fetch(
490
+ `/plugins/workflow/workflows/${encodeURIComponent(workflowId)}`
491
+ );
492
+ } catch (error) {
493
+ if (error instanceof KBError && error.status === 404) {
494
+ return null;
495
+ }
496
+ throw error;
497
+ }
498
+ }
499
+ async runWorkflowById(workflowId, input) {
500
+ return this.client.fetch(
501
+ `/plugins/workflow/workflows/${encodeURIComponent(workflowId)}/run`,
502
+ {
503
+ method: "POST",
504
+ data: { input }
505
+ }
506
+ );
507
+ }
508
+ async listJobs(filters) {
509
+ const params = new URLSearchParams();
510
+ if (filters?.type) {
511
+ params.set("type", filters.type);
512
+ }
513
+ if (filters?.status) {
514
+ params.set("status", filters.status);
515
+ }
516
+ if (typeof filters?.limit === "number" && !Number.isNaN(filters.limit)) {
517
+ params.set("limit", String(filters.limit));
518
+ }
519
+ if (typeof filters?.offset === "number" && !Number.isNaN(filters.offset)) {
520
+ params.set("offset", String(filters.offset));
521
+ }
522
+ const query = params.toString();
523
+ return this.client.fetch(
524
+ `/plugins/workflow/jobs${query ? `?${query}` : ""}`
525
+ );
526
+ }
527
+ async getJob(jobId) {
528
+ try {
529
+ return await this.client.fetch(
530
+ `/plugins/workflow/jobs/${encodeURIComponent(jobId)}`
531
+ );
532
+ } catch (error) {
533
+ if (error instanceof KBError && error.status === 404) {
534
+ return null;
535
+ }
536
+ throw error;
537
+ }
538
+ }
539
+ async getJobSteps(jobId) {
540
+ return this.client.fetch(
541
+ `/plugins/workflow/jobs/${encodeURIComponent(jobId)}/steps`
542
+ );
543
+ }
544
+ async getJobLogs(jobId, filters) {
545
+ const params = new URLSearchParams();
546
+ if (typeof filters?.limit === "number" && !Number.isNaN(filters.limit)) {
547
+ params.set("limit", String(filters.limit));
548
+ }
549
+ if (typeof filters?.offset === "number" && !Number.isNaN(filters.offset)) {
550
+ params.set("offset", String(filters.offset));
551
+ }
552
+ if (filters?.level) {
553
+ params.set("level", filters.level);
554
+ }
555
+ const query = params.toString();
556
+ return this.client.fetch(
557
+ `/plugins/workflow/jobs/${encodeURIComponent(jobId)}/logs${query ? `?${query}` : ""}`
558
+ );
559
+ }
560
+ async listCronJobs() {
561
+ return this.client.fetch("/plugins/workflow/cron");
562
+ }
563
+ async getPendingApprovals(runId) {
564
+ return this.client.fetch(
565
+ `/plugins/workflow/runs/${encodeURIComponent(runId)}/pending-approvals`
566
+ );
567
+ }
568
+ async resolveApproval(params) {
569
+ const { runId, ...body } = params;
570
+ return this.client.fetch(
571
+ `/plugins/workflow/runs/${encodeURIComponent(runId)}/approve`,
572
+ {
573
+ method: "POST",
574
+ data: body
575
+ }
576
+ );
577
+ }
578
+ async cancelWorkflowRun(runId) {
579
+ return this.client.fetch(
580
+ `/plugins/workflow/workflows/runs/${encodeURIComponent(runId)}/cancel`,
581
+ { method: "POST" }
582
+ );
583
+ }
584
+ async getWorkflowRuns(workflowId, filters) {
585
+ const params = new URLSearchParams();
586
+ if (typeof filters?.limit === "number" && !Number.isNaN(filters.limit)) {
587
+ params.set("limit", String(filters.limit));
588
+ }
589
+ if (typeof filters?.offset === "number" && !Number.isNaN(filters.offset)) {
590
+ params.set("offset", String(filters.offset));
591
+ }
592
+ if (filters?.status) {
593
+ params.set("status", filters.status);
594
+ }
595
+ const query = params.toString();
596
+ return this.client.fetch(
597
+ `/plugins/workflow/workflows/${encodeURIComponent(workflowId)}/runs${query ? `?${query}` : ""}`
598
+ );
599
+ }
600
+ };
601
+
602
+ // src/sources/http-cache-source.ts
603
+ var HttpCacheSource = class {
604
+ constructor(client) {
605
+ this.client = client;
606
+ }
607
+ async invalidateCache() {
608
+ return this.client.fetch("/cache/invalidate", {
609
+ method: "POST"
610
+ // No Content-Type header needed for empty body POST
611
+ });
612
+ }
613
+ };
614
+
615
+ // src/sources/prometheus-metrics-parser.ts
616
+ function parseLabels(raw) {
617
+ if (!raw) {
618
+ return {};
619
+ }
620
+ const labels = {};
621
+ const pattern = /([a-zA-Z_][a-zA-Z0-9_]*)="((?:\\"|[^"])*)"/g;
622
+ for (const match of raw.matchAll(pattern)) {
623
+ const key = match[1];
624
+ if (!key) {
625
+ continue;
626
+ }
627
+ labels[key] = (match[2] ?? "").replace(/\\"/g, '"');
628
+ }
629
+ return labels;
630
+ }
631
+ function parseSamples(text) {
632
+ const samples = [];
633
+ for (const line of text.split("\n")) {
634
+ const trimmed = line.trim();
635
+ if (!trimmed || trimmed.startsWith("#")) {
636
+ continue;
637
+ }
638
+ const match = trimmed.match(/^([a-zA-Z_:][a-zA-Z0-9_:]*)(?:\{([^}]*)\})?\s+(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)$/);
639
+ if (!match) {
640
+ continue;
641
+ }
642
+ samples.push({
643
+ name: match[1],
644
+ labels: parseLabels(match[2]),
645
+ value: Number(match[3])
646
+ });
647
+ }
648
+ return samples;
649
+ }
650
+ function sumMetric(samples, metricName) {
651
+ return samples.filter((sample) => sample.name === metricName).reduce((sum, sample) => sum + sample.value, 0);
652
+ }
653
+ function latestMetric(samples, metricName) {
654
+ const metric = [...samples].reverse().find((sample) => sample.name === metricName);
655
+ return metric ? metric.value : null;
656
+ }
657
+ function buildHistogram(samples, bucketMetric) {
658
+ return samples.filter((sample) => sample.name === bucketMetric && sample.labels.le).map((sample) => ({
659
+ le: sample.labels.le === "+Inf" ? Number.POSITIVE_INFINITY : Number(sample.labels.le),
660
+ count: sample.value
661
+ })).sort((a, b) => a.le - b.le);
662
+ }
663
+ function interpolateQuantile(quantile, histogram) {
664
+ if (histogram.length === 0) {
665
+ return 0;
666
+ }
667
+ const total = histogram.find((point) => !Number.isFinite(point.le))?.count ?? histogram[histogram.length - 1].count;
668
+ if (total <= 0) {
669
+ return 0;
670
+ }
671
+ const target = total * quantile;
672
+ let previousCount = 0;
673
+ let previousLe = 0;
674
+ for (const point of histogram) {
675
+ if (point.count >= target) {
676
+ if (!Number.isFinite(point.le)) {
677
+ return previousLe;
678
+ }
679
+ const bucketCount = point.count - previousCount;
680
+ if (bucketCount <= 0) {
681
+ return point.le;
682
+ }
683
+ const progress = (target - previousCount) / bucketCount;
684
+ return previousLe + (point.le - previousLe) * progress;
685
+ }
686
+ previousCount = point.count;
687
+ if (Number.isFinite(point.le)) {
688
+ previousLe = point.le;
689
+ }
690
+ }
691
+ return previousLe;
692
+ }
693
+ function buildLatency(samples) {
694
+ const count = sumMetric(samples, "http_request_duration_ms_count");
695
+ const total = sumMetric(samples, "http_request_duration_ms_sum");
696
+ const histogram = buildHistogram(samples, "http_request_duration_ms_bucket");
697
+ const finiteBuckets = histogram.filter((point) => Number.isFinite(point.le) && point.count > 0);
698
+ return {
699
+ average: count > 0 ? total / count : 0,
700
+ min: finiteBuckets[0]?.le ?? 0,
701
+ max: finiteBuckets[finiteBuckets.length - 1]?.le ?? 0,
702
+ p50: interpolateQuantile(0.5, histogram),
703
+ p95: interpolateQuantile(0.95, histogram),
704
+ p99: interpolateQuantile(0.99, histogram)
705
+ };
706
+ }
707
+ function groupByLabel(samples, metricName, label) {
708
+ const grouped = /* @__PURE__ */ new Map();
709
+ for (const sample of samples) {
710
+ if (sample.name !== metricName || !sample.labels[label]) {
711
+ continue;
712
+ }
713
+ const key = sample.labels[label];
714
+ const existing = grouped.get(key) ?? [];
715
+ existing.push(sample);
716
+ grouped.set(key, existing);
717
+ }
718
+ return grouped;
719
+ }
720
+ function buildPluginMetrics(samples) {
721
+ const groupedCounts = groupByLabel(samples, "kb_plugin_request_total", "plugin");
722
+ const durationSums = groupByLabel(samples, "kb_plugin_request_duration_ms_sum", "plugin");
723
+ const durationCounts = groupByLabel(samples, "kb_plugin_request_duration_ms_count", "plugin");
724
+ return Array.from(/* @__PURE__ */ new Set([
725
+ ...groupedCounts.keys(),
726
+ ...durationSums.keys(),
727
+ ...durationCounts.keys()
728
+ ])).map((pluginId) => {
729
+ const requests = (groupedCounts.get(pluginId) ?? []).reduce((sum, sample) => sum + sample.value, 0);
730
+ const errors = (groupedCounts.get(pluginId) ?? []).filter((sample) => Number(sample.labels.status_code ?? 0) >= 400).reduce((sum, sample) => sum + sample.value, 0);
731
+ const totalDuration = (durationSums.get(pluginId) ?? []).reduce((sum, sample) => sum + sample.value, 0);
732
+ const durationCount = (durationCounts.get(pluginId) ?? []).reduce((sum, sample) => sum + sample.value, 0);
733
+ return {
734
+ pluginId,
735
+ requests,
736
+ errors,
737
+ latency: {
738
+ average: durationCount > 0 ? totalDuration / durationCount : 0,
739
+ min: 0,
740
+ max: 0
741
+ }
742
+ };
743
+ });
744
+ }
745
+ function buildTenantMetrics(samples) {
746
+ const groupedCounts = groupByLabel(samples, "kb_tenant_request_total", "tenant");
747
+ const errorCounts = groupByLabel(samples, "kb_tenant_request_errors_total", "tenant");
748
+ const durationSums = groupByLabel(samples, "kb_tenant_request_duration_ms_sum", "tenant");
749
+ const durationCounts = groupByLabel(samples, "kb_tenant_request_duration_ms_count", "tenant");
750
+ return Array.from(/* @__PURE__ */ new Set([
751
+ ...groupedCounts.keys(),
752
+ ...errorCounts.keys(),
753
+ ...durationSums.keys(),
754
+ ...durationCounts.keys()
755
+ ])).map((tenantId) => {
756
+ const requests = (groupedCounts.get(tenantId) ?? []).reduce((sum, sample) => sum + sample.value, 0);
757
+ const errors = (errorCounts.get(tenantId) ?? []).reduce((sum, sample) => sum + sample.value, 0);
758
+ const totalDuration = (durationSums.get(tenantId) ?? []).reduce((sum, sample) => sum + sample.value, 0);
759
+ const durationCount = (durationCounts.get(tenantId) ?? []).reduce((sum, sample) => sum + sample.value, 0);
760
+ return {
761
+ tenantId,
762
+ requests,
763
+ errors,
764
+ latency: {
765
+ average: durationCount > 0 ? totalDuration / durationCount : 0
766
+ }
767
+ };
768
+ });
769
+ }
770
+ function buildErrorBreakdown(samples) {
771
+ const byStatusCode = {};
772
+ for (const sample of samples) {
773
+ if (sample.name !== "http_requests_total") {
774
+ continue;
775
+ }
776
+ const statusCode = Number(sample.labels.status_code ?? 0);
777
+ if (statusCode < 400) {
778
+ continue;
779
+ }
780
+ byStatusCode[statusCode] = (byStatusCode[statusCode] ?? 0) + sample.value;
781
+ }
782
+ return {
783
+ byStatusCode,
784
+ recent: []
785
+ };
786
+ }
787
+ function parsePrometheusMetrics(text) {
788
+ const samples = parseSamples(text);
789
+ const totalRequests = sumMetric(samples, "http_requests_total");
790
+ const errors = buildErrorBreakdown(samples);
791
+ const clientErrors = Object.entries(errors.byStatusCode).filter(([code]) => Number(code) >= 400 && Number(code) < 500).reduce((sum, [, count]) => sum + count, 0);
792
+ const serverErrors = Object.entries(errors.byStatusCode).filter(([code]) => Number(code) >= 500).reduce((sum, [, count]) => sum + count, 0);
793
+ const pluginMountTotal = latestMetric(samples, "kb_plugins_mount_total");
794
+ const pluginMountSucceeded = latestMetric(samples, "kb_plugins_mount_succeeded");
795
+ const pluginMountFailed = latestMetric(samples, "kb_plugins_mount_failed");
796
+ const pluginMountElapsedMs = latestMetric(samples, "kb_plugins_mount_elapsed_ms");
797
+ const uptimeSeconds = latestMetric(samples, "process_uptime_seconds") ?? 0;
798
+ const redisHealthy = latestMetric(samples, "kb_redis_healthy");
799
+ const redisTransitions = groupByLabel(samples, "kb_redis_status_transitions_total", "state");
800
+ return {
801
+ requests: {
802
+ total: totalRequests,
803
+ success: Math.max(0, totalRequests - clientErrors - serverErrors),
804
+ clientErrors,
805
+ serverErrors
806
+ },
807
+ latency: buildLatency(samples),
808
+ perPlugin: buildPluginMetrics(samples),
809
+ perTenant: buildTenantMetrics(samples),
810
+ errors,
811
+ timestamps: {
812
+ startTime: Date.now() - uptimeSeconds * 1e3,
813
+ lastRequest: null
814
+ },
815
+ redis: {
816
+ updates: sumMetric(samples, "kb_redis_status_updates_total"),
817
+ healthyTransitions: (redisTransitions.get("healthy") ?? []).reduce((sum, sample) => sum + sample.value, 0),
818
+ unhealthyTransitions: (redisTransitions.get("unhealthy") ?? []).reduce((sum, sample) => sum + sample.value, 0),
819
+ lastStatus: redisHealthy === null ? null : {
820
+ healthy: redisHealthy >= 1,
821
+ state: redisHealthy >= 1 ? "healthy" : "unhealthy",
822
+ role: "unknown"
823
+ }
824
+ },
825
+ pluginMounts: pluginMountTotal === null ? null : {
826
+ total: pluginMountTotal,
827
+ succeeded: pluginMountSucceeded ?? 0,
828
+ failed: pluginMountFailed ?? 0,
829
+ elapsedMs: pluginMountElapsedMs ?? 0
830
+ },
831
+ uptime: {
832
+ seconds: uptimeSeconds,
833
+ startTime: new Date(Date.now() - uptimeSeconds * 1e3).toISOString(),
834
+ lastRequest: null
835
+ }
836
+ };
837
+ }
838
+
839
+ // src/sources/http-observability-source.ts
840
+ var HttpObservabilitySource = class {
841
+ constructor(client) {
842
+ this.client = client;
843
+ }
844
+ async getStateBrokerStats() {
845
+ try {
846
+ return await this.client.fetch(
847
+ "/observability/state-broker"
848
+ );
849
+ } catch (error) {
850
+ throw new KBError(
851
+ "STATE_BROKER_FETCH_FAILED",
852
+ "Failed to fetch State Broker stats",
853
+ 500,
854
+ error
855
+ );
856
+ }
857
+ }
858
+ async getDevKitHealth() {
859
+ try {
860
+ return await this.client.fetch(
861
+ "/observability/devkit"
862
+ );
863
+ } catch (error) {
864
+ throw new KBError(
865
+ "DEVKIT_FETCH_FAILED",
866
+ "Failed to fetch DevKit health",
867
+ 500,
868
+ error
869
+ );
870
+ }
871
+ }
872
+ async getPrometheusMetrics() {
873
+ try {
874
+ const payload = await this.client.fetch(
875
+ "/metrics",
876
+ { responseType: "text" }
877
+ );
878
+ return parsePrometheusMetrics(payload);
879
+ } catch (error) {
880
+ throw new KBError(
881
+ "PROMETHEUS_METRICS_FETCH_FAILED",
882
+ "Failed to fetch Prometheus metrics",
883
+ 500,
884
+ error
885
+ );
886
+ }
887
+ }
888
+ subscribeToSystemEvents(onEvent, onError) {
889
+ const eventSource = new EventSource(`${this.client.getBaseUrl()}/events/registry`);
890
+ eventSource.addEventListener("registry", (e) => {
891
+ try {
892
+ const event = JSON.parse(e.data);
893
+ onEvent(event);
894
+ } catch (err) {
895
+ console.error("Failed to parse registry event:", err);
896
+ }
897
+ });
898
+ eventSource.addEventListener("health", (e) => {
899
+ try {
900
+ const event = JSON.parse(e.data);
901
+ onEvent(event);
902
+ } catch (err) {
903
+ console.error("Failed to parse health event:", err);
904
+ }
905
+ });
906
+ eventSource.onerror = () => {
907
+ onError(new Error("Connection to event stream failed"));
908
+ eventSource.close();
909
+ };
910
+ return () => {
911
+ eventSource.close();
912
+ };
913
+ }
914
+ async queryLogs(filters) {
915
+ try {
916
+ const params = new URLSearchParams();
917
+ if (filters.from) {
918
+ params.append("from", filters.from);
919
+ }
920
+ if (filters.to) {
921
+ params.append("to", filters.to);
922
+ }
923
+ if (filters.level) {
924
+ params.append("level", filters.level);
925
+ }
926
+ if (filters.plugin) {
927
+ params.append("plugin", filters.plugin);
928
+ }
929
+ if (filters.executionId) {
930
+ params.append("executionId", filters.executionId);
931
+ }
932
+ if (filters.tenantId) {
933
+ params.append("tenantId", filters.tenantId);
934
+ }
935
+ if (filters.search) {
936
+ params.append("search", filters.search);
937
+ }
938
+ if (filters.limit !== void 0) {
939
+ params.append("limit", String(filters.limit));
940
+ }
941
+ if (filters.offset !== void 0) {
942
+ params.append("offset", String(filters.offset));
943
+ }
944
+ const queryString = params.toString();
945
+ const url = queryString ? `/logs?${queryString}` : "/logs";
946
+ return await this.client.fetch(url);
947
+ } catch (error) {
948
+ throw new KBError(
949
+ "LOGS_QUERY_FAILED",
950
+ "Failed to query logs",
951
+ 500,
952
+ error
953
+ );
954
+ }
955
+ }
956
+ subscribeToLogs(onLog, onError, filters) {
957
+ const params = new URLSearchParams();
958
+ if (filters?.level) {
959
+ params.append("level", filters.level);
960
+ }
961
+ if (filters?.plugin) {
962
+ params.append("plugin", filters.plugin);
963
+ }
964
+ if (filters?.executionId) {
965
+ params.append("executionId", filters.executionId);
966
+ }
967
+ if (filters?.tenantId) {
968
+ params.append("tenantId", filters.tenantId);
969
+ }
970
+ const queryString = params.toString();
971
+ const streamBase = this.client.getBaseUrl();
972
+ const url = queryString ? `${streamBase}/logs/stream?${queryString}` : `${streamBase}/logs/stream`;
973
+ const eventSource = new EventSource(url);
974
+ eventSource.addEventListener("log", (e) => {
975
+ try {
976
+ const log = JSON.parse(e.data);
977
+ onLog(log);
978
+ } catch (err) {
979
+ console.error("Failed to parse log event:", err);
980
+ }
981
+ });
982
+ eventSource.onerror = () => {
983
+ onError(new Error("Connection to log stream failed"));
984
+ eventSource.close();
985
+ };
986
+ return () => {
987
+ eventSource.close();
988
+ };
989
+ }
990
+ async summarizeLogs(request) {
991
+ try {
992
+ return await this.client.fetch("/logs/summarize", {
993
+ method: "POST",
994
+ data: request
995
+ });
996
+ } catch (error) {
997
+ throw new KBError(
998
+ "LOG_SUMMARIZATION_FAILED",
999
+ "Failed to summarize logs",
1000
+ 500,
1001
+ error
1002
+ );
1003
+ }
1004
+ }
1005
+ async getLog(id, includeRelated) {
1006
+ try {
1007
+ const params = new URLSearchParams();
1008
+ if (includeRelated) {
1009
+ params.append("includeRelated", "true");
1010
+ }
1011
+ const queryString = params.toString();
1012
+ const url = queryString ? `/logs/${id}?${queryString}` : `/logs/${id}`;
1013
+ return await this.client.fetch(url);
1014
+ } catch (error) {
1015
+ throw new KBError(
1016
+ "LOG_FETCH_FAILED",
1017
+ "Failed to fetch log",
1018
+ 500,
1019
+ error
1020
+ );
1021
+ }
1022
+ }
1023
+ async getRelatedLogs(id) {
1024
+ try {
1025
+ return await this.client.fetch(
1026
+ `/logs/${id}/related`
1027
+ );
1028
+ } catch (error) {
1029
+ throw new KBError(
1030
+ "RELATED_LOGS_FETCH_FAILED",
1031
+ "Failed to fetch related logs",
1032
+ 500,
1033
+ error
1034
+ );
1035
+ }
1036
+ }
1037
+ async getMetricsHistory(query) {
1038
+ try {
1039
+ const params = new URLSearchParams();
1040
+ params.append("metric", query.metric);
1041
+ params.append("range", query.range);
1042
+ if (query.interval) {
1043
+ params.append("interval", query.interval);
1044
+ }
1045
+ return await this.client.fetch(
1046
+ `/observability/metrics/history?${params.toString()}`
1047
+ );
1048
+ } catch (error) {
1049
+ throw new KBError(
1050
+ "METRICS_HISTORY_FETCH_FAILED",
1051
+ "Failed to fetch metrics history",
1052
+ 500,
1053
+ error
1054
+ );
1055
+ }
1056
+ }
1057
+ async getMetricsHeatmap(query) {
1058
+ try {
1059
+ const params = new URLSearchParams();
1060
+ params.append("metric", query.metric);
1061
+ if (query.days) {
1062
+ params.append("days", String(query.days));
1063
+ }
1064
+ return await this.client.fetch(
1065
+ `/observability/metrics/heatmap?${params.toString()}`
1066
+ );
1067
+ } catch (error) {
1068
+ throw new KBError(
1069
+ "METRICS_HEATMAP_FETCH_FAILED",
1070
+ "Failed to fetch metrics heatmap",
1071
+ 500,
1072
+ error
1073
+ );
1074
+ }
1075
+ }
1076
+ async queryIncidents(query) {
1077
+ try {
1078
+ const params = new URLSearchParams();
1079
+ if (query?.limit) {
1080
+ params.append("limit", String(query.limit));
1081
+ }
1082
+ if (query?.severity) {
1083
+ const severityList = Array.isArray(query.severity) ? query.severity : [query.severity];
1084
+ params.append("severity", severityList.join(","));
1085
+ }
1086
+ if (query?.type) {
1087
+ const typeList = Array.isArray(query.type) ? query.type : [query.type];
1088
+ params.append("type", typeList.join(","));
1089
+ }
1090
+ if (query?.from) {
1091
+ params.append("from", String(query.from));
1092
+ }
1093
+ if (query?.to) {
1094
+ params.append("to", String(query.to));
1095
+ }
1096
+ if (query?.includeResolved !== void 0) {
1097
+ params.append("includeResolved", String(query.includeResolved));
1098
+ }
1099
+ const queryString = params.toString();
1100
+ const url = queryString ? `/observability/incidents/history?${queryString}` : "/observability/incidents/history";
1101
+ return await this.client.fetch(url);
1102
+ } catch (error) {
1103
+ throw new KBError(
1104
+ "INCIDENTS_QUERY_FAILED",
1105
+ "Failed to query incidents",
1106
+ 500,
1107
+ error
1108
+ );
1109
+ }
1110
+ }
1111
+ async createIncident(payload) {
1112
+ try {
1113
+ return await this.client.fetch(
1114
+ "/observability/incidents",
1115
+ {
1116
+ method: "POST",
1117
+ data: payload
1118
+ }
1119
+ );
1120
+ } catch (error) {
1121
+ throw new KBError(
1122
+ "INCIDENT_CREATE_FAILED",
1123
+ "Failed to create incident",
1124
+ 500,
1125
+ error
1126
+ );
1127
+ }
1128
+ }
1129
+ async resolveIncident(id, resolutionNotes) {
1130
+ try {
1131
+ return await this.client.fetch(
1132
+ `/observability/incidents/${id}/resolve`,
1133
+ {
1134
+ method: "POST",
1135
+ data: { resolutionNotes }
1136
+ }
1137
+ );
1138
+ } catch (error) {
1139
+ throw new KBError(
1140
+ "INCIDENT_RESOLVE_FAILED",
1141
+ "Failed to resolve incident",
1142
+ 500,
1143
+ error
1144
+ );
1145
+ }
1146
+ }
1147
+ async listIncidents(query) {
1148
+ try {
1149
+ const params = buildIncidentQueryParams(query);
1150
+ const url = `/observability/incidents${params ? `?${params}` : ""}`;
1151
+ const response = await this.client.fetch(url);
1152
+ return {
1153
+ ok: true,
1154
+ data: response
1155
+ // HttpClient auto-unwraps envelope
1156
+ };
1157
+ } catch (error) {
1158
+ throw new KBError(
1159
+ "INCIDENTS_LIST_FAILED",
1160
+ "Failed to list incidents",
1161
+ 500,
1162
+ error
1163
+ );
1164
+ }
1165
+ }
1166
+ async getIncident(id) {
1167
+ try {
1168
+ const data = await this.client.fetch(`/observability/incidents/${id}`);
1169
+ return {
1170
+ ok: true,
1171
+ data
1172
+ };
1173
+ } catch (error) {
1174
+ throw new KBError(
1175
+ "INCIDENT_FETCH_FAILED",
1176
+ "Failed to fetch incident",
1177
+ 500,
1178
+ error
1179
+ );
1180
+ }
1181
+ }
1182
+ async analyzeIncident(id) {
1183
+ try {
1184
+ const data = await this.client.fetch(
1185
+ `/observability/incidents/${id}/analyze`,
1186
+ { method: "POST" }
1187
+ );
1188
+ return {
1189
+ ok: true,
1190
+ data
1191
+ };
1192
+ } catch (error) {
1193
+ throw new KBError(
1194
+ "INCIDENT_ANALYSIS_FAILED",
1195
+ "Failed to analyze incident",
1196
+ 500,
1197
+ error
1198
+ );
1199
+ }
1200
+ }
1201
+ async chatWithInsights(question, context) {
1202
+ try {
1203
+ return await this.client.fetch("/observability/insights/chat", {
1204
+ method: "POST",
1205
+ data: { question, context }
1206
+ });
1207
+ } catch (error) {
1208
+ throw new KBError(
1209
+ "INSIGHTS_CHAT_FAILED",
1210
+ "Failed to chat with AI insights",
1211
+ 500,
1212
+ error
1213
+ );
1214
+ }
1215
+ }
1216
+ };
1217
+ function buildIncidentQueryParams(query) {
1218
+ if (!query) {
1219
+ return "";
1220
+ }
1221
+ const params = new URLSearchParams();
1222
+ if (query.limit !== void 0) {
1223
+ params.append("limit", query.limit.toString());
1224
+ }
1225
+ if (query.severity) {
1226
+ const severities = Array.isArray(query.severity) ? query.severity : [query.severity];
1227
+ severities.forEach((s) => params.append("severity", s));
1228
+ }
1229
+ if (query.type) {
1230
+ const types = Array.isArray(query.type) ? query.type : [query.type];
1231
+ types.forEach((t) => params.append("type", t));
1232
+ }
1233
+ if (query.from !== void 0) {
1234
+ params.append("from", query.from.toString());
1235
+ }
1236
+ if (query.to !== void 0) {
1237
+ params.append("to", query.to.toString());
1238
+ }
1239
+ if (query.includeResolved !== void 0) {
1240
+ params.append("includeResolved", query.includeResolved.toString());
1241
+ }
1242
+ return params.toString();
1243
+ }
1244
+
1245
+ // src/sources/http-analytics-source.ts
1246
+ var HttpAnalyticsSource = class {
1247
+ constructor(client) {
1248
+ this.client = client;
1249
+ }
1250
+ async getEvents(query) {
1251
+ const params = new URLSearchParams();
1252
+ if (query?.type) {
1253
+ if (Array.isArray(query.type)) {
1254
+ query.type.forEach((t) => params.append("type", t));
1255
+ } else {
1256
+ params.set("type", query.type);
1257
+ }
1258
+ }
1259
+ if (query?.source) {
1260
+ params.set("source", query.source);
1261
+ }
1262
+ if (query?.actor) {
1263
+ params.set("actor", query.actor);
1264
+ }
1265
+ if (query?.from) {
1266
+ params.set("from", query.from);
1267
+ }
1268
+ if (query?.to) {
1269
+ params.set("to", query.to);
1270
+ }
1271
+ if (query?.limit) {
1272
+ params.set("limit", String(query.limit));
1273
+ }
1274
+ if (query?.offset) {
1275
+ params.set("offset", String(query.offset));
1276
+ }
1277
+ const path = `/analytics/events${params.toString() ? `?${params}` : ""}`;
1278
+ return this.client.fetch(path);
1279
+ }
1280
+ async getStats() {
1281
+ return this.client.fetch("/analytics/stats");
1282
+ }
1283
+ async getBufferStatus() {
1284
+ try {
1285
+ return this.client.fetch("/analytics/buffer/status");
1286
+ } catch (_error) {
1287
+ return null;
1288
+ }
1289
+ }
1290
+ async getDlqStatus() {
1291
+ try {
1292
+ return this.client.fetch("/analytics/dlq/status");
1293
+ } catch (_error) {
1294
+ return null;
1295
+ }
1296
+ }
1297
+ };
1298
+
1299
+ // src/sources/http-adapters-source.ts
1300
+ var HttpAdaptersSource = class {
1301
+ constructor(client) {
1302
+ this.client = client;
1303
+ }
1304
+ /**
1305
+ * Build query string from date range options
1306
+ */
1307
+ buildQueryString(options) {
1308
+ const params = new URLSearchParams();
1309
+ if (options?.from) {
1310
+ params.append("from", options.from);
1311
+ }
1312
+ if (options?.to) {
1313
+ params.append("to", options.to);
1314
+ }
1315
+ if (options?.models) {
1316
+ const modelsArray = Array.isArray(options.models) ? options.models : [options.models];
1317
+ if (modelsArray.length > 0) {
1318
+ params.append("models", modelsArray.join(","));
1319
+ }
1320
+ }
1321
+ if (options?.groupBy) {
1322
+ params.append("groupBy", options.groupBy);
1323
+ }
1324
+ if (options?.breakdownBy) {
1325
+ params.append("breakdownBy", options.breakdownBy);
1326
+ }
1327
+ if (options?.metrics && options.metrics.length > 0) {
1328
+ params.append("metrics", options.metrics.join(","));
1329
+ }
1330
+ const qs = params.toString();
1331
+ return qs ? `?${qs}` : "";
1332
+ }
1333
+ async getLLMUsage(options) {
1334
+ const query = this.buildQueryString(options);
1335
+ return this.client.fetch(`/adapters/llm/usage${query}`);
1336
+ }
1337
+ async getEmbeddingsUsage(options) {
1338
+ const query = this.buildQueryString(options);
1339
+ return this.client.fetch(`/adapters/embeddings/usage${query}`);
1340
+ }
1341
+ async getVectorStoreUsage(options) {
1342
+ const query = this.buildQueryString(options);
1343
+ return this.client.fetch(`/adapters/vectorstore/usage${query}`);
1344
+ }
1345
+ async getCacheUsage(options) {
1346
+ const query = this.buildQueryString(options);
1347
+ return this.client.fetch(`/adapters/cache/usage${query}`);
1348
+ }
1349
+ async getStorageUsage(options) {
1350
+ const query = this.buildQueryString(options);
1351
+ return this.client.fetch(`/adapters/storage/usage${query}`);
1352
+ }
1353
+ async getLLMDailyStats(options) {
1354
+ const query = this.buildQueryString(options);
1355
+ return this.client.fetch(`/adapters/llm/daily-stats${query}`);
1356
+ }
1357
+ async getEmbeddingsDailyStats(options) {
1358
+ const query = this.buildQueryString(options);
1359
+ return this.client.fetch(`/adapters/embeddings/daily-stats${query}`);
1360
+ }
1361
+ async getVectorStoreDailyStats(options) {
1362
+ const query = this.buildQueryString(options);
1363
+ return this.client.fetch(`/adapters/vectorstore/daily-stats${query}`);
1364
+ }
1365
+ async getCacheDailyStats(options) {
1366
+ const query = this.buildQueryString(options);
1367
+ return this.client.fetch(`/adapters/cache/daily-stats${query}`);
1368
+ }
1369
+ async getStorageDailyStats(options) {
1370
+ const query = this.buildQueryString(options);
1371
+ return this.client.fetch(`/adapters/storage/daily-stats${query}`);
1372
+ }
1373
+ };
1374
+
1375
+ // src/sources/http-platform-source.ts
1376
+ var HttpPlatformSource = class {
1377
+ constructor(client) {
1378
+ this.client = client;
1379
+ }
1380
+ /**
1381
+ * Get platform configuration
1382
+ */
1383
+ async getConfig() {
1384
+ return this.client.fetch("/platform/config");
1385
+ }
1386
+ };
1387
+
1388
+ // src/sources/http-plugins-source.ts
1389
+ var HttpPluginsSource = class {
1390
+ constructor(client) {
1391
+ this.client = client;
1392
+ }
1393
+ async getPlugins() {
1394
+ return this.client.fetch("/plugins/registry");
1395
+ }
1396
+ async askAboutPlugin(pluginId, request) {
1397
+ return this.client.fetch(`/plugins/${encodeURIComponent(pluginId)}/ask`, {
1398
+ method: "POST",
1399
+ data: request
1400
+ });
1401
+ }
1402
+ };
1403
+
1404
+ // src/mocks/mock-system-source.ts
1405
+ function delay(ms) {
1406
+ return new Promise((resolve) => {
1407
+ setTimeout(() => resolve(), ms);
1408
+ });
1409
+ }
1410
+ var MockSystemSource = class {
1411
+ async getHealth() {
1412
+ await delay(150);
1413
+ const snapshot = {
1414
+ schema: "kb.observability/1",
1415
+ contractVersion: "1.0",
1416
+ serviceId: "rest",
1417
+ instanceId: "mock-rest",
1418
+ observedAt: (/* @__PURE__ */ new Date()).toISOString(),
1419
+ status: "healthy",
1420
+ uptimeSec: 3600,
1421
+ metricsEndpoint: "/api/v1/metrics",
1422
+ logsSource: "rest",
1423
+ capabilities: ["httpMetrics", "eventLoopMetrics", "operationMetrics", "logCorrelation"],
1424
+ checks: [
1425
+ { id: "registry", status: "ok", message: "Registry snapshot loaded" },
1426
+ { id: "plugin-routes", status: "ok", message: "12 plugin routes mounted" }
1427
+ ],
1428
+ snapshot: {
1429
+ cpuPercent: 6.2,
1430
+ rssBytes: 188743680,
1431
+ heapUsedBytes: 73400320,
1432
+ eventLoopLagMs: 12,
1433
+ activeOperations: 3
1434
+ },
1435
+ topOperations: [
1436
+ { operation: "http.GET /api/v1/health", count: 42, avgDurationMs: 3.1, maxDurationMs: 8.2, errorCount: 0 }
1437
+ ],
1438
+ state: "active"
1439
+ };
1440
+ return {
1441
+ ok: true,
1442
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1443
+ sources: [
1444
+ { name: "registry", ok: true, latency: 100 },
1445
+ { name: "plugin-routes", ok: true, latency: 120 }
1446
+ ],
1447
+ snapshot
1448
+ };
1449
+ }
1450
+ async getRoutes() {
1451
+ await delay(100);
1452
+ return {
1453
+ schema: "kb.routes/1",
1454
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1455
+ count: 5,
1456
+ routes: [
1457
+ { method: "GET", url: "/api/v1/health" },
1458
+ { method: "GET", url: "/api/v1/ready" },
1459
+ { method: "GET", url: "/api/v1/plugins" },
1460
+ { method: "GET", url: "/api/v1/plugins/:id" },
1461
+ { method: "POST", url: "/api/v1/workflows/run" }
1462
+ ]
1463
+ };
1464
+ }
1465
+ getBaseUrl() {
1466
+ return "http://localhost:5050/api/v1";
1467
+ }
1468
+ };
1469
+ function createMockRun(overrides = {}) {
1470
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1471
+ return {
1472
+ id: ulid(),
1473
+ name: "demo-workflow",
1474
+ version: "1.0.0",
1475
+ status: "success",
1476
+ createdAt: now,
1477
+ queuedAt: now,
1478
+ startedAt: now,
1479
+ finishedAt: now,
1480
+ trigger: {
1481
+ type: "manual",
1482
+ actor: "mock-user",
1483
+ payload: {}
1484
+ },
1485
+ jobs: [],
1486
+ artifacts: [],
1487
+ metadata: {},
1488
+ ...overrides
1489
+ };
1490
+ }
1491
+ var MockWorkflowSource = class {
1492
+ runs = [createMockRun()];
1493
+ async listRuns(_filters) {
1494
+ return {
1495
+ runs: this.runs,
1496
+ total: this.runs.length
1497
+ };
1498
+ }
1499
+ async getRun(runId) {
1500
+ return this.runs.find((run) => run.id === runId) ?? null;
1501
+ }
1502
+ async cancelRun(runId) {
1503
+ const run = await this.getRun(runId);
1504
+ if (!run) {
1505
+ throw new Error(`Run ${runId} not found`);
1506
+ }
1507
+ const updated = {
1508
+ ...run,
1509
+ status: "cancelled",
1510
+ finishedAt: (/* @__PURE__ */ new Date()).toISOString()
1511
+ };
1512
+ this.runs = this.runs.map((existing) => existing.id === runId ? updated : existing);
1513
+ return updated;
1514
+ }
1515
+ async runWorkflow(params) {
1516
+ const run = createMockRun({
1517
+ id: ulid(),
1518
+ name: params.spec.name,
1519
+ version: params.spec.version,
1520
+ status: "queued",
1521
+ metadata: params.metadata ?? {}
1522
+ });
1523
+ this.runs = [run, ...this.runs];
1524
+ return run;
1525
+ }
1526
+ async listEvents() {
1527
+ return {
1528
+ events: [],
1529
+ cursor: null
1530
+ };
1531
+ }
1532
+ // 🆕 NEW mock methods for UI
1533
+ async getStats() {
1534
+ return {
1535
+ workflows: {
1536
+ total: 5,
1537
+ active: 3,
1538
+ inactive: 2
1539
+ },
1540
+ jobs: {
1541
+ running: 2,
1542
+ pending: 1,
1543
+ completed: 15,
1544
+ failed: 3
1545
+ },
1546
+ crons: {
1547
+ total: 4,
1548
+ enabled: 3,
1549
+ disabled: 1
1550
+ },
1551
+ activeExecutions: [
1552
+ {
1553
+ id: "job-1",
1554
+ type: "workflow:demo",
1555
+ workflowName: "Demo Workflow",
1556
+ status: "running",
1557
+ progress: 45,
1558
+ progressMessage: "Processing step 2 of 4",
1559
+ startedAt: new Date(Date.now() - 3e4).toISOString(),
1560
+ durationMs: 3e4
1561
+ },
1562
+ {
1563
+ id: "job-2",
1564
+ type: "workflow:build",
1565
+ workflowName: "Build Pipeline",
1566
+ status: "running",
1567
+ progress: 75,
1568
+ progressMessage: "Running tests",
1569
+ startedAt: new Date(Date.now() - 12e4).toISOString(),
1570
+ durationMs: 12e4
1571
+ }
1572
+ ],
1573
+ recentActivity: [
1574
+ {
1575
+ id: "job-3",
1576
+ type: "workflow:deploy",
1577
+ workflowName: "Deploy to Production",
1578
+ status: "completed",
1579
+ finishedAt: new Date(Date.now() - 3e5).toISOString(),
1580
+ durationMs: 18e4
1581
+ },
1582
+ {
1583
+ id: "job-4",
1584
+ type: "workflow:test",
1585
+ workflowName: "Integration Tests",
1586
+ status: "failed",
1587
+ finishedAt: new Date(Date.now() - 6e5).toISOString(),
1588
+ durationMs: 45e3,
1589
+ error: "Test suite failed: 3 of 15 tests failed"
1590
+ }
1591
+ ]
1592
+ };
1593
+ }
1594
+ async listWorkflows(_filters) {
1595
+ return {
1596
+ workflows: [
1597
+ {
1598
+ id: "demo-workflow",
1599
+ name: "Demo Workflow",
1600
+ description: "Example workflow for testing",
1601
+ source: "manifest",
1602
+ pluginId: "demo-plugin",
1603
+ status: "active",
1604
+ tags: ["demo", "test"]
1605
+ },
1606
+ {
1607
+ id: "build-pipeline",
1608
+ name: "Build Pipeline",
1609
+ description: "CI/CD build workflow",
1610
+ source: "standalone",
1611
+ status: "active",
1612
+ tags: ["ci", "build"]
1613
+ },
1614
+ {
1615
+ id: "deploy-prod",
1616
+ name: "Deploy to Production",
1617
+ description: "Production deployment workflow",
1618
+ source: "manifest",
1619
+ pluginId: "deploy-plugin",
1620
+ status: "active",
1621
+ tags: ["deploy", "production"]
1622
+ }
1623
+ ]
1624
+ };
1625
+ }
1626
+ async getWorkflow(workflowId) {
1627
+ const workflows = await this.listWorkflows();
1628
+ return workflows.workflows.find((w) => w.id === workflowId) ?? null;
1629
+ }
1630
+ async runWorkflowById(workflowId, _input) {
1631
+ const runId = ulid();
1632
+ console.log(`[MockWorkflowSource] Running workflow ${workflowId}, run ID: ${runId}`);
1633
+ return {
1634
+ runId,
1635
+ status: "pending"
1636
+ };
1637
+ }
1638
+ async listJobs(filters) {
1639
+ const mockJobs = [
1640
+ {
1641
+ id: "job-1",
1642
+ type: "workflow:demo",
1643
+ status: "running",
1644
+ priority: 5,
1645
+ createdAt: new Date(Date.now() - 6e4).toISOString(),
1646
+ startedAt: new Date(Date.now() - 3e4).toISOString(),
1647
+ attempt: 1,
1648
+ maxRetries: 3,
1649
+ progress: 45,
1650
+ progressMessage: "Processing step 2 of 4"
1651
+ },
1652
+ {
1653
+ id: "job-2",
1654
+ type: "workflow:build",
1655
+ status: "completed",
1656
+ priority: 8,
1657
+ createdAt: new Date(Date.now() - 3e5).toISOString(),
1658
+ startedAt: new Date(Date.now() - 28e4).toISOString(),
1659
+ finishedAt: new Date(Date.now() - 12e4).toISOString(),
1660
+ attempt: 1,
1661
+ maxRetries: 3,
1662
+ result: { success: true }
1663
+ },
1664
+ {
1665
+ id: "job-3",
1666
+ type: "workflow:test",
1667
+ status: "failed",
1668
+ priority: 5,
1669
+ createdAt: new Date(Date.now() - 6e5).toISOString(),
1670
+ startedAt: new Date(Date.now() - 58e4).toISOString(),
1671
+ finishedAt: new Date(Date.now() - 535e3).toISOString(),
1672
+ attempt: 3,
1673
+ maxRetries: 3,
1674
+ error: "Test suite failed: 3 of 15 tests failed"
1675
+ }
1676
+ ];
1677
+ let filtered = mockJobs;
1678
+ if (filters?.status) {
1679
+ filtered = filtered.filter((j) => j.status === filters.status);
1680
+ }
1681
+ if (filters?.type) {
1682
+ filtered = filtered.filter((j) => j.type.includes(filters.type));
1683
+ }
1684
+ return { jobs: filtered };
1685
+ }
1686
+ async getJob(jobId) {
1687
+ const jobs = await this.listJobs();
1688
+ return jobs.jobs.find((j) => j.id === jobId) ?? null;
1689
+ }
1690
+ async getJobSteps(jobId) {
1691
+ return {
1692
+ jobId,
1693
+ workflowName: "Demo Workflow",
1694
+ status: "running",
1695
+ steps: [
1696
+ {
1697
+ name: "checkout",
1698
+ handler: "git-checkout",
1699
+ status: "completed",
1700
+ startedAt: new Date(Date.now() - 12e4).toISOString(),
1701
+ finishedAt: new Date(Date.now() - 11e4).toISOString(),
1702
+ durationMs: 1e4
1703
+ },
1704
+ {
1705
+ name: "build",
1706
+ handler: "npm-build",
1707
+ status: "running",
1708
+ progress: 65,
1709
+ startedAt: new Date(Date.now() - 11e4).toISOString()
1710
+ },
1711
+ {
1712
+ name: "test",
1713
+ handler: "npm-test",
1714
+ status: "pending"
1715
+ },
1716
+ {
1717
+ name: "deploy",
1718
+ handler: "k8s-deploy",
1719
+ status: "pending"
1720
+ }
1721
+ ],
1722
+ currentStep: 1
1723
+ };
1724
+ }
1725
+ async getJobLogs(jobId, _filters) {
1726
+ return {
1727
+ jobId,
1728
+ logs: [
1729
+ {
1730
+ timestamp: new Date(Date.now() - 12e4).toISOString(),
1731
+ level: "info",
1732
+ message: "Starting workflow execution",
1733
+ context: { step: "init" }
1734
+ },
1735
+ {
1736
+ timestamp: new Date(Date.now() - 115e3).toISOString(),
1737
+ level: "info",
1738
+ message: "Checking out code from repository",
1739
+ context: { step: "checkout" }
1740
+ },
1741
+ {
1742
+ timestamp: new Date(Date.now() - 11e4).toISOString(),
1743
+ level: "info",
1744
+ message: "Checkout completed successfully",
1745
+ context: { step: "checkout", duration: 1e4 }
1746
+ },
1747
+ {
1748
+ timestamp: new Date(Date.now() - 105e3).toISOString(),
1749
+ level: "info",
1750
+ message: "Installing dependencies",
1751
+ context: { step: "build" }
1752
+ },
1753
+ {
1754
+ timestamp: new Date(Date.now() - 85e3).toISOString(),
1755
+ level: "info",
1756
+ message: "Running build scripts",
1757
+ context: { step: "build" }
1758
+ },
1759
+ {
1760
+ timestamp: new Date(Date.now() - 6e4).toISOString(),
1761
+ level: "warn",
1762
+ message: 'Build warning: Unused variable "foo" in module "bar"',
1763
+ context: { step: "build" }
1764
+ }
1765
+ ],
1766
+ total: 6,
1767
+ hasMore: false
1768
+ };
1769
+ }
1770
+ async listCronJobs() {
1771
+ return {
1772
+ crons: [
1773
+ {
1774
+ id: "daily-backup",
1775
+ schedule: "0 2 * * *",
1776
+ jobType: "backup:database",
1777
+ timezone: "UTC",
1778
+ enabled: true,
1779
+ lastRun: new Date(Date.now() - 864e5).toISOString(),
1780
+ nextRun: new Date(Date.now() + 864e5).toISOString(),
1781
+ pluginId: "backup-plugin"
1782
+ },
1783
+ {
1784
+ id: "hourly-sync",
1785
+ schedule: "0 * * * *",
1786
+ jobType: "sync:data",
1787
+ timezone: "UTC",
1788
+ enabled: true,
1789
+ lastRun: new Date(Date.now() - 36e5).toISOString(),
1790
+ nextRun: new Date(Date.now() + 6e5).toISOString(),
1791
+ pluginId: "sync-plugin"
1792
+ },
1793
+ {
1794
+ id: "weekly-report",
1795
+ schedule: "0 9 * * 1",
1796
+ jobType: "report:generate",
1797
+ timezone: "America/New_York",
1798
+ enabled: false,
1799
+ pluginId: "report-plugin"
1800
+ }
1801
+ ]
1802
+ };
1803
+ }
1804
+ async cancelWorkflowRun(runId) {
1805
+ return { cancelled: true, runId };
1806
+ }
1807
+ async getWorkflowRuns(workflowId, _filters) {
1808
+ return {
1809
+ workflowId,
1810
+ runs: [
1811
+ {
1812
+ id: "run-1",
1813
+ workflowId,
1814
+ status: "completed",
1815
+ trigger: { type: "manual", user: "admin" },
1816
+ startedAt: new Date(Date.now() - 36e5).toISOString(),
1817
+ finishedAt: new Date(Date.now() - 342e4).toISOString(),
1818
+ durationMs: 18e4
1819
+ },
1820
+ {
1821
+ id: "run-2",
1822
+ workflowId,
1823
+ status: "failed",
1824
+ trigger: { type: "cron" },
1825
+ startedAt: new Date(Date.now() - 72e5).toISOString(),
1826
+ finishedAt: new Date(Date.now() - 7155e3).toISOString(),
1827
+ durationMs: 45e3,
1828
+ error: 'Step "deploy" failed: connection timeout'
1829
+ },
1830
+ {
1831
+ id: "run-3",
1832
+ workflowId,
1833
+ status: "completed",
1834
+ trigger: { type: "api", user: "ci-system" },
1835
+ startedAt: new Date(Date.now() - 864e5).toISOString(),
1836
+ finishedAt: new Date(Date.now() - 8622e4).toISOString(),
1837
+ durationMs: 18e4
1838
+ }
1839
+ ],
1840
+ total: 3
1841
+ };
1842
+ }
1843
+ };
1844
+
1845
+ // src/mocks/mock-cache-source.ts
1846
+ var MockCacheSource = class {
1847
+ async invalidateCache() {
1848
+ return {
1849
+ invalidated: true,
1850
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1851
+ previousRev: 1,
1852
+ newRev: 2,
1853
+ pluginsDiscovered: 4
1854
+ };
1855
+ }
1856
+ };
1857
+
1858
+ // src/mocks/mock-observability-source.ts
1859
+ function delay2(ms) {
1860
+ return new Promise((resolve) => {
1861
+ setTimeout(() => resolve(), ms);
1862
+ });
1863
+ }
1864
+ var MockObservabilitySource = class {
1865
+ async getStateBrokerStats() {
1866
+ await delay2(150);
1867
+ return {
1868
+ uptime: 36e5,
1869
+ // 1 hour
1870
+ totalEntries: 42,
1871
+ totalSize: 10240,
1872
+ // 10KB
1873
+ hitRate: 0.85,
1874
+ missRate: 0.15,
1875
+ evictions: 5,
1876
+ namespaces: {
1877
+ mind: {
1878
+ entries: 20,
1879
+ hits: 100,
1880
+ misses: 10,
1881
+ size: 5120
1882
+ },
1883
+ workflow: {
1884
+ entries: 15,
1885
+ hits: 80,
1886
+ misses: 5,
1887
+ size: 3072
1888
+ },
1889
+ plugin: {
1890
+ entries: 7,
1891
+ hits: 30,
1892
+ misses: 2,
1893
+ size: 2048
1894
+ }
1895
+ }
1896
+ };
1897
+ }
1898
+ async getDevKitHealth() {
1899
+ await delay2(200);
1900
+ return {
1901
+ healthScore: 68,
1902
+ grade: "D",
1903
+ issues: {
1904
+ duplicateDeps: 30,
1905
+ missingReadmes: 12,
1906
+ typeErrors: 3012,
1907
+ brokenImports: 5,
1908
+ unusedExports: 120
1909
+ },
1910
+ packages: 91,
1911
+ avgTypeCoverage: 91.1
1912
+ };
1913
+ }
1914
+ async getPrometheusMetrics() {
1915
+ await delay2(180);
1916
+ const now = Date.now();
1917
+ const startTime = now - 72e5;
1918
+ return {
1919
+ requests: {
1920
+ total: 1542,
1921
+ success: 1489,
1922
+ clientErrors: 38,
1923
+ serverErrors: 15
1924
+ },
1925
+ latency: {
1926
+ average: 47.3,
1927
+ min: 3.2,
1928
+ max: 892.5,
1929
+ p50: 38.1,
1930
+ p95: 125.7,
1931
+ p99: 287.4
1932
+ },
1933
+ perPlugin: [
1934
+ {
1935
+ pluginId: "workflow",
1936
+ requests: 523,
1937
+ errors: 12,
1938
+ latency: {
1939
+ average: 52.1,
1940
+ min: 5.3,
1941
+ max: 345.2
1942
+ }
1943
+ },
1944
+ {
1945
+ pluginId: "mind",
1946
+ requests: 387,
1947
+ errors: 8,
1948
+ latency: {
1949
+ average: 68.5,
1950
+ min: 12.1,
1951
+ max: 892.5
1952
+ }
1953
+ },
1954
+ {
1955
+ pluginId: "commit",
1956
+ requests: 142,
1957
+ errors: 3,
1958
+ latency: {
1959
+ average: 35.2,
1960
+ min: 8.7,
1961
+ max: 156.3
1962
+ }
1963
+ }
1964
+ ],
1965
+ perTenant: [
1966
+ {
1967
+ tenantId: "default",
1968
+ requests: 1542,
1969
+ errors: 53,
1970
+ latency: {
1971
+ average: 47.3
1972
+ }
1973
+ }
1974
+ ],
1975
+ errors: {
1976
+ byStatusCode: {
1977
+ 400: 12,
1978
+ 404: 18,
1979
+ 422: 8,
1980
+ 500: 10,
1981
+ 503: 5
1982
+ },
1983
+ recent: [
1984
+ {
1985
+ timestamp: now - 12e4,
1986
+ statusCode: 500,
1987
+ errorCode: "INTERNAL_ERROR",
1988
+ message: "Database connection timeout"
1989
+ },
1990
+ {
1991
+ timestamp: now - 3e5,
1992
+ statusCode: 404,
1993
+ message: "Resource not found"
1994
+ },
1995
+ {
1996
+ timestamp: now - 45e4,
1997
+ statusCode: 422,
1998
+ errorCode: "VALIDATION_ERROR",
1999
+ message: "Invalid request payload"
2000
+ }
2001
+ ]
2002
+ },
2003
+ timestamps: {
2004
+ startTime,
2005
+ lastRequest: now - 2500
2006
+ },
2007
+ redis: {
2008
+ updates: 342,
2009
+ healthyTransitions: 2,
2010
+ unhealthyTransitions: 1,
2011
+ lastStatus: {
2012
+ healthy: true,
2013
+ state: "ready",
2014
+ role: "master"
2015
+ }
2016
+ },
2017
+ pluginMounts: {
2018
+ total: 8,
2019
+ succeeded: 7,
2020
+ failed: 1,
2021
+ elapsedMs: 1247
2022
+ },
2023
+ uptime: {
2024
+ seconds: 7200,
2025
+ startTime: new Date(startTime).toISOString(),
2026
+ lastRequest: new Date(now - 2500).toISOString()
2027
+ }
2028
+ };
2029
+ }
2030
+ async queryLogs(filters) {
2031
+ await delay2(200);
2032
+ const now = Date.now();
2033
+ const oldest = new Date(now - 36e5).toISOString();
2034
+ const newest = new Date(now).toISOString();
2035
+ const mockLogs = Array.from({ length: filters.limit || 20 }, (_, i) => ({
2036
+ time: new Date(now - i * 6e4).toISOString(),
2037
+ level: ["info", "warn", "error"][i % 3],
2038
+ msg: `Mock log entry ${i + 1}`,
2039
+ plugin: filters.plugin || ["rest-api", "workflow", "mind"][i % 3],
2040
+ executionId: filters.executionId || `exec-${i}`,
2041
+ tenantId: filters.tenantId || "default",
2042
+ meta: { mockData: true, index: i }
2043
+ }));
2044
+ return {
2045
+ ok: true,
2046
+ data: {
2047
+ logs: mockLogs,
2048
+ total: 42,
2049
+ filters,
2050
+ bufferStats: {
2051
+ size: mockLogs.length,
2052
+ maxSize: 1e3,
2053
+ oldest,
2054
+ newest
2055
+ }
2056
+ }
2057
+ };
2058
+ }
2059
+ subscribeToSystemEvents(onEvent, _onError) {
2060
+ const interval = setInterval(() => {
2061
+ const now = Date.now();
2062
+ if (Math.random() > 0.5) {
2063
+ onEvent({
2064
+ type: "health",
2065
+ status: "healthy",
2066
+ ts: new Date(now).toISOString(),
2067
+ ready: true,
2068
+ reason: null,
2069
+ registryPartial: false,
2070
+ registryStale: false,
2071
+ registryLoaded: true,
2072
+ pluginMountInProgress: false,
2073
+ pluginRoutesMounted: true,
2074
+ pluginsMounted: 7,
2075
+ pluginsFailed: 1,
2076
+ lastPluginMountTs: new Date(now - 6e4).toISOString(),
2077
+ pluginRoutesLastDurationMs: 1247,
2078
+ redisEnabled: true,
2079
+ redisHealthy: true
2080
+ });
2081
+ } else {
2082
+ onEvent({
2083
+ type: "registry",
2084
+ rev: Math.random().toString(36).substring(7),
2085
+ generatedAt: new Date(now).toISOString(),
2086
+ partial: false,
2087
+ stale: false,
2088
+ expiresAt: new Date(now + 3e5).toISOString(),
2089
+ ttlMs: 3e5,
2090
+ checksum: Math.random().toString(36).substring(2, 15),
2091
+ checksumAlgorithm: "sha256",
2092
+ previousChecksum: null
2093
+ });
2094
+ }
2095
+ }, 3e3);
2096
+ return () => {
2097
+ clearInterval(interval);
2098
+ };
2099
+ }
2100
+ subscribeToLogs(onLog, _onError, filters) {
2101
+ let counter = 0;
2102
+ const interval = setInterval(() => {
2103
+ const now = Date.now();
2104
+ onLog({
2105
+ time: new Date(now).toISOString(),
2106
+ level: ["info", "warn", "error"][counter % 3],
2107
+ msg: `Mock live log ${counter + 1}`,
2108
+ plugin: filters?.plugin || ["rest-api", "workflow", "mind"][counter % 3],
2109
+ executionId: filters?.executionId || `exec-${counter}`,
2110
+ tenantId: filters?.tenantId || "default",
2111
+ meta: { mockData: true, counter }
2112
+ });
2113
+ counter++;
2114
+ }, 2e3);
2115
+ return () => {
2116
+ clearInterval(interval);
2117
+ };
2118
+ }
2119
+ async getLog(_id, includeRelated) {
2120
+ await delay2(200);
2121
+ const now = Date.now();
2122
+ const mockLog = {
2123
+ id: _id,
2124
+ time: new Date(now - 12e4).toISOString(),
2125
+ // 2 minutes ago
2126
+ level: "error",
2127
+ msg: `Mock log entry with id ${_id}`,
2128
+ plugin: "rest-api",
2129
+ executionId: `exec-${_id}`,
2130
+ tenantId: "default",
2131
+ requestId: `req-${_id}`,
2132
+ traceId: `trace-${_id}`,
2133
+ err: {
2134
+ name: "MockError",
2135
+ message: "This is a mock error for demonstration",
2136
+ stack: `MockError: This is a mock error for demonstration
2137
+ at mockFunction (mock.ts:42)
2138
+ at handler (handler.ts:89)
2139
+ at process (process.ts:123)`
2140
+ },
2141
+ meta: { mockData: true }
2142
+ };
2143
+ let related;
2144
+ if (includeRelated) {
2145
+ related = Array.from({ length: 3 }, (_, i) => ({
2146
+ id: `${_id}-related-${i}`,
2147
+ time: new Date(now - (12e4 + i * 1e3)).toISOString(),
2148
+ level: ["info", "debug", "error"][i % 3],
2149
+ msg: `Mock related log ${i + 1}`,
2150
+ plugin: "rest-api",
2151
+ executionId: mockLog.executionId,
2152
+ requestId: mockLog.requestId,
2153
+ traceId: mockLog.traceId,
2154
+ meta: { mockData: true, relatedIndex: i }
2155
+ }));
2156
+ }
2157
+ return { log: mockLog, related };
2158
+ }
2159
+ async getRelatedLogs(_id) {
2160
+ await delay2(150);
2161
+ const now = Date.now();
2162
+ const mockLogs = Array.from({ length: 5 }, (_, i) => ({
2163
+ id: `${_id}-related-${i}`,
2164
+ time: new Date(now - (12e4 + i * 1e3)).toISOString(),
2165
+ level: ["info", "debug", "warn", "error"][i % 4],
2166
+ msg: `Mock related log ${i + 1}`,
2167
+ plugin: "rest-api",
2168
+ executionId: `exec-${_id}`,
2169
+ requestId: `req-${_id}`,
2170
+ traceId: `trace-${_id}`,
2171
+ meta: { mockData: true, relatedIndex: i }
2172
+ }));
2173
+ return {
2174
+ total: mockLogs.length,
2175
+ logs: mockLogs,
2176
+ correlationKeys: {
2177
+ requestId: `req-${_id}`,
2178
+ traceId: `trace-${_id}`,
2179
+ executionId: `exec-${_id}`
2180
+ }
2181
+ };
2182
+ }
2183
+ async summarizeLogs(request) {
2184
+ await delay2(1500);
2185
+ return {
2186
+ ok: true,
2187
+ data: {
2188
+ summary: {
2189
+ question: request.question,
2190
+ timeRange: {
2191
+ from: request.timeRange?.from || null,
2192
+ to: request.timeRange?.to || null
2193
+ },
2194
+ total: 42,
2195
+ stats: {
2196
+ total: 42,
2197
+ byLevel: {
2198
+ error: 3,
2199
+ warn: 5,
2200
+ info: 34
2201
+ },
2202
+ byPlugin: {
2203
+ "rest-api": 20,
2204
+ "workflow": 15,
2205
+ "mind": 7
2206
+ },
2207
+ topErrors: [
2208
+ { message: "Connection timeout", count: 2 },
2209
+ { message: "Invalid parameter", count: 1 }
2210
+ ],
2211
+ timeRange: {
2212
+ from: request.timeRange?.from || null,
2213
+ to: request.timeRange?.to || null
2214
+ }
2215
+ },
2216
+ groups: null
2217
+ },
2218
+ aiSummary: `## Mock AI Summary
2219
+
2220
+ Based on the analysis of ${42} log entries:
2221
+
2222
+ **Key Findings:**
2223
+ - Total of 3 errors and 5 warnings detected
2224
+ - Most active component: rest-api (20 logs)
2225
+ - Primary issue: Connection timeouts (2 occurrences)
2226
+
2227
+ **Timeline:**
2228
+ The system has been mostly stable with info-level logs. Two connection timeout errors were observed, likely related to external service availability.
2229
+
2230
+ **Recommendations:**
2231
+ 1. Investigate network connectivity to external services
2232
+ 2. Consider implementing retry logic with exponential backoff
2233
+ 3. Monitor timeout patterns over next 24 hours
2234
+
2235
+ *Note: This is mock data from MockObservabilitySource*`,
2236
+ message: null
2237
+ }
2238
+ };
2239
+ }
2240
+ async getMetricsHistory(query) {
2241
+ await delay2(100);
2242
+ const now = Date.now();
2243
+ const rangeMs = {
2244
+ "1m": 60 * 1e3,
2245
+ "5m": 5 * 60 * 1e3,
2246
+ "10m": 10 * 60 * 1e3,
2247
+ "30m": 30 * 60 * 1e3,
2248
+ "1h": 60 * 60 * 1e3
2249
+ }[query.range];
2250
+ const intervalMs = query.interval === "1m" ? 60 * 1e3 : query.interval === "5m" ? 5 * 60 * 1e3 : 5e3;
2251
+ const points = [];
2252
+ for (let t = now - rangeMs; t <= now; t += intervalMs) {
2253
+ let value = 0;
2254
+ switch (query.metric) {
2255
+ case "requests":
2256
+ value = 100 + Math.floor(Math.random() * 50);
2257
+ break;
2258
+ case "errors":
2259
+ value = Math.floor(Math.random() * 5);
2260
+ break;
2261
+ case "latency":
2262
+ value = 30 + Math.floor(Math.random() * 20);
2263
+ break;
2264
+ case "uptime":
2265
+ value = (now - t) / 1e3;
2266
+ break;
2267
+ }
2268
+ points.push({ timestamp: t, value });
2269
+ }
2270
+ return points;
2271
+ }
2272
+ async getMetricsHeatmap(query) {
2273
+ await delay2(150);
2274
+ const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
2275
+ const cells = [];
2276
+ for (const day of days) {
2277
+ for (let hour = 0; hour < 24; hour++) {
2278
+ cells.push({ day, hour, value: mockHeatmapValue(query.metric, hour) });
2279
+ }
2280
+ }
2281
+ return cells;
2282
+ }
2283
+ async queryIncidents(query) {
2284
+ await delay2(200);
2285
+ const mockIncidents = [
2286
+ {
2287
+ id: "inc-1",
2288
+ type: "latency_spike",
2289
+ severity: "warning",
2290
+ title: "Elevated API Latency",
2291
+ details: "Average latency increased to 250ms (baseline: 50ms)",
2292
+ rootCause: [
2293
+ {
2294
+ factor: "Database connection pool exhaustion",
2295
+ confidence: 0.85,
2296
+ evidence: "Connection pool utilization at 100%, wait queue growing"
2297
+ },
2298
+ {
2299
+ factor: "Increased query complexity",
2300
+ confidence: 0.6,
2301
+ evidence: "Average query time increased 3x in the last hour"
2302
+ }
2303
+ ],
2304
+ affectedServices: ["rest-api", "workflow-runtime"],
2305
+ timestamp: Date.now() - 2 * 60 * 60 * 1e3,
2306
+ // 2 hours ago
2307
+ resolvedAt: Date.now() - 1 * 60 * 60 * 1e3,
2308
+ // 1 hour ago
2309
+ resolutionNotes: "Increased connection pool size from 10 to 20",
2310
+ metadata: { peakLatency: 350, duration: "45m" }
2311
+ },
2312
+ {
2313
+ id: "inc-2",
2314
+ type: "error_rate",
2315
+ severity: "critical",
2316
+ title: "High Error Rate in Mind Plugin",
2317
+ details: "Error rate spiked to 15% (baseline: <1%)",
2318
+ affectedServices: ["mind-engine"],
2319
+ timestamp: Date.now() - 30 * 60 * 1e3,
2320
+ // 30 minutes ago
2321
+ metadata: { errorCount: 47, requestCount: 310 }
2322
+ },
2323
+ {
2324
+ id: "inc-3",
2325
+ type: "plugin_failure",
2326
+ severity: "warning",
2327
+ title: "Plugin Mount Timeout",
2328
+ details: "workflow plugin took 15s to mount (expected: <3s)",
2329
+ affectedServices: ["workflow-runtime"],
2330
+ timestamp: Date.now() - 10 * 60 * 1e3,
2331
+ // 10 minutes ago
2332
+ resolvedAt: Date.now() - 5 * 60 * 1e3,
2333
+ // 5 minutes ago
2334
+ resolutionNotes: "Plugin restarted successfully"
2335
+ }
2336
+ ];
2337
+ let filtered = [...mockIncidents];
2338
+ if (query?.severity) {
2339
+ const severityList = Array.isArray(query.severity) ? query.severity : [query.severity];
2340
+ filtered = filtered.filter((inc) => severityList.includes(inc.severity));
2341
+ }
2342
+ if (query?.type) {
2343
+ const typeList = Array.isArray(query.type) ? query.type : [query.type];
2344
+ filtered = filtered.filter((inc) => typeList.includes(inc.type));
2345
+ }
2346
+ if (query?.from) {
2347
+ filtered = filtered.filter((inc) => inc.timestamp >= query.from);
2348
+ }
2349
+ if (query?.to) {
2350
+ filtered = filtered.filter((inc) => inc.timestamp <= query.to);
2351
+ }
2352
+ if (!query?.includeResolved) {
2353
+ filtered = filtered.filter((inc) => !inc.resolvedAt);
2354
+ }
2355
+ if (query?.limit) {
2356
+ filtered = filtered.slice(0, query.limit);
2357
+ }
2358
+ return filtered;
2359
+ }
2360
+ async createIncident(payload) {
2361
+ await delay2(150);
2362
+ const incident = {
2363
+ id: `inc-${Date.now()}`,
2364
+ ...payload,
2365
+ timestamp: payload.timestamp || Date.now()
2366
+ };
2367
+ return incident;
2368
+ }
2369
+ async resolveIncident(_id, resolutionNotes) {
2370
+ await delay2(150);
2371
+ const incident = {
2372
+ id: _id,
2373
+ type: "error_rate",
2374
+ severity: "critical",
2375
+ title: "Mock Incident",
2376
+ details: "Mock incident details",
2377
+ timestamp: Date.now() - 60 * 60 * 1e3,
2378
+ resolvedAt: Date.now(),
2379
+ resolutionNotes
2380
+ };
2381
+ return incident;
2382
+ }
2383
+ async listIncidents(query) {
2384
+ await delay2(150);
2385
+ const incidents = await this.queryIncidents(query);
2386
+ const unresolved = incidents.filter((i) => !i.resolvedAt).length;
2387
+ return {
2388
+ ok: true,
2389
+ data: {
2390
+ incidents,
2391
+ summary: {
2392
+ total: incidents.length,
2393
+ unresolved,
2394
+ bySeverity: {
2395
+ critical: incidents.filter((i) => i.severity === "critical").length,
2396
+ warning: incidents.filter((i) => i.severity === "warning").length,
2397
+ info: incidents.filter((i) => i.severity === "info").length
2398
+ },
2399
+ showing: incidents.length
2400
+ }
2401
+ }
2402
+ };
2403
+ }
2404
+ async getIncident(_id) {
2405
+ await delay2(150);
2406
+ const incident = {
2407
+ id: _id,
2408
+ type: "error_rate",
2409
+ severity: "critical",
2410
+ title: "High Error Rate Detected",
2411
+ details: "Error rate exceeded threshold of 10%",
2412
+ timestamp: Date.now() - 60 * 60 * 1e3,
2413
+ affectedServices: ["rest-api", "workflow-engine"],
2414
+ metadata: {
2415
+ errorRate: 15.2,
2416
+ threshold: 10
2417
+ },
2418
+ relatedData: {
2419
+ logs: {
2420
+ errorCount: 42,
2421
+ warnCount: 18,
2422
+ timeRange: [Date.now() - 5 * 60 * 1e3, Date.now()],
2423
+ sampleErrors: [
2424
+ "TypeError: Cannot read property 'name' of undefined",
2425
+ "Error: Failed to connect to database",
2426
+ "Error: Timeout exceeded for operation"
2427
+ ]
2428
+ },
2429
+ metrics: {
2430
+ before: {
2431
+ errorRate: 2.1,
2432
+ avgLatency: 45,
2433
+ totalRequests: 1e3
2434
+ },
2435
+ during: {
2436
+ errorRate: 15.2,
2437
+ avgLatency: 120,
2438
+ totalRequests: 500,
2439
+ totalErrors: 76
2440
+ }
2441
+ },
2442
+ timeline: [
2443
+ {
2444
+ timestamp: Date.now(),
2445
+ event: "Incident detected: error_rate",
2446
+ source: "detector"
2447
+ },
2448
+ {
2449
+ timestamp: Date.now() - 2 * 60 * 1e3,
2450
+ event: "Error: Failed to connect to database",
2451
+ source: "logs"
2452
+ },
2453
+ {
2454
+ timestamp: Date.now() - 3 * 60 * 1e3,
2455
+ event: "Error: Timeout exceeded for operation",
2456
+ source: "logs"
2457
+ }
2458
+ ]
2459
+ }
2460
+ };
2461
+ return {
2462
+ ok: true,
2463
+ data: incident
2464
+ };
2465
+ }
2466
+ async analyzeIncident(_id) {
2467
+ await delay2(800);
2468
+ return {
2469
+ ok: true,
2470
+ data: {
2471
+ summary: "High error rate detected due to database connection issues and timeout problems. System experienced 15.2% error rate, significantly above the 2.1% baseline.",
2472
+ rootCauses: [
2473
+ {
2474
+ factor: "Database connection pool exhaustion",
2475
+ confidence: 0.85,
2476
+ evidence: 'Multiple "Failed to connect to database" errors in logs. Error rate correlation with database connection attempts.'
2477
+ },
2478
+ {
2479
+ factor: "Increased request timeout frequency",
2480
+ confidence: 0.72,
2481
+ evidence: "Timeout errors increased from 0% to 8% during incident window. Latency jumped from 45ms to 120ms."
2482
+ },
2483
+ {
2484
+ factor: "Potential memory leak in error handler",
2485
+ confidence: 0.45,
2486
+ evidence: "TypeError suggests undefined object access, possibly due to improper error handling initialization."
2487
+ }
2488
+ ],
2489
+ patterns: [
2490
+ "Error rate spike correlates with increased latency (45ms \u2192 120ms)",
2491
+ "Database connection errors preceded timeout errors by ~1 minute",
2492
+ "Error rate increased 7x above baseline during incident"
2493
+ ],
2494
+ recommendations: [
2495
+ "Increase database connection pool size and implement connection retry logic with exponential backoff",
2496
+ "Add circuit breaker pattern to prevent cascading failures when database is unavailable",
2497
+ "Review error handling code for undefined object access, especially in database connection error paths",
2498
+ "Implement request timeout monitoring and alerting at 75% of threshold",
2499
+ "Consider adding database health check endpoint to proactively detect connection issues"
2500
+ ],
2501
+ analyzedAt: Date.now(),
2502
+ cached: false
2503
+ }
2504
+ };
2505
+ }
2506
+ async chatWithInsights(question, context) {
2507
+ await delay2(500);
2508
+ return {
2509
+ answer: `Based on the current system metrics, here's my analysis of "${question}": The system is performing well with average latency of 45ms and 99.2% success rate. No critical issues detected.`,
2510
+ context: [
2511
+ "Current metrics: 1,234 requests in the last hour",
2512
+ "Average latency: 45ms",
2513
+ "Error rate: 0.8%",
2514
+ context?.includeIncidents ? "2 active incidents" : void 0
2515
+ ].filter(Boolean),
2516
+ usage: {
2517
+ promptTokens: 150,
2518
+ completionTokens: 80,
2519
+ totalTokens: 230
2520
+ }
2521
+ };
2522
+ }
2523
+ };
2524
+ function mockHeatmapValue(metric, hour) {
2525
+ const isBusinessHour = hour >= 9 && hour <= 17;
2526
+ if (metric === "latency") {
2527
+ return 30 + Math.floor(Math.random() * 40) + (isBusinessHour ? 10 : 0);
2528
+ }
2529
+ if (metric === "errors") {
2530
+ return Math.floor(Math.random() * 10);
2531
+ }
2532
+ if (metric === "requests") {
2533
+ return 50 + Math.floor(Math.random() * 100) + (isBusinessHour ? 50 : 0);
2534
+ }
2535
+ return 0;
2536
+ }
2537
+
2538
+ // src/mocks/mock-analytics-source.ts
2539
+ function delay3(ms) {
2540
+ return new Promise((resolve) => {
2541
+ setTimeout(() => resolve(), ms);
2542
+ });
2543
+ }
2544
+ var MockAnalyticsSource = class {
2545
+ mockEvents;
2546
+ constructor() {
2547
+ this.mockEvents = this.generateMockEvents();
2548
+ }
2549
+ generateMockEvents() {
2550
+ const now = Date.now();
2551
+ const events = [];
2552
+ const eventTypes = [
2553
+ "mind.query.started",
2554
+ "mind.query.completed",
2555
+ "workflow.run.started",
2556
+ "workflow.run.completed",
2557
+ "commit.generated",
2558
+ "plugin.mounted"
2559
+ ];
2560
+ const sources = ["mind", "workflow", "commit", "core"];
2561
+ const actors = ["user", "agent", "ci"];
2562
+ for (let i = 0; i < 100; i++) {
2563
+ const ts = new Date(now - i * 6e4).toISOString();
2564
+ const type = eventTypes[Math.floor(Math.random() * eventTypes.length)];
2565
+ const source = sources[Math.floor(Math.random() * sources.length)];
2566
+ const actorType = actors[Math.floor(Math.random() * actors.length)];
2567
+ events.push({
2568
+ id: `mock-event-${i}`,
2569
+ schema: "kb.v1",
2570
+ type,
2571
+ ts,
2572
+ ingestTs: ts,
2573
+ source: {
2574
+ product: source,
2575
+ version: "1.0.0"
2576
+ },
2577
+ runId: `run-${Math.floor(i / 5)}`,
2578
+ // Group every 5 events
2579
+ actor: {
2580
+ type: actorType,
2581
+ id: `${actorType}-${Math.floor(Math.random() * 10)}`,
2582
+ name: `Mock ${actorType}`
2583
+ },
2584
+ ctx: {
2585
+ workspace: "/mock/workspace",
2586
+ branch: "main"
2587
+ },
2588
+ payload: {
2589
+ duration: Math.random() * 1e3,
2590
+ success: Math.random() > 0.1
2591
+ }
2592
+ });
2593
+ }
2594
+ return events;
2595
+ }
2596
+ async getEvents(query) {
2597
+ await delay3(150);
2598
+ let filtered = [...this.mockEvents];
2599
+ if (query?.type) {
2600
+ const types = Array.isArray(query.type) ? query.type : [query.type];
2601
+ filtered = filtered.filter((e) => types.includes(e.type));
2602
+ }
2603
+ if (query?.source) {
2604
+ filtered = filtered.filter((e) => e.source.product === query.source);
2605
+ }
2606
+ if (query?.actor) {
2607
+ filtered = filtered.filter((e) => e.actor?.type === query.actor);
2608
+ }
2609
+ const limit = query?.limit || 100;
2610
+ const offset = query?.offset || 0;
2611
+ const paginated = filtered.slice(offset, offset + limit);
2612
+ return {
2613
+ events: paginated,
2614
+ total: filtered.length,
2615
+ hasMore: offset + limit < filtered.length
2616
+ };
2617
+ }
2618
+ async getStats() {
2619
+ await delay3(180);
2620
+ const byType = {};
2621
+ const bySource = {};
2622
+ const byActor = {};
2623
+ this.mockEvents.forEach((event) => {
2624
+ byType[event.type] = (byType[event.type] || 0) + 1;
2625
+ bySource[event.source.product] = (bySource[event.source.product] || 0) + 1;
2626
+ if (event.actor) {
2627
+ byActor[event.actor.type] = (byActor[event.actor.type] || 0) + 1;
2628
+ }
2629
+ });
2630
+ const timestamps = this.mockEvents.map((e) => new Date(e.ts).getTime());
2631
+ const oldestTs = Math.min(...timestamps);
2632
+ const newestTs = Math.max(...timestamps);
2633
+ return {
2634
+ totalEvents: this.mockEvents.length,
2635
+ byType,
2636
+ bySource,
2637
+ byActor,
2638
+ timeRange: {
2639
+ from: new Date(oldestTs).toISOString(),
2640
+ to: new Date(newestTs).toISOString()
2641
+ }
2642
+ };
2643
+ }
2644
+ async getBufferStatus() {
2645
+ await delay3(100);
2646
+ const timestamps = this.mockEvents.map((e) => new Date(e.ts).getTime());
2647
+ return {
2648
+ segments: 3,
2649
+ totalSizeBytes: 524288,
2650
+ // 512 KB
2651
+ oldestEventTs: new Date(Math.min(...timestamps)).toISOString(),
2652
+ newestEventTs: new Date(Math.max(...timestamps)).toISOString()
2653
+ };
2654
+ }
2655
+ async getDlqStatus() {
2656
+ await delay3(100);
2657
+ return {
2658
+ failedEvents: 2,
2659
+ oldestFailureTs: new Date(Date.now() - 36e5).toISOString()
2660
+ // 1 hour ago
2661
+ };
2662
+ }
2663
+ };
2664
+
2665
+ // src/mocks/mock-adapters-source.ts
2666
+ var MockAdaptersSource = class {
2667
+ async getLLMUsage(_options) {
2668
+ return {
2669
+ totalRequests: 1247,
2670
+ totalTokens: 3456789,
2671
+ totalCost: 12.45,
2672
+ totalCacheReadTokens: 0,
2673
+ totalBillableTokens: 3456789,
2674
+ totalCacheSavingsUsd: 0,
2675
+ byModel: {
2676
+ "gpt-4": {
2677
+ requests: 234,
2678
+ promptTokens: 45678,
2679
+ completionTokens: 23456,
2680
+ totalTokens: 69134,
2681
+ cost: 4.15,
2682
+ costPer1KTokens: 0.06,
2683
+ tokensPerRequest: 295,
2684
+ errorRate: 0.5,
2685
+ avgDurationMs: 2345,
2686
+ cacheReadTokens: 0,
2687
+ billableTokens: 69134,
2688
+ cacheSavingsUsd: 0
2689
+ },
2690
+ "gpt-3.5-turbo": {
2691
+ requests: 789,
2692
+ promptTokens: 234567,
2693
+ completionTokens: 123456,
2694
+ totalTokens: 358023,
2695
+ cost: 0.54,
2696
+ costPer1KTokens: 15e-4,
2697
+ tokensPerRequest: 454,
2698
+ errorRate: 0,
2699
+ avgDurationMs: 876,
2700
+ cacheReadTokens: 0,
2701
+ billableTokens: 358023,
2702
+ cacheSavingsUsd: 0
2703
+ },
2704
+ "claude-3-sonnet": {
2705
+ requests: 224,
2706
+ promptTokens: 567890,
2707
+ completionTokens: 234567,
2708
+ totalTokens: 802457,
2709
+ cost: 7.76,
2710
+ costPer1KTokens: 97e-4,
2711
+ tokensPerRequest: 3582,
2712
+ errorRate: 1.2,
2713
+ avgDurationMs: 1567,
2714
+ cacheReadTokens: 0,
2715
+ billableTokens: 802457,
2716
+ cacheSavingsUsd: 0
2717
+ }
2718
+ },
2719
+ errors: 12,
2720
+ timeRange: {
2721
+ from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3).toISOString(),
2722
+ to: (/* @__PURE__ */ new Date()).toISOString()
2723
+ }
2724
+ };
2725
+ }
2726
+ async getEmbeddingsUsage(_options) {
2727
+ return {
2728
+ totalRequests: 3456,
2729
+ totalTextLength: 1234567,
2730
+ totalCost: 2.47,
2731
+ errors: 8,
2732
+ avgDurationMs: 234,
2733
+ batchRequests: 456,
2734
+ singleRequests: 3e3,
2735
+ avgBatchSize: 15.3
2736
+ };
2737
+ }
2738
+ async getVectorStoreUsage(_options) {
2739
+ return {
2740
+ searchQueries: 2345,
2741
+ upsertOperations: 567,
2742
+ deleteOperations: 89,
2743
+ avgSearchDuration: 45.6,
2744
+ avgSearchScore: 0.87,
2745
+ avgResultsCount: 12.4,
2746
+ totalVectorsUpserted: 45678,
2747
+ totalVectorsDeleted: 1234
2748
+ };
2749
+ }
2750
+ async getCacheUsage(_options) {
2751
+ return {
2752
+ totalGets: 15678,
2753
+ hits: 13456,
2754
+ misses: 2222,
2755
+ hitRate: 85.8,
2756
+ sets: 3456,
2757
+ avgGetDuration: 2.3,
2758
+ avgSetDuration: 5.7
2759
+ };
2760
+ }
2761
+ async getStorageUsage(_options) {
2762
+ return {
2763
+ readOperations: 8765,
2764
+ writeOperations: 2345,
2765
+ deleteOperations: 234,
2766
+ totalBytesRead: 123456789,
2767
+ totalBytesWritten: 45678901,
2768
+ avgReadDuration: 12.4,
2769
+ avgWriteDuration: 34.5
2770
+ };
2771
+ }
2772
+ async getLLMDailyStats(_options) {
2773
+ return this.generateMockDailyStats({
2774
+ totalTokens: [1e4, 6e4],
2775
+ totalCost: [1, 6],
2776
+ avgDurationMs: [500, 2500]
2777
+ });
2778
+ }
2779
+ async getEmbeddingsDailyStats(_options) {
2780
+ return this.generateMockDailyStats({
2781
+ totalTokens: [5e3, 3e4],
2782
+ totalCost: [0.1, 0.5],
2783
+ avgDurationMs: [100, 500]
2784
+ });
2785
+ }
2786
+ async getVectorStoreDailyStats(_options) {
2787
+ return this.generateMockDailyStats({
2788
+ totalSearches: [100, 500],
2789
+ totalUpserts: [50, 200],
2790
+ totalDeletes: [10, 50],
2791
+ avgDurationMs: [30, 150]
2792
+ });
2793
+ }
2794
+ async getCacheDailyStats(_options) {
2795
+ return this.generateMockDailyStats({
2796
+ totalHits: [500, 2e3],
2797
+ totalMisses: [100, 500],
2798
+ totalSets: [200, 800],
2799
+ hitRate: [70, 95]
2800
+ });
2801
+ }
2802
+ async getStorageDailyStats(_options) {
2803
+ return this.generateMockDailyStats({
2804
+ totalBytesRead: [1e6, 1e7],
2805
+ totalBytesWritten: [5e5, 5e6],
2806
+ avgDurationMs: [10, 50]
2807
+ });
2808
+ }
2809
+ /**
2810
+ * Helper to generate mock daily stats
2811
+ */
2812
+ generateMockDailyStats(metricsRanges) {
2813
+ const days = 7;
2814
+ const stats = [];
2815
+ const now = /* @__PURE__ */ new Date();
2816
+ for (let i = days - 1; i >= 0; i--) {
2817
+ const date = new Date(now);
2818
+ date.setDate(date.getDate() - i);
2819
+ const dateStr = date.toISOString().split("T")[0];
2820
+ const metrics = {};
2821
+ for (const [key, [min, max]] of Object.entries(metricsRanges)) {
2822
+ metrics[key] = Math.floor(Math.random() * (max - min)) + min;
2823
+ }
2824
+ stats.push({
2825
+ date: dateStr,
2826
+ count: Math.floor(Math.random() * 100) + 50,
2827
+ // 50-150 requests
2828
+ metrics
2829
+ });
2830
+ }
2831
+ return stats;
2832
+ }
2833
+ };
2834
+
2835
+ // src/mocks/mock-platform-source.ts
2836
+ var MockPlatformSource = class {
2837
+ async getConfig() {
2838
+ return {
2839
+ schema: "kb.platform.config/1",
2840
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2841
+ adapters: {
2842
+ // Multi-adapter example: array of providers for LLM
2843
+ llm: ["@kb-labs/adapters-openai", "@kb-labs/adapters-vibeproxy"],
2844
+ embeddings: "@kb-labs/adapters-openai/embeddings",
2845
+ storage: "@kb-labs/adapters-fs",
2846
+ logger: "@kb-labs/adapters-pino",
2847
+ analytics: "@kb-labs/adapters-analytics-file",
2848
+ vectorStore: "@kb-labs/adapters-qdrant",
2849
+ cache: "@kb-labs/adapters-redis"
2850
+ },
2851
+ adapterOptions: {
2852
+ llm: {
2853
+ defaultModel: "gpt-4o-mini"
2854
+ },
2855
+ vectorStore: {
2856
+ url: "http://localhost:6333"
2857
+ },
2858
+ cache: {
2859
+ url: "redis://localhost:6379"
2860
+ }
2861
+ },
2862
+ execution: {
2863
+ mode: "in-process"
2864
+ },
2865
+ redacted: []
2866
+ };
2867
+ }
2868
+ };
2869
+
2870
+ // src/mocks/mock-plugins-source.ts
2871
+ var mockManifests = {
2872
+ manifests: [
2873
+ {
2874
+ pluginId: "@kb-labs/mind-plugin",
2875
+ source: {
2876
+ kind: "workspace",
2877
+ path: "/workspace/kb-labs-mind/packages/mind-plugin"
2878
+ },
2879
+ pluginRoot: "/workspace/kb-labs-mind/packages/mind-plugin",
2880
+ discoveredAt: new Date(Date.now() - 36e5).toISOString(),
2881
+ // 1 hour ago
2882
+ buildTimestamp: new Date(Date.now() - 72e5).toISOString(),
2883
+ // 2 hours ago
2884
+ manifest: {
2885
+ schema: "kb.plugin/3",
2886
+ id: "@kb-labs/mind-plugin",
2887
+ version: "0.1.0",
2888
+ display: {
2889
+ name: "Mind RAG Plugin",
2890
+ description: "Semantic code search and RAG system",
2891
+ author: "KB Labs",
2892
+ icon: "\u{1F9E0}",
2893
+ tags: ["search", "ai", "rag"]
2894
+ },
2895
+ permissions: {
2896
+ fs: { mode: "read", allow: [".kb/**", "src/**"] },
2897
+ net: { allowHosts: ["api.openai.com"] }
2898
+ },
2899
+ platform: {
2900
+ requires: ["vectorStore", "embeddings", "cache"]
2901
+ },
2902
+ cli: {
2903
+ commands: [
2904
+ {
2905
+ id: "rag-query",
2906
+ group: "mind",
2907
+ describe: "Query the RAG index",
2908
+ handler: "./dist/commands/rag-query.js",
2909
+ flags: [
2910
+ { name: "text", type: "string", required: true, description: "Query text" },
2911
+ { name: "agent", type: "boolean", description: "Use agent mode" }
2912
+ ]
2913
+ },
2914
+ {
2915
+ id: "rag-index",
2916
+ group: "mind",
2917
+ describe: "Build RAG index",
2918
+ handler: "./dist/commands/rag-index.js",
2919
+ flags: [
2920
+ { name: "scope", type: "string", default: "default", description: "Index scope" }
2921
+ ]
2922
+ }
2923
+ ]
2924
+ },
2925
+ rest: {
2926
+ basePath: "/v1/plugins/mind",
2927
+ routes: [
2928
+ {
2929
+ method: "POST",
2930
+ path: "/search",
2931
+ description: "Semantic code search",
2932
+ handler: "./dist/rest/search.js",
2933
+ timeoutMs: 3e4,
2934
+ input: { zod: "./schemas/search-input.ts#SearchInputSchema" },
2935
+ output: { zod: "./schemas/search-output.ts#SearchOutputSchema" }
2936
+ }
2937
+ ]
2938
+ }
2939
+ }
2940
+ },
2941
+ {
2942
+ pluginId: "@kb-labs/workflow-plugin",
2943
+ source: {
2944
+ kind: "workspace",
2945
+ path: "/workspace/kb-labs-workflow/packages/workflow-plugin"
2946
+ },
2947
+ pluginRoot: "/workspace/kb-labs-workflow/packages/workflow-plugin",
2948
+ discoveredAt: new Date(Date.now() - 36e5).toISOString(),
2949
+ // 1 hour ago
2950
+ buildTimestamp: new Date(Date.now() - 54e5).toISOString(),
2951
+ // 1.5 hours ago
2952
+ manifest: {
2953
+ schema: "kb.plugin/3",
2954
+ id: "@kb-labs/workflow-plugin",
2955
+ version: "1.0.0",
2956
+ display: {
2957
+ name: "Workflow Engine",
2958
+ description: "Orchestrate multi-step workflows",
2959
+ author: "KB Labs",
2960
+ icon: "\u2699\uFE0F",
2961
+ tags: ["workflow", "automation", "orchestration"]
2962
+ },
2963
+ permissions: {
2964
+ fs: { mode: "readwrite", allow: [".kb/workflows/**"] }
2965
+ },
2966
+ platform: {
2967
+ requires: ["storage", "cache"]
2968
+ },
2969
+ cli: {
2970
+ commands: [
2971
+ {
2972
+ id: "run",
2973
+ group: "workflow",
2974
+ describe: "Run a workflow",
2975
+ handler: "./dist/commands/run.js",
2976
+ flags: [
2977
+ { name: "workflow-id", type: "string", required: true },
2978
+ { name: "input", type: "string" }
2979
+ ]
2980
+ }
2981
+ ]
2982
+ },
2983
+ rest: {
2984
+ basePath: "/v1/plugins/workflow",
2985
+ routes: [
2986
+ {
2987
+ method: "POST",
2988
+ path: "/execute",
2989
+ description: "Execute workflow",
2990
+ handler: "./dist/rest/execute.js",
2991
+ input: { $ref: "#/components/schemas/WorkflowExecuteRequest" },
2992
+ output: { $ref: "#/components/schemas/WorkflowExecuteResponse" }
2993
+ },
2994
+ {
2995
+ method: "GET",
2996
+ path: "/status/:runId",
2997
+ description: "Get workflow status",
2998
+ handler: "./dist/rest/status.js",
2999
+ output: { $ref: "#/components/schemas/WorkflowStatus" }
3000
+ }
3001
+ ]
3002
+ },
3003
+ jobs: {
3004
+ handlers: [
3005
+ {
3006
+ id: "cleanup-old-runs",
3007
+ handler: "./dist/jobs/cleanup.js",
3008
+ describe: "Clean up old workflow runs"
3009
+ }
3010
+ ],
3011
+ cron: [
3012
+ {
3013
+ jobId: "cleanup-old-runs",
3014
+ schedule: "0 2 * * *",
3015
+ enabled: true
3016
+ }
3017
+ ]
3018
+ }
3019
+ }
3020
+ }
3021
+ ]
3022
+ };
3023
+ var MockPluginsSource = class {
3024
+ async getPlugins() {
3025
+ await new Promise((resolve) => {
3026
+ setTimeout(() => resolve(), 300);
3027
+ });
3028
+ return {
3029
+ ...mockManifests,
3030
+ apiBasePath: "/api/v1"
3031
+ };
3032
+ }
3033
+ async askAboutPlugin(pluginId, request) {
3034
+ await new Promise((resolve) => {
3035
+ setTimeout(() => resolve(), 1e3);
3036
+ });
3037
+ const question = request.question.toLowerCase();
3038
+ let answer = "";
3039
+ if (question.includes("permission") || question.includes("access")) {
3040
+ answer = `This plugin requires the following permissions:
3041
+
3042
+ - File System: Read-only access to .kb/** and src/** directories
3043
+ - Network: Access to api.openai.com for AI operations
3044
+
3045
+ These permissions are necessary for RAG indexing and semantic search functionality.`;
3046
+ } else if (question.includes("command") || question.includes("cli")) {
3047
+ answer = `The plugin provides 2 CLI commands:
3048
+
3049
+ 1. **rag-query** - Query the RAG index
3050
+ - Required: --text (query text)
3051
+ - Optional: --agent (use agent mode)
3052
+
3053
+ 2. **rag-index** - Build RAG index
3054
+ - Optional: --scope (default: 'default')
3055
+
3056
+ Use these commands to perform semantic code search across your codebase.`;
3057
+ } else if (question.includes("rest") || question.includes("api") || question.includes("endpoint")) {
3058
+ answer = `The plugin exposes 1 REST API endpoint:
3059
+
3060
+ **POST /v1/plugins/mind/search** - Semantic code search
3061
+ - Timeout: 30 seconds
3062
+ - Input: SearchInputSchema (query text and options)
3063
+ - Output: SearchOutputSchema (search results with relevance scores)
3064
+
3065
+ This endpoint allows integration with external tools and web interfaces.`;
3066
+ } else {
3067
+ answer = `This is the Mind RAG Plugin (v0.1.0) - a semantic code search and RAG system.
3068
+
3069
+ Key features:
3070
+ - 2 CLI commands (rag-query, rag-index)
3071
+ - 1 REST API endpoint (/search)
3072
+ - AI-powered semantic search
3073
+ - Read-only file system access
3074
+ - OpenAI API integration
3075
+
3076
+ The plugin helps developers find relevant code using natural language queries.`;
3077
+ }
3078
+ return {
3079
+ answer,
3080
+ usage: {
3081
+ promptTokens: 150,
3082
+ completionTokens: 100
3083
+ }
3084
+ };
3085
+ }
3086
+ };
3087
+
3088
+ // src/factory.ts
3089
+ function createDataSources(config) {
3090
+ if (config.mode === "mock") {
3091
+ return {
3092
+ system: new MockSystemSource(),
3093
+ workflow: new MockWorkflowSource(),
3094
+ cache: new MockCacheSource(),
3095
+ observability: new MockObservabilitySource(),
3096
+ analytics: new MockAnalyticsSource(),
3097
+ adapters: new MockAdaptersSource(),
3098
+ platform: new MockPlatformSource(),
3099
+ plugins: new MockPluginsSource()
3100
+ };
3101
+ }
3102
+ const baseUrl = config.baseUrl || "";
3103
+ const client = new HttpClient(baseUrl, config.token);
3104
+ return {
3105
+ system: new HttpSystemSource(client),
3106
+ workflow: new HttpWorkflowSource(client),
3107
+ cache: new HttpCacheSource(client),
3108
+ observability: new HttpObservabilitySource(client),
3109
+ analytics: new HttpAnalyticsSource(client),
3110
+ adapters: new HttpAdaptersSource(client),
3111
+ platform: new HttpPlatformSource(client),
3112
+ plugins: new HttpPluginsSource(client)
3113
+ };
3114
+ }
3115
+
3116
+ // src/query-keys.ts
3117
+ var qk = {
3118
+ // Audit queries
3119
+ audit: {
3120
+ all: ["audit"],
3121
+ summary: () => [...qk.audit.all, "summary"],
3122
+ runs: {
3123
+ all: () => [...qk.audit.all, "runs"],
3124
+ list: (params) => [...qk.audit.runs.all(), "list", params],
3125
+ byId: (runId) => [...qk.audit.runs.all(), "detail", runId]
3126
+ },
3127
+ report: {
3128
+ latest: () => [...qk.audit.all, "report", "latest"],
3129
+ byRunId: (runId) => [...qk.audit.all, "report", runId]
3130
+ },
3131
+ pkg: (name) => [...qk.audit.all, "pkg", name]
3132
+ },
3133
+ // Release queries
3134
+ release: {
3135
+ all: ["release"],
3136
+ preview: (params) => [...qk.release.all, "preview", params],
3137
+ runs: {
3138
+ all: () => [...qk.release.all, "runs"],
3139
+ byId: (runId) => [...qk.release.runs.all(), "detail", runId]
3140
+ },
3141
+ changelog: (params) => [...qk.release.all, "changelog", params]
3142
+ },
3143
+ // Jobs queries
3144
+ jobs: {
3145
+ all: ["jobs"],
3146
+ byId: (jobId) => [...qk.jobs.all, "detail", jobId],
3147
+ logs: {
3148
+ byJobId: (jobId, offset) => [...qk.jobs.all, "logs", jobId, offset],
3149
+ stream: (jobId) => [...qk.jobs.all, "logs", "stream", jobId]
3150
+ },
3151
+ events: (jobId) => [...qk.jobs.all, "events", jobId],
3152
+ list: (params) => [...qk.jobs.all, "list", params]
3153
+ },
3154
+ // System queries
3155
+ system: {
3156
+ all: ["system"],
3157
+ health: {
3158
+ live: () => [...qk.system.all, "health", "live"],
3159
+ ready: () => [...qk.system.all, "health", "ready"]
3160
+ },
3161
+ info: () => [...qk.system.all, "info"],
3162
+ capabilities: () => [...qk.system.all, "capabilities"],
3163
+ config: () => [...qk.system.all, "config"]
3164
+ },
3165
+ workflows: {
3166
+ all: ["workflows"],
3167
+ list: (filters) => [...qk.workflows.all, "list", filters ?? {}],
3168
+ run: (runId) => [...qk.workflows.all, "run", runId]
3169
+ },
3170
+ // DevLink queries
3171
+ devlink: {
3172
+ all: ["devlink"],
3173
+ summary: () => [...qk.devlink.all, "summary"],
3174
+ graph: () => [...qk.devlink.all, "graph"]
3175
+ },
3176
+ // Mind queries
3177
+ mind: {
3178
+ all: ["mind"],
3179
+ summary: () => [...qk.mind.all, "summary"]
3180
+ },
3181
+ // Analytics queries
3182
+ analytics: {
3183
+ all: ["analytics"],
3184
+ summary: (params) => [...qk.analytics.all, "summary", params]
3185
+ },
3186
+ // Platform queries
3187
+ platform: {
3188
+ all: ["platform"],
3189
+ config: () => [...qk.platform.all, "config"]
3190
+ }
3191
+ };
3192
+ var queryKeys = qk;
3193
+ function useHealthStatus(source) {
3194
+ return useQuery({
3195
+ queryKey: qk.system.health.live(),
3196
+ queryFn: async () => {
3197
+ try {
3198
+ return source.getHealth();
3199
+ } catch (error) {
3200
+ return {
3201
+ ok: false,
3202
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3203
+ sources: [{
3204
+ name: "system",
3205
+ ok: false,
3206
+ error: error instanceof Error ? error.message : "Unknown error"
3207
+ }]
3208
+ };
3209
+ }
3210
+ },
3211
+ refetchInterval: 3e4,
3212
+ // Poll every 30 seconds
3213
+ staleTime: 15e3,
3214
+ retry: 2,
3215
+ retryDelay: 1e3
3216
+ });
3217
+ }
3218
+ function useReadyStatus(source) {
3219
+ const httpSource = source;
3220
+ return useQuery({
3221
+ queryKey: qk.system.health.ready(),
3222
+ queryFn: async () => {
3223
+ if (httpSource.getReady) {
3224
+ return httpSource.getReady();
3225
+ }
3226
+ return {
3227
+ ready: true
3228
+ };
3229
+ },
3230
+ refetchInterval: 3e4,
3231
+ staleTime: 15e3,
3232
+ retry: 2,
3233
+ retryDelay: 1e3
3234
+ });
3235
+ }
3236
+ function useSystemInfo(source) {
3237
+ const httpSource = source;
3238
+ return useQuery({
3239
+ queryKey: qk.system.info(),
3240
+ queryFn: async () => {
3241
+ if (httpSource.getInfo) {
3242
+ return httpSource.getInfo();
3243
+ }
3244
+ return {
3245
+ cwd: process.cwd(),
3246
+ repo: void 0,
3247
+ profiles: [],
3248
+ plugins: [],
3249
+ apiVersion: "1.0.0"
3250
+ };
3251
+ },
3252
+ staleTime: 6e4
3253
+ // Cache for 1 minute
3254
+ });
3255
+ }
3256
+ function useCapabilities(source) {
3257
+ const httpSource = source;
3258
+ return useQuery({
3259
+ queryKey: qk.system.capabilities(),
3260
+ queryFn: async () => {
3261
+ if (httpSource.getCapabilities) {
3262
+ return httpSource.getCapabilities();
3263
+ }
3264
+ return {
3265
+ commands: ["audit", "release", "devlink", "mind", "analytics"],
3266
+ adapters: {
3267
+ queue: ["memory"],
3268
+ storage: ["fs"],
3269
+ auth: ["none"]
3270
+ }
3271
+ };
3272
+ },
3273
+ staleTime: 6e4
3274
+ });
3275
+ }
3276
+ function useWorkflowRuns(source, filters) {
3277
+ const queryKey = useMemo(() => qk.workflows.list(filters), [filters]);
3278
+ return useQuery({
3279
+ queryKey,
3280
+ queryFn: async () => {
3281
+ return source.listRuns(filters);
3282
+ }
3283
+ });
3284
+ }
3285
+ function useWorkflowRun(runId, source) {
3286
+ return useQuery({
3287
+ queryKey: qk.workflows.run(runId ?? ""),
3288
+ enabled: Boolean(runId),
3289
+ queryFn: async () => {
3290
+ if (!runId) {
3291
+ return null;
3292
+ }
3293
+ return source.getRun(runId);
3294
+ }
3295
+ });
3296
+ }
3297
+ function useCancelWorkflowRun(source) {
3298
+ const queryClient = useQueryClient();
3299
+ return useMutation({
3300
+ mutationFn: async (runId) => source.cancelRun(runId),
3301
+ onSuccess: (run) => {
3302
+ void queryClient.invalidateQueries({ queryKey: qk.workflows.all, exact: false });
3303
+ if (run?.id) {
3304
+ void queryClient.invalidateQueries({ queryKey: qk.workflows.run(run.id) });
3305
+ }
3306
+ }
3307
+ });
3308
+ }
3309
+ function useRunWorkflow(source) {
3310
+ const queryClient = useQueryClient();
3311
+ return useMutation({
3312
+ mutationFn: async (params) => {
3313
+ if (!source.runWorkflow) {
3314
+ throw new Error("Workflow source does not support running workflows");
3315
+ }
3316
+ return source.runWorkflow(params);
3317
+ },
3318
+ onSuccess: (run) => {
3319
+ void queryClient.invalidateQueries({ queryKey: qk.workflows.all, exact: false });
3320
+ if (run?.id) {
3321
+ void queryClient.invalidateQueries({ queryKey: qk.workflows.run(run.id) });
3322
+ }
3323
+ }
3324
+ });
3325
+ }
3326
+ function useResolveApproval(source) {
3327
+ const queryClient = useQueryClient();
3328
+ return useMutation({
3329
+ mutationFn: async (params) => {
3330
+ if (!source.resolveApproval) {
3331
+ throw new Error("Workflow source does not support approvals");
3332
+ }
3333
+ return source.resolveApproval(params);
3334
+ },
3335
+ onSuccess: (_data, variables) => {
3336
+ void queryClient.invalidateQueries({ queryKey: qk.workflows.run(variables.runId) });
3337
+ }
3338
+ });
3339
+ }
3340
+ function useWorkflowLogs(runId, options = {}) {
3341
+ const { follow = true, idleTimeoutMs, enabled = true, baseUrl = "" } = options;
3342
+ const [events, setEvents] = useState([]);
3343
+ const [error, setError] = useState(null);
3344
+ const [isConnected, setIsConnected] = useState(false);
3345
+ useEffect(() => {
3346
+ if (!runId || !enabled) {
3347
+ setIsConnected(false);
3348
+ setError(null);
3349
+ return;
3350
+ }
3351
+ setEvents([]);
3352
+ setError(null);
3353
+ const params = new URLSearchParams();
3354
+ if (follow) {
3355
+ params.set("follow", "1");
3356
+ }
3357
+ if (typeof idleTimeoutMs === "number") {
3358
+ params.set("idleTimeoutMs", String(idleTimeoutMs));
3359
+ }
3360
+ const url = `${baseUrl}/workflows/runs/${runId}/logs${params.toString() ? `?${params}` : ""}`;
3361
+ const eventSource = new EventSource(url);
3362
+ const handleMessage = (event) => {
3363
+ try {
3364
+ const payload = JSON.parse(event.data);
3365
+ setEvents((prev) => [...prev, payload]);
3366
+ } catch (err) {
3367
+ setError(err instanceof Error ? err : new Error("Failed to parse workflow log event"));
3368
+ }
3369
+ };
3370
+ eventSource.addEventListener("workflow.log", handleMessage);
3371
+ eventSource.addEventListener("workflow.done", () => {
3372
+ setIsConnected(false);
3373
+ eventSource.close();
3374
+ });
3375
+ eventSource.onopen = () => {
3376
+ setIsConnected(true);
3377
+ setError(null);
3378
+ };
3379
+ eventSource.onerror = (_event) => {
3380
+ setIsConnected(false);
3381
+ setError(new Error("Workflow log stream disconnected"));
3382
+ eventSource.close();
3383
+ };
3384
+ return () => {
3385
+ eventSource.removeEventListener("workflow.log", handleMessage);
3386
+ eventSource.close();
3387
+ };
3388
+ }, [runId, follow, idleTimeoutMs, enabled]);
3389
+ return {
3390
+ events,
3391
+ error,
3392
+ isConnected
3393
+ };
3394
+ }
3395
+ function useWorkflowEvents(runId, options = {}) {
3396
+ const { follow = true, pollIntervalMs, cursor, enabled = true, baseUrl = "" } = options;
3397
+ const [events, setEvents] = useState([]);
3398
+ const [error, setError] = useState(null);
3399
+ const [isConnected, setIsConnected] = useState(false);
3400
+ useEffect(() => {
3401
+ if (!runId || !enabled) {
3402
+ return;
3403
+ }
3404
+ setEvents([]);
3405
+ setError(null);
3406
+ const params = new URLSearchParams();
3407
+ if (follow) {
3408
+ params.set("follow", "1");
3409
+ }
3410
+ if (typeof pollIntervalMs === "number") {
3411
+ params.set("pollIntervalMs", String(pollIntervalMs));
3412
+ }
3413
+ if (cursor) {
3414
+ params.set("cursor", cursor);
3415
+ }
3416
+ const url = `${baseUrl}/workflows/runs/${runId}/events${params.toString() ? `?${params}` : ""}`;
3417
+ const eventSource = new EventSource(url);
3418
+ const handleMessage = (event) => {
3419
+ try {
3420
+ const payload = JSON.parse(event.data);
3421
+ setEvents((prev) => [...prev, payload]);
3422
+ } catch (err) {
3423
+ setError(err instanceof Error ? err : new Error("Failed to parse workflow event"));
3424
+ }
3425
+ };
3426
+ eventSource.addEventListener("workflow.event", handleMessage);
3427
+ eventSource.onopen = () => {
3428
+ setIsConnected(true);
3429
+ setError(null);
3430
+ };
3431
+ eventSource.onerror = () => {
3432
+ setIsConnected(false);
3433
+ setError(new Error("Workflow event stream disconnected"));
3434
+ eventSource.close();
3435
+ };
3436
+ return () => {
3437
+ eventSource.removeEventListener("workflow.event", handleMessage);
3438
+ eventSource.close();
3439
+ };
3440
+ }, [runId, follow, pollIntervalMs, cursor, enabled]);
3441
+ return {
3442
+ events,
3443
+ error,
3444
+ isConnected
3445
+ };
3446
+ }
3447
+ function useStateBrokerStats(source) {
3448
+ return useQuery({
3449
+ queryKey: ["observability", "state-broker"],
3450
+ queryFn: () => source.getStateBrokerStats(),
3451
+ refetchInterval: 5e3,
3452
+ // Auto-refresh every 5s for real-time updates
3453
+ staleTime: 3e3,
3454
+ // Consider data stale after 3s
3455
+ retry: 2
3456
+ // Retry failed requests twice
3457
+ });
3458
+ }
3459
+ function useDevKitHealth(source) {
3460
+ return useQuery({
3461
+ queryKey: ["observability", "devkit"],
3462
+ queryFn: () => source.getDevKitHealth(),
3463
+ staleTime: 6e4,
3464
+ // Cache for 1 minute
3465
+ gcTime: 3e5,
3466
+ // Keep in cache for 5 minutes (React Query v5)
3467
+ retry: 1
3468
+ // DevKit can be slow, only retry once
3469
+ });
3470
+ }
3471
+ function usePrometheusMetrics(source) {
3472
+ return useQuery({
3473
+ queryKey: ["observability", "prometheus-metrics"],
3474
+ queryFn: () => source.getPrometheusMetrics(),
3475
+ refetchInterval: 1e4,
3476
+ // Auto-refresh every 10s
3477
+ staleTime: 8e3,
3478
+ // Consider data stale after 8s
3479
+ retry: 2
3480
+ // Retry failed requests twice
3481
+ });
3482
+ }
3483
+ function useSystemEvents(source) {
3484
+ const [events, setEvents] = useState([]);
3485
+ const [isConnected, setIsConnected] = useState(false);
3486
+ const [error, setError] = useState(null);
3487
+ useEffect(() => {
3488
+ setIsConnected(true);
3489
+ setError(null);
3490
+ const cleanup = source.subscribeToSystemEvents(
3491
+ (event) => {
3492
+ setEvents((prev) => [event, ...prev].slice(0, 100));
3493
+ },
3494
+ (err) => {
3495
+ setIsConnected(false);
3496
+ setError(err);
3497
+ }
3498
+ );
3499
+ return () => {
3500
+ cleanup();
3501
+ setIsConnected(false);
3502
+ };
3503
+ }, [source]);
3504
+ return { events, isConnected, error };
3505
+ }
3506
+ function useLogStream(source, filters) {
3507
+ const [logs, setLogs] = useState([]);
3508
+ const [isConnected, setIsConnected] = useState(false);
3509
+ const [error, setError] = useState(null);
3510
+ useEffect(() => {
3511
+ setIsConnected(true);
3512
+ setError(null);
3513
+ const cleanup = source.subscribeToLogs(
3514
+ (log) => {
3515
+ setLogs((prev) => [log, ...prev].slice(0, 500));
3516
+ },
3517
+ (err) => {
3518
+ setIsConnected(false);
3519
+ setError(err);
3520
+ },
3521
+ filters
3522
+ );
3523
+ return () => {
3524
+ cleanup();
3525
+ setIsConnected(false);
3526
+ };
3527
+ }, [source, filters]);
3528
+ const clearLogs = () => setLogs([]);
3529
+ return { logs, isConnected, error, clearLogs };
3530
+ }
3531
+ function useMetricsHistory(source, query) {
3532
+ return useQuery({
3533
+ queryKey: ["observability", "metrics-history", query.metric, query.range, query.interval],
3534
+ queryFn: () => source.getMetricsHistory(query),
3535
+ refetchInterval: 5e3,
3536
+ // Auto-refresh every 5s
3537
+ staleTime: 3e3,
3538
+ // Consider data stale after 3s
3539
+ retry: 2
3540
+ });
3541
+ }
3542
+ function useMetricsHeatmap(source, query) {
3543
+ return useQuery({
3544
+ queryKey: ["observability", "metrics-heatmap", query.metric, query.days],
3545
+ queryFn: () => source.getMetricsHeatmap(query),
3546
+ staleTime: 6e4,
3547
+ // Cache for 1 minute
3548
+ gcTime: 3e5,
3549
+ // Keep in cache for 5 minutes
3550
+ retry: 2
3551
+ });
3552
+ }
3553
+ function useIncidents(source, query) {
3554
+ return useQuery({
3555
+ queryKey: ["observability", "incidents", query],
3556
+ queryFn: () => source.queryIncidents(query),
3557
+ refetchInterval: 3e4,
3558
+ // Auto-refresh every 30s
3559
+ staleTime: 2e4,
3560
+ // Consider data stale after 20s
3561
+ retry: 2
3562
+ });
3563
+ }
3564
+ function useAnalyticsEvents(source, query) {
3565
+ return useQuery({
3566
+ queryKey: ["analytics", "events", query],
3567
+ queryFn: () => source.getEvents(query),
3568
+ refetchInterval: 3e4,
3569
+ // Auto-refresh every 30s
3570
+ staleTime: 25e3,
3571
+ // Consider data stale after 25s
3572
+ retry: 2
3573
+ });
3574
+ }
3575
+ function useAnalyticsStats(source) {
3576
+ return useQuery({
3577
+ queryKey: ["analytics", "stats"],
3578
+ queryFn: () => source.getStats(),
3579
+ refetchInterval: 3e4,
3580
+ // Auto-refresh every 30s
3581
+ staleTime: 25e3,
3582
+ retry: 2
3583
+ });
3584
+ }
3585
+ function useAnalyticsBufferStatus(source) {
3586
+ return useQuery({
3587
+ queryKey: ["analytics", "buffer"],
3588
+ queryFn: () => source.getBufferStatus(),
3589
+ refetchInterval: 1e4,
3590
+ // Auto-refresh every 10s
3591
+ staleTime: 8e3,
3592
+ retry: 2
3593
+ });
3594
+ }
3595
+ function useAnalyticsDlqStatus(source) {
3596
+ return useQuery({
3597
+ queryKey: ["analytics", "dlq"],
3598
+ queryFn: () => source.getDlqStatus(),
3599
+ refetchInterval: 15e3,
3600
+ // Auto-refresh every 15s
3601
+ staleTime: 12e3,
3602
+ retry: 2
3603
+ });
3604
+ }
3605
+ var DAILY_STATS = "daily-stats";
3606
+ function useAdaptersLLMUsage(source, options) {
3607
+ return useQuery({
3608
+ queryKey: ["adapters", "llm", "usage", options?.from, options?.to],
3609
+ queryFn: () => source.getLLMUsage(options),
3610
+ refetchInterval: 6e4,
3611
+ // Auto-refresh every 60s (LLM stats change slower)
3612
+ staleTime: 5e4,
3613
+ retry: 2
3614
+ });
3615
+ }
3616
+ function useAdaptersEmbeddingsUsage(source, options) {
3617
+ return useQuery({
3618
+ queryKey: ["adapters", "embeddings", "usage", options?.from, options?.to],
3619
+ queryFn: () => source.getEmbeddingsUsage(options),
3620
+ refetchInterval: 6e4,
3621
+ staleTime: 5e4,
3622
+ retry: 2
3623
+ });
3624
+ }
3625
+ function useAdaptersVectorStoreUsage(source, options) {
3626
+ return useQuery({
3627
+ queryKey: ["adapters", "vectorstore", "usage", options?.from, options?.to],
3628
+ queryFn: () => source.getVectorStoreUsage(options),
3629
+ refetchInterval: 6e4,
3630
+ staleTime: 5e4,
3631
+ retry: 2
3632
+ });
3633
+ }
3634
+ function useAdaptersCacheUsage(source, options) {
3635
+ return useQuery({
3636
+ queryKey: ["adapters", "cache", "usage", options?.from, options?.to],
3637
+ queryFn: () => source.getCacheUsage(options),
3638
+ refetchInterval: 3e4,
3639
+ // Cache stats change faster - refresh every 30s
3640
+ staleTime: 25e3,
3641
+ retry: 2
3642
+ });
3643
+ }
3644
+ function useAdaptersStorageUsage(source, options) {
3645
+ return useQuery({
3646
+ queryKey: ["adapters", "storage", "usage", options?.from, options?.to],
3647
+ queryFn: () => source.getStorageUsage(options),
3648
+ refetchInterval: 6e4,
3649
+ staleTime: 5e4,
3650
+ retry: 2
3651
+ });
3652
+ }
3653
+ function useAdaptersLLMDailyStats(source, options) {
3654
+ return useQuery({
3655
+ queryKey: ["adapters", "llm", DAILY_STATS, options?.from, options?.to, options?.models],
3656
+ queryFn: () => source.getLLMDailyStats(options),
3657
+ refetchInterval: 6e4,
3658
+ // Daily stats change slower
3659
+ staleTime: 5e4,
3660
+ retry: 2
3661
+ });
3662
+ }
3663
+ function useAdaptersEmbeddingsDailyStats(source, options) {
3664
+ return useQuery({
3665
+ queryKey: ["adapters", "embeddings", DAILY_STATS, options?.from, options?.to],
3666
+ queryFn: () => source.getEmbeddingsDailyStats(options),
3667
+ refetchInterval: 6e4,
3668
+ staleTime: 5e4,
3669
+ retry: 2
3670
+ });
3671
+ }
3672
+ function useAdaptersVectorStoreDailyStats(source, options) {
3673
+ return useQuery({
3674
+ queryKey: ["adapters", "vectorstore", DAILY_STATS, options?.from, options?.to],
3675
+ queryFn: () => source.getVectorStoreDailyStats(options),
3676
+ refetchInterval: 6e4,
3677
+ staleTime: 5e4,
3678
+ retry: 2
3679
+ });
3680
+ }
3681
+ function useAdaptersCacheDailyStats(source, options) {
3682
+ return useQuery({
3683
+ queryKey: ["adapters", "cache", DAILY_STATS, options?.from, options?.to],
3684
+ queryFn: () => source.getCacheDailyStats(options),
3685
+ refetchInterval: 3e4,
3686
+ // Cache stats change faster
3687
+ staleTime: 25e3,
3688
+ retry: 2
3689
+ });
3690
+ }
3691
+ function useAdaptersStorageDailyStats(source, options) {
3692
+ return useQuery({
3693
+ queryKey: ["adapters", "storage", DAILY_STATS, options?.from, options?.to],
3694
+ queryFn: () => source.getStorageDailyStats(options),
3695
+ refetchInterval: 6e4,
3696
+ staleTime: 5e4,
3697
+ retry: 2
3698
+ });
3699
+ }
3700
+ function usePlatformConfig(source) {
3701
+ return useQuery({
3702
+ queryKey: qk.platform.config(),
3703
+ queryFn: async () => {
3704
+ return source.getConfig();
3705
+ },
3706
+ staleTime: 6e4,
3707
+ // Cache for 1 minute (config rarely changes)
3708
+ retry: 2,
3709
+ retryDelay: 1e3
3710
+ });
3711
+ }
3712
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
3713
+ function statusToEventType(status) {
3714
+ if (status === "completed") {
3715
+ return "job.finished";
3716
+ }
3717
+ if (status === "failed") {
3718
+ return "job.failed";
3719
+ }
3720
+ if (status === "running") {
3721
+ return "job.started";
3722
+ }
3723
+ return "job.queued";
3724
+ }
3725
+ function useJobEvents(jobId, options = {}) {
3726
+ const {
3727
+ enabled = true,
3728
+ pollInterval = 1e3,
3729
+ baseUrl = "",
3730
+ onEvent,
3731
+ onError,
3732
+ onComplete
3733
+ } = options;
3734
+ const [events, setEvents] = useState([]);
3735
+ const [isConnected, setIsConnected] = useState(false);
3736
+ const [error, setError] = useState(null);
3737
+ const eventSourceRef = useRef(null);
3738
+ const pollingRef = useRef(null);
3739
+ const useSSERef = useRef(true);
3740
+ const reconnect = useCallback(() => {
3741
+ if (eventSourceRef.current) {
3742
+ eventSourceRef.current.close();
3743
+ eventSourceRef.current = null;
3744
+ }
3745
+ if (pollingRef.current) {
3746
+ clearInterval(pollingRef.current);
3747
+ pollingRef.current = null;
3748
+ }
3749
+ setEvents([]);
3750
+ setError(null);
3751
+ setIsConnected(false);
3752
+ useSSERef.current = true;
3753
+ }, []);
3754
+ useEffect(() => {
3755
+ if (!enabled || !jobId) {
3756
+ return;
3757
+ }
3758
+ const eventsUrl = `${baseUrl}/jobs/${jobId}/events`;
3759
+ if (useSSERef.current) {
3760
+ try {
3761
+ const eventSource = new EventSource(eventsUrl);
3762
+ eventSourceRef.current = eventSource;
3763
+ eventSource.onopen = () => {
3764
+ setIsConnected(true);
3765
+ setError(null);
3766
+ };
3767
+ eventSource.onmessage = (e) => {
3768
+ try {
3769
+ const event = JSON.parse(e.data);
3770
+ setEvents((prev) => [...prev, event]);
3771
+ onEvent?.(event);
3772
+ if (event.type === "job.finished" || event.type === "job.failed") {
3773
+ eventSource.close();
3774
+ setIsConnected(false);
3775
+ onComplete?.();
3776
+ }
3777
+ } catch (_err) {
3778
+ setError(_err instanceof Error ? _err : new Error("Failed to parse event"));
3779
+ onError?.(_err instanceof Error ? _err : new Error("Failed to parse event"));
3780
+ }
3781
+ };
3782
+ eventSource.onerror = (_event) => {
3783
+ eventSource.close();
3784
+ eventSourceRef.current = null;
3785
+ useSSERef.current = false;
3786
+ setIsConnected(false);
3787
+ const poll = async () => {
3788
+ try {
3789
+ const response = await fetch(`${baseUrl}/jobs/${jobId}`);
3790
+ if (!response.ok) {
3791
+ throw new Error(`HTTP ${response.status}`);
3792
+ }
3793
+ const data = await response.json();
3794
+ const currentStatus = data.status;
3795
+ const lastEvent = events[events.length - 1];
3796
+ if (!lastEvent || lastEvent.data?.status !== currentStatus) {
3797
+ const event = {
3798
+ type: statusToEventType(currentStatus),
3799
+ jobId,
3800
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3801
+ data: {
3802
+ status: currentStatus,
3803
+ progress: data.progress,
3804
+ error: data.error
3805
+ }
3806
+ };
3807
+ setEvents((prev) => [...prev, event]);
3808
+ onEvent?.(event);
3809
+ if (TERMINAL_STATUSES.has(currentStatus)) {
3810
+ if (pollingRef.current) {
3811
+ clearInterval(pollingRef.current);
3812
+ pollingRef.current = null;
3813
+ }
3814
+ onComplete?.();
3815
+ }
3816
+ }
3817
+ } catch (_err) {
3818
+ const errorInstance = _err instanceof Error ? _err : new Error("Polling failed");
3819
+ setError(errorInstance);
3820
+ onError?.(errorInstance);
3821
+ }
3822
+ };
3823
+ poll();
3824
+ pollingRef.current = setInterval(poll, pollInterval);
3825
+ };
3826
+ return () => {
3827
+ if (eventSourceRef.current) {
3828
+ eventSourceRef.current.close();
3829
+ eventSourceRef.current = null;
3830
+ }
3831
+ if (pollingRef.current) {
3832
+ clearInterval(pollingRef.current);
3833
+ pollingRef.current = null;
3834
+ }
3835
+ };
3836
+ } catch (_err) {
3837
+ useSSERef.current = false;
3838
+ }
3839
+ }
3840
+ if (!useSSERef.current && !pollingRef.current) {
3841
+ const poll = async () => {
3842
+ try {
3843
+ const response = await fetch(`${baseUrl}/jobs/${jobId}`);
3844
+ if (!response.ok) {
3845
+ throw new Error(`HTTP ${response.status}`);
3846
+ }
3847
+ const data = await response.json();
3848
+ const currentStatus = data.status;
3849
+ setEvents((prev) => {
3850
+ const lastEvent = prev[prev.length - 1];
3851
+ if (!lastEvent || lastEvent.data?.status !== currentStatus) {
3852
+ const event = {
3853
+ type: statusToEventType(currentStatus),
3854
+ jobId,
3855
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3856
+ data: {
3857
+ status: currentStatus,
3858
+ progress: data.progress,
3859
+ error: data.error
3860
+ }
3861
+ };
3862
+ onEvent?.(event);
3863
+ if (currentStatus === "completed" || currentStatus === "failed" || currentStatus === "cancelled") {
3864
+ if (pollingRef.current) {
3865
+ clearInterval(pollingRef.current);
3866
+ pollingRef.current = null;
3867
+ }
3868
+ onComplete?.();
3869
+ }
3870
+ return [...prev, event];
3871
+ }
3872
+ return prev;
3873
+ });
3874
+ setIsConnected(true);
3875
+ setError(null);
3876
+ } catch (_err) {
3877
+ const errorInstance = _err instanceof Error ? _err : new Error("Polling failed");
3878
+ setError(errorInstance);
3879
+ onError?.(errorInstance);
3880
+ setIsConnected(false);
3881
+ }
3882
+ };
3883
+ poll();
3884
+ pollingRef.current = setInterval(poll, pollInterval);
3885
+ return () => {
3886
+ if (pollingRef.current) {
3887
+ clearInterval(pollingRef.current);
3888
+ pollingRef.current = null;
3889
+ }
3890
+ };
3891
+ }
3892
+ }, [jobId, enabled, pollInterval, onEvent, onError, onComplete, events]);
3893
+ return {
3894
+ events,
3895
+ isConnected,
3896
+ error,
3897
+ reconnect
3898
+ };
3899
+ }
3900
+ var MAX_NOTIFICATIONS = 50;
3901
+ function useNotifications(source, maxNotifications = MAX_NOTIFICATIONS) {
3902
+ const [notifications, setNotifications] = useState([]);
3903
+ useEffect(() => {
3904
+ return source.subscribeToLogs(
3905
+ (log) => {
3906
+ if (log.level !== "warn" && log.level !== "error") {
3907
+ return;
3908
+ }
3909
+ let messageText = "No message";
3910
+ if (log.msg) {
3911
+ messageText = typeof log.msg === "string" ? log.msg : JSON.stringify(log.msg);
3912
+ }
3913
+ const notification = {
3914
+ id: log.id || `${log.time}-${Math.random().toString(36).slice(2, 9)}`,
3915
+ // Use log.id from database, fallback to generated
3916
+ timestamp: log.time,
3917
+ level: log.level,
3918
+ message: messageText,
3919
+ plugin: log.plugin,
3920
+ executionId: log.executionId,
3921
+ error: log.err ? {
3922
+ name: String(log.err.name || "Error"),
3923
+ message: String(log.err.message || "Unknown error")
3924
+ } : void 0,
3925
+ read: false
3926
+ };
3927
+ setNotifications((prev) => [notification, ...prev].slice(0, maxNotifications));
3928
+ },
3929
+ (err) => {
3930
+ console.error("Notifications SSE error:", err);
3931
+ }
3932
+ );
3933
+ }, [source, maxNotifications]);
3934
+ const unreadCount = notifications.filter((n) => !n.read).length;
3935
+ const markAsRead = useCallback((id) => {
3936
+ setNotifications(
3937
+ (prev) => prev.map((n) => n.id === id ? { ...n, read: true } : n)
3938
+ );
3939
+ }, []);
3940
+ const markAllAsRead = useCallback(() => {
3941
+ setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));
3942
+ }, []);
3943
+ const clearAll = useCallback(() => {
3944
+ setNotifications([]);
3945
+ }, []);
3946
+ const clearNotification = useCallback((id) => {
3947
+ setNotifications((prev) => prev.filter((n) => n.id !== id));
3948
+ }, []);
3949
+ return {
3950
+ notifications,
3951
+ unreadCount,
3952
+ markAsRead,
3953
+ markAllAsRead,
3954
+ clearAll,
3955
+ clearNotification
3956
+ };
3957
+ }
3958
+
3959
+ export { HttpAdaptersSource, HttpAnalyticsSource, HttpCacheSource, HttpClient, HttpObservabilitySource, HttpPlatformSource, HttpPluginsSource, HttpSystemSource, HttpWorkflowSource, KBError, MockAdaptersSource, MockAnalyticsSource, MockCacheSource, MockObservabilitySource, MockPlatformSource, MockPluginsSource, MockSystemSource, MockWorkflowSource, SCHEMA_VERSION, actionResultSchema, auditCheckSchema, auditPackageReportSchema, auditSummarySchema, createDataSources, createEnvelopeInterceptor, errorCodes, extractEnvelopeMeta, healthStatusSchema, idSchema, isoDateSchema, mapErrorEnvelope, mapFetchError, packageRefSchema, qk, queryKeys, releasePreviewSchema, runRefSchema, useAdaptersCacheDailyStats, useAdaptersCacheUsage, useAdaptersEmbeddingsDailyStats, useAdaptersEmbeddingsUsage, useAdaptersLLMDailyStats, useAdaptersLLMUsage, useAdaptersStorageDailyStats, useAdaptersStorageUsage, useAdaptersVectorStoreDailyStats, useAdaptersVectorStoreUsage, useAnalyticsBufferStatus, useAnalyticsDlqStatus, useAnalyticsEvents, useAnalyticsStats, useCancelWorkflowRun, useCapabilities, useDevKitHealth, useHealthStatus, useIncidents, useJobEvents, useLogStream, useMetricsHeatmap, useMetricsHistory, useNotifications, usePlatformConfig, usePrometheusMetrics, useReadyStatus, useResolveApproval, useRunWorkflow, useStateBrokerStats, useSystemEvents, useSystemInfo, useWorkflowEvents, useWorkflowLogs, useWorkflowRun, useWorkflowRuns };
3960
+ //# sourceMappingURL=index.js.map
3961
+ //# sourceMappingURL=index.js.map