rterm-backend 2.9.4 → 2.9.5
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/bin/gybackend.cjs +863 -295
- package/bin/gybackend.js +863 -295
- package/package.json +5 -2
package/bin/gybackend.js
CHANGED
|
@@ -252183,6 +252183,477 @@ var init_orchestratedPlaybookRunner = __esm({
|
|
|
252183
252183
|
}
|
|
252184
252184
|
});
|
|
252185
252185
|
|
|
252186
|
+
// packages/backend/src/services/apm/spanLedger.ts
|
|
252187
|
+
var spanLedger_exports = {};
|
|
252188
|
+
__export(spanLedger_exports, {
|
|
252189
|
+
SpanLedger: () => SpanLedger,
|
|
252190
|
+
ingestOtlp: () => ingestOtlp,
|
|
252191
|
+
newSpanId: () => newSpanId,
|
|
252192
|
+
parseOtlpJson: () => parseOtlpJson,
|
|
252193
|
+
stableId: () => stableId
|
|
252194
|
+
});
|
|
252195
|
+
function percentile(sorted, p) {
|
|
252196
|
+
if (sorted.length === 0) return void 0;
|
|
252197
|
+
return sorted[Math.min(sorted.length - 1, Math.floor(p / 100 * sorted.length))];
|
|
252198
|
+
}
|
|
252199
|
+
function parseOtlpJson(payload, defaultService = "unknown") {
|
|
252200
|
+
const out = [];
|
|
252201
|
+
const root = payload;
|
|
252202
|
+
const rs = root?.resourceSpans;
|
|
252203
|
+
if (!Array.isArray(rs)) return out;
|
|
252204
|
+
for (const r of rs) {
|
|
252205
|
+
const rr = r;
|
|
252206
|
+
let service = defaultService;
|
|
252207
|
+
const attrs2 = rr?.resource?.attributes ?? [];
|
|
252208
|
+
const svc = attrs2.find((a) => a.key === "service.name")?.value?.stringValue;
|
|
252209
|
+
if (svc) service = svc;
|
|
252210
|
+
const scopeSpans = rr?.scopeSpans;
|
|
252211
|
+
if (!Array.isArray(scopeSpans)) continue;
|
|
252212
|
+
for (const ss of scopeSpans) {
|
|
252213
|
+
const spans = ss?.spans;
|
|
252214
|
+
if (!Array.isArray(spans)) continue;
|
|
252215
|
+
for (const sp of spans) {
|
|
252216
|
+
const s = sp;
|
|
252217
|
+
if (!s.traceId || !s.spanId) continue;
|
|
252218
|
+
const startNs = Number(s.startTimeUnixNano ?? 0);
|
|
252219
|
+
const endNs = Number(s.endTimeUnixNano ?? 0);
|
|
252220
|
+
const startMs = startNs / 1e6;
|
|
252221
|
+
const durationMs = Math.max(0, (endNs - startNs) / 1e6);
|
|
252222
|
+
const isErr = s.status?.code === 2 || s.status?.code === "STATUS_CODE_ERROR" || s.status?.code === "Error";
|
|
252223
|
+
out.push({
|
|
252224
|
+
traceId: String(s.traceId),
|
|
252225
|
+
spanId: String(s.spanId),
|
|
252226
|
+
...s.parentSpanId ? { parentSpanId: String(s.parentSpanId) } : {},
|
|
252227
|
+
service,
|
|
252228
|
+
name: s.name ?? "span",
|
|
252229
|
+
startMs,
|
|
252230
|
+
durationMs,
|
|
252231
|
+
status: isErr ? "error" : "ok"
|
|
252232
|
+
});
|
|
252233
|
+
}
|
|
252234
|
+
}
|
|
252235
|
+
}
|
|
252236
|
+
return out;
|
|
252237
|
+
}
|
|
252238
|
+
function ingestOtlp(ledger, payload, defaultService = "unknown") {
|
|
252239
|
+
const spans = parseOtlpJson(payload, defaultService);
|
|
252240
|
+
return ledger.ingestBatch(spans);
|
|
252241
|
+
}
|
|
252242
|
+
function stableId(seed) {
|
|
252243
|
+
return (0, import_crypto7.createHash)("sha1").update(seed).digest("hex").slice(0, 16);
|
|
252244
|
+
}
|
|
252245
|
+
function newSpanId() {
|
|
252246
|
+
return (0, import_crypto7.randomUUID)().replace(/-/g, "").slice(0, 16);
|
|
252247
|
+
}
|
|
252248
|
+
var import_crypto7, DEFAULT_LIMIT, SpanLedger;
|
|
252249
|
+
var init_spanLedger = __esm({
|
|
252250
|
+
"packages/backend/src/services/apm/spanLedger.ts"() {
|
|
252251
|
+
"use strict";
|
|
252252
|
+
import_crypto7 = require("crypto");
|
|
252253
|
+
DEFAULT_LIMIT = 5e4;
|
|
252254
|
+
SpanLedger = class {
|
|
252255
|
+
spans = /* @__PURE__ */ new Map();
|
|
252256
|
+
// traceId -> spans
|
|
252257
|
+
order = [];
|
|
252258
|
+
// traceIds in insert order
|
|
252259
|
+
spanLimit;
|
|
252260
|
+
totalSpans = 0;
|
|
252261
|
+
constructor(opts = {}) {
|
|
252262
|
+
this.spanLimit = opts.spanLimit ?? DEFAULT_LIMIT;
|
|
252263
|
+
}
|
|
252264
|
+
/** Ingest one span. */
|
|
252265
|
+
ingest(span) {
|
|
252266
|
+
let arr3 = this.spans.get(span.traceId);
|
|
252267
|
+
if (!arr3) {
|
|
252268
|
+
arr3 = [];
|
|
252269
|
+
this.spans.set(span.traceId, arr3);
|
|
252270
|
+
this.order.push(span.traceId);
|
|
252271
|
+
}
|
|
252272
|
+
arr3.push(span);
|
|
252273
|
+
this.totalSpans += 1;
|
|
252274
|
+
while (this.totalSpans > this.spanLimit && this.order.length > 0) {
|
|
252275
|
+
const oldest = this.order.shift();
|
|
252276
|
+
const old = this.spans.get(oldest) ?? [];
|
|
252277
|
+
this.totalSpans -= old.length;
|
|
252278
|
+
this.spans.delete(oldest);
|
|
252279
|
+
}
|
|
252280
|
+
}
|
|
252281
|
+
/** Ingest many spans. */
|
|
252282
|
+
ingestBatch(spans) {
|
|
252283
|
+
for (const s of spans) this.ingest(s);
|
|
252284
|
+
return spans.length;
|
|
252285
|
+
}
|
|
252286
|
+
/** All spans for a trace. */
|
|
252287
|
+
trace(traceId) {
|
|
252288
|
+
return this.spans.get(traceId) ?? [];
|
|
252289
|
+
}
|
|
252290
|
+
traceIds() {
|
|
252291
|
+
return this.order;
|
|
252292
|
+
}
|
|
252293
|
+
/** Summarize a trace (root service, span count, total duration, error). */
|
|
252294
|
+
summarize(traceId) {
|
|
252295
|
+
const spans = this.spans.get(traceId);
|
|
252296
|
+
if (!spans || spans.length === 0) return void 0;
|
|
252297
|
+
const root = spans.find((s) => !s.parentSpanId) ?? spans[0];
|
|
252298
|
+
const services = Array.from(new Set(spans.map((s) => s.service)));
|
|
252299
|
+
const hasError = spans.some((s) => s.status === "error");
|
|
252300
|
+
const start = Math.min(...spans.map((s) => s.startMs));
|
|
252301
|
+
const end = Math.max(...spans.map((s) => s.startMs + s.durationMs));
|
|
252302
|
+
return {
|
|
252303
|
+
traceId,
|
|
252304
|
+
rootService: root.service,
|
|
252305
|
+
spanCount: spans.length,
|
|
252306
|
+
totalDurationMs: end - start,
|
|
252307
|
+
hasError,
|
|
252308
|
+
services,
|
|
252309
|
+
at: start
|
|
252310
|
+
};
|
|
252311
|
+
}
|
|
252312
|
+
/** Per-service stats over a window. */
|
|
252313
|
+
serviceStats(opts = {}) {
|
|
252314
|
+
const byService = /* @__PURE__ */ new Map();
|
|
252315
|
+
for (const arr3 of this.spans.values()) {
|
|
252316
|
+
for (const s of arr3) {
|
|
252317
|
+
if (opts.sinceMs !== void 0 && s.startMs < opts.sinceMs) continue;
|
|
252318
|
+
if (opts.service && s.service !== opts.service) continue;
|
|
252319
|
+
let e = byService.get(s.service);
|
|
252320
|
+
if (!e) {
|
|
252321
|
+
e = { durations: [], errors: 0 };
|
|
252322
|
+
byService.set(s.service, e);
|
|
252323
|
+
}
|
|
252324
|
+
e.durations.push(s.durationMs);
|
|
252325
|
+
if (s.status === "error") e.errors += 1;
|
|
252326
|
+
}
|
|
252327
|
+
}
|
|
252328
|
+
const out = [];
|
|
252329
|
+
for (const [service, e] of byService) {
|
|
252330
|
+
const durations = e.durations.slice().sort((a, b) => a - b);
|
|
252331
|
+
out.push({
|
|
252332
|
+
service,
|
|
252333
|
+
spanCount: durations.length,
|
|
252334
|
+
errorCount: e.errors,
|
|
252335
|
+
errorRate: durations.length > 0 ? e.errors / durations.length : 0,
|
|
252336
|
+
p50Ms: percentile(durations, 50),
|
|
252337
|
+
p95Ms: percentile(durations, 95),
|
|
252338
|
+
p99Ms: percentile(durations, 99),
|
|
252339
|
+
maxMs: durations.length > 0 ? durations[durations.length - 1] : void 0
|
|
252340
|
+
});
|
|
252341
|
+
}
|
|
252342
|
+
return out.sort((a, b) => (b.p95Ms ?? 0) - (a.p95Ms ?? 0));
|
|
252343
|
+
}
|
|
252344
|
+
/** Slowest traces by total duration. */
|
|
252345
|
+
slowestTraces(limit2 = 10, opts = {}) {
|
|
252346
|
+
const summaries = [];
|
|
252347
|
+
for (const id of this.order) {
|
|
252348
|
+
const s = this.summarize(id);
|
|
252349
|
+
if (!s) continue;
|
|
252350
|
+
if (opts.sinceMs !== void 0 && s.at < opts.sinceMs) continue;
|
|
252351
|
+
summaries.push(s);
|
|
252352
|
+
}
|
|
252353
|
+
return summaries.sort((a, b) => b.totalDurationMs - a.totalDurationMs).slice(0, limit2);
|
|
252354
|
+
}
|
|
252355
|
+
/** Services ranked by total error count (bottleneck/failing services). */
|
|
252356
|
+
bottleneckServices(opts = {}) {
|
|
252357
|
+
return this.serviceStats(opts).sort((a, b) => b.errorCount - a.errorCount);
|
|
252358
|
+
}
|
|
252359
|
+
/** Total stored spans. */
|
|
252360
|
+
size() {
|
|
252361
|
+
return this.totalSpans;
|
|
252362
|
+
}
|
|
252363
|
+
clear() {
|
|
252364
|
+
this.spans.clear();
|
|
252365
|
+
this.order.length = 0;
|
|
252366
|
+
this.totalSpans = 0;
|
|
252367
|
+
}
|
|
252368
|
+
};
|
|
252369
|
+
}
|
|
252370
|
+
});
|
|
252371
|
+
|
|
252372
|
+
// packages/backend/src/services/infra/infraMonitor.ts
|
|
252373
|
+
var infraMonitor_exports = {};
|
|
252374
|
+
__export(infraMonitor_exports, {
|
|
252375
|
+
InfraMonitor: () => InfraMonitor,
|
|
252376
|
+
clusterHealth: () => clusterHealth,
|
|
252377
|
+
newClusterContextId: () => newClusterContextId,
|
|
252378
|
+
parseKubectlPods: () => parseKubectlPods,
|
|
252379
|
+
podUnhealthy: () => podUnhealthy
|
|
252380
|
+
});
|
|
252381
|
+
function parseKubectlPods(text) {
|
|
252382
|
+
const out = [];
|
|
252383
|
+
const lines = text.split(/\r?\n/).map((l) => l.trimEnd()).filter((l) => l.trim() !== "");
|
|
252384
|
+
const header = lines.find((l) => /^NAME(SPACE)?\s+/.test(l));
|
|
252385
|
+
const hasNamespaceCol = header !== void 0 && /^NAMESPACE\s+/.test(header);
|
|
252386
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
252387
|
+
const l = lines[i];
|
|
252388
|
+
if (/^NAME(SPACE)?\s+/.test(l)) continue;
|
|
252389
|
+
const parts = l.trim().split(/\s+/);
|
|
252390
|
+
const minFields = hasNamespaceCol ? 6 : 5;
|
|
252391
|
+
if (parts.length < minFields) continue;
|
|
252392
|
+
let namespace = "default";
|
|
252393
|
+
let name;
|
|
252394
|
+
let readyFrac;
|
|
252395
|
+
let status;
|
|
252396
|
+
let restartsStr;
|
|
252397
|
+
if (hasNamespaceCol) {
|
|
252398
|
+
;
|
|
252399
|
+
[namespace, name, readyFrac, status, restartsStr] = parts;
|
|
252400
|
+
} else {
|
|
252401
|
+
;
|
|
252402
|
+
[name, readyFrac, status, restartsStr] = parts;
|
|
252403
|
+
}
|
|
252404
|
+
const [readyNum, readyDen] = (readyFrac ?? "0/1").split("/").map((x) => parseInt(x, 10));
|
|
252405
|
+
const restarts = parseInt((restartsStr ?? "0").replace(/\D.*$/, ""), 10) || 0;
|
|
252406
|
+
const phase = ["Pending", "Running", "Succeeded", "Failed", "Unknown"].includes(status) ? status : "Unknown";
|
|
252407
|
+
out.push({
|
|
252408
|
+
name,
|
|
252409
|
+
namespace,
|
|
252410
|
+
phase,
|
|
252411
|
+
restarts,
|
|
252412
|
+
ready: readyNum === readyDen && readyDen > 0 && status === "Running"
|
|
252413
|
+
});
|
|
252414
|
+
}
|
|
252415
|
+
return out;
|
|
252416
|
+
}
|
|
252417
|
+
function clusterHealth(context2, pods, nodes) {
|
|
252418
|
+
const running = pods.filter((p) => p.phase === "Running");
|
|
252419
|
+
const notReady = pods.filter((p) => !p.ready).length;
|
|
252420
|
+
const crashLoop = pods.filter((p) => p.restarts >= 5 || p.phase === "Unknown" && p.restarts > 0).length;
|
|
252421
|
+
const totalRestarts = pods.reduce((s, p) => s + p.restarts, 0);
|
|
252422
|
+
const nodesReady = nodes.filter((n2) => n2.ready).length;
|
|
252423
|
+
let cpuPct;
|
|
252424
|
+
let memPct;
|
|
252425
|
+
const withCpu = pods.filter((p) => typeof p.cpuMillicores === "number" && typeof p.cpuLimitMillicores === "number" && p.cpuLimitMillicores > 0);
|
|
252426
|
+
if (withCpu.length > 0) {
|
|
252427
|
+
const used = withCpu.reduce((s, p) => s + (p.cpuMillicores ?? 0), 0);
|
|
252428
|
+
const limit2 = withCpu.reduce((s, p) => s + (p.cpuLimitMillicores ?? 0), 0);
|
|
252429
|
+
cpuPct = limit2 > 0 ? used / limit2 * 100 : void 0;
|
|
252430
|
+
}
|
|
252431
|
+
const withMem = pods.filter((p) => typeof p.memMiB === "number" && typeof p.memLimitMiB === "number" && p.memLimitMiB > 0);
|
|
252432
|
+
if (withMem.length > 0) {
|
|
252433
|
+
const used = withMem.reduce((s, p) => s + (p.memMiB ?? 0), 0);
|
|
252434
|
+
const limit2 = withMem.reduce((s, p) => s + (p.memLimitMiB ?? 0), 0);
|
|
252435
|
+
memPct = limit2 > 0 ? used / limit2 * 100 : void 0;
|
|
252436
|
+
}
|
|
252437
|
+
return {
|
|
252438
|
+
context: context2,
|
|
252439
|
+
totalPods: pods.length,
|
|
252440
|
+
runningPods: running.length,
|
|
252441
|
+
notReadyPods: notReady,
|
|
252442
|
+
crashLoopPods: crashLoop,
|
|
252443
|
+
totalRestarts,
|
|
252444
|
+
nodesReady,
|
|
252445
|
+
nodesTotal: nodes.length,
|
|
252446
|
+
...cpuPct !== void 0 ? { cpuUsagePercentOfLimit: cpuPct } : {},
|
|
252447
|
+
...memPct !== void 0 ? { memUsagePercentOfLimit: memPct } : {}
|
|
252448
|
+
};
|
|
252449
|
+
}
|
|
252450
|
+
function podUnhealthy(p) {
|
|
252451
|
+
return !p.ready || p.phase === "Failed" || p.phase === "Unknown" || p.restarts >= 5;
|
|
252452
|
+
}
|
|
252453
|
+
function newClusterContextId(name) {
|
|
252454
|
+
return `k8s-${name}-${(0, import_crypto8.randomUUID)().slice(0, 6)}`;
|
|
252455
|
+
}
|
|
252456
|
+
var import_crypto8, InfraMonitor;
|
|
252457
|
+
var init_infraMonitor = __esm({
|
|
252458
|
+
"packages/backend/src/services/infra/infraMonitor.ts"() {
|
|
252459
|
+
"use strict";
|
|
252460
|
+
import_crypto8 = require("crypto");
|
|
252461
|
+
InfraMonitor = class {
|
|
252462
|
+
clusters = /* @__PURE__ */ new Map();
|
|
252463
|
+
instances = /* @__PURE__ */ new Map();
|
|
252464
|
+
constructor(_deps = {}) {
|
|
252465
|
+
}
|
|
252466
|
+
/** Record a cluster health snapshot. */
|
|
252467
|
+
recordCluster(context2, pods, nodes) {
|
|
252468
|
+
const h = clusterHealth(context2, pods, nodes);
|
|
252469
|
+
this.clusters.set(context2, h);
|
|
252470
|
+
return h;
|
|
252471
|
+
}
|
|
252472
|
+
cluster(context2) {
|
|
252473
|
+
return this.clusters.get(context2);
|
|
252474
|
+
}
|
|
252475
|
+
clusters_() {
|
|
252476
|
+
return Array.from(this.clusters.values());
|
|
252477
|
+
}
|
|
252478
|
+
/** Unhealthy pods for a cluster (for alerting). */
|
|
252479
|
+
unhealthyPods(pods) {
|
|
252480
|
+
return pods.filter(podUnhealthy);
|
|
252481
|
+
}
|
|
252482
|
+
/** Record a cloud instance state. */
|
|
252483
|
+
recordInstance(inst) {
|
|
252484
|
+
this.instances.set(inst.id, inst);
|
|
252485
|
+
}
|
|
252486
|
+
instance(id) {
|
|
252487
|
+
return this.instances.get(id);
|
|
252488
|
+
}
|
|
252489
|
+
/** Instances that are not healthy (stopped/failed). */
|
|
252490
|
+
unhealthyInstances() {
|
|
252491
|
+
return Array.from(this.instances.values()).filter((i) => i.statusOk === false || /stopped|terminated|failed/i.test(i.state));
|
|
252492
|
+
}
|
|
252493
|
+
clear() {
|
|
252494
|
+
this.clusters.clear();
|
|
252495
|
+
this.instances.clear();
|
|
252496
|
+
}
|
|
252497
|
+
};
|
|
252498
|
+
}
|
|
252499
|
+
});
|
|
252500
|
+
|
|
252501
|
+
// packages/backend/src/services/etw/etwService.ts
|
|
252502
|
+
var etwService_exports = {};
|
|
252503
|
+
__export(etwService_exports, {
|
|
252504
|
+
ETW_PROVIDERS: () => ETW_PROVIDERS,
|
|
252505
|
+
EtwService: () => EtwService,
|
|
252506
|
+
buildCounterQuery: () => buildCounterQuery,
|
|
252507
|
+
buildStartCommands: () => buildStartCommands,
|
|
252508
|
+
buildStopCommands: () => buildStopCommands,
|
|
252509
|
+
buildWinEventQuery: () => buildWinEventQuery,
|
|
252510
|
+
extractFields: () => extractFields,
|
|
252511
|
+
parseCounterJson: () => parseCounterJson,
|
|
252512
|
+
parseWinEventJson: () => parseWinEventJson,
|
|
252513
|
+
parseWinEventText: () => parseWinEventText,
|
|
252514
|
+
topCounters: () => topCounters
|
|
252515
|
+
});
|
|
252516
|
+
function buildStartCommands(session) {
|
|
252517
|
+
const cmds = [];
|
|
252518
|
+
for (const kind of session.providers) {
|
|
252519
|
+
const provider = ETW_PROVIDERS[kind];
|
|
252520
|
+
const name = `${session.name}-${kind}`;
|
|
252521
|
+
cmds.push(`logman create trace "${name}" -p "${provider}" -o "${session.outFile}-${kind}.etl" -ets`);
|
|
252522
|
+
}
|
|
252523
|
+
return cmds;
|
|
252524
|
+
}
|
|
252525
|
+
function buildStopCommands(session) {
|
|
252526
|
+
return session.providers.map((kind) => `logman stop "${session.name}-${kind}" -ets`);
|
|
252527
|
+
}
|
|
252528
|
+
function buildWinEventQuery(logName, maxEvents = 100, filter) {
|
|
252529
|
+
const filterPart = filter ? ` | Where-Object { ${filter} }` : "";
|
|
252530
|
+
return `Get-WinEvent -LogName '${logName}' -MaxEvents ${maxEvents}${filterPart} | Select-Object TimeCreated,Id,ProviderName,Message | ConvertTo-Json -Depth 3 -Compress`;
|
|
252531
|
+
}
|
|
252532
|
+
function buildCounterQuery(counterPath, samples = 1) {
|
|
252533
|
+
return `Get-Counter -Counter '${counterPath}' -MaxSamples ${samples} | Select-Object -ExpandProperty CounterSamples | Select-Object Path,CookedValue | ConvertTo-Json -Depth 3 -Compress`;
|
|
252534
|
+
}
|
|
252535
|
+
function parseWinEventJson(output) {
|
|
252536
|
+
const trimmed = output.trim();
|
|
252537
|
+
if (!trimmed) return [];
|
|
252538
|
+
let parsed;
|
|
252539
|
+
try {
|
|
252540
|
+
parsed = JSON.parse(trimmed);
|
|
252541
|
+
} catch {
|
|
252542
|
+
return parseWinEventText(trimmed);
|
|
252543
|
+
}
|
|
252544
|
+
const arr3 = Array.isArray(parsed) ? parsed : [parsed];
|
|
252545
|
+
const out = [];
|
|
252546
|
+
for (const item of arr3) {
|
|
252547
|
+
const o = item;
|
|
252548
|
+
if (!o || typeof o !== "object") continue;
|
|
252549
|
+
const message = (o.Message ?? "").toString().trim();
|
|
252550
|
+
if (!message) continue;
|
|
252551
|
+
out.push({
|
|
252552
|
+
at: o.TimeCreated,
|
|
252553
|
+
provider: o.ProviderName,
|
|
252554
|
+
message,
|
|
252555
|
+
fields: extractFields(message)
|
|
252556
|
+
});
|
|
252557
|
+
}
|
|
252558
|
+
return out;
|
|
252559
|
+
}
|
|
252560
|
+
function parseWinEventText(output) {
|
|
252561
|
+
const out = [];
|
|
252562
|
+
const blocks2 = output.split(/\r?\n\r?\n/);
|
|
252563
|
+
for (const b of blocks2) {
|
|
252564
|
+
const msg = b.trim();
|
|
252565
|
+
if (!msg) continue;
|
|
252566
|
+
out.push({ message: msg.split(/\r?\n/).slice(0, 4).join(" "), fields: extractFields(msg) });
|
|
252567
|
+
}
|
|
252568
|
+
return out;
|
|
252569
|
+
}
|
|
252570
|
+
function extractFields(message) {
|
|
252571
|
+
const fields = {};
|
|
252572
|
+
const ip = message.match(/\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b/);
|
|
252573
|
+
if (ip) fields.ip = ip[1];
|
|
252574
|
+
const port = message.match(/[Pp]ort[:\s]+(\d{1,5})/);
|
|
252575
|
+
if (port) fields.port = port[1];
|
|
252576
|
+
const path32 = message.match(/([A-Za-z]:\\[^\s"',;]+)/);
|
|
252577
|
+
if (path32) fields.path = path32[1];
|
|
252578
|
+
const key = message.match(/(HKLM|HKCU|HKCR|HKU)\\[^\s"',;]+/i);
|
|
252579
|
+
if (key) fields.key = key[0];
|
|
252580
|
+
const proc = message.match(/[Pp]rocess(?:Name)?[:\s]+([A-Za-z0-9_.-]+\.exe)/);
|
|
252581
|
+
if (proc) fields.processName = proc[1];
|
|
252582
|
+
const pid = message.match(/[Pp]rocess\s*[Ii]d[:\s]+(\d+)/);
|
|
252583
|
+
if (pid) fields.pid = pid[1];
|
|
252584
|
+
return fields;
|
|
252585
|
+
}
|
|
252586
|
+
function parseCounterJson(output) {
|
|
252587
|
+
const trimmed = output.trim();
|
|
252588
|
+
if (!trimmed) return [];
|
|
252589
|
+
let parsed;
|
|
252590
|
+
try {
|
|
252591
|
+
parsed = JSON.parse(trimmed);
|
|
252592
|
+
} catch {
|
|
252593
|
+
return [];
|
|
252594
|
+
}
|
|
252595
|
+
const arr3 = Array.isArray(parsed) ? parsed : [parsed];
|
|
252596
|
+
const out = [];
|
|
252597
|
+
for (const item of arr3) {
|
|
252598
|
+
const o = item;
|
|
252599
|
+
if (!o || o.Path === void 0) continue;
|
|
252600
|
+
const value = typeof o.CookedValue === "number" ? o.CookedValue : parseFloat(String(o.CookedValue ?? "NaN"));
|
|
252601
|
+
if (Number.isFinite(value)) out.push({ path: o.Path, value });
|
|
252602
|
+
}
|
|
252603
|
+
return out;
|
|
252604
|
+
}
|
|
252605
|
+
function topCounters(points, n2 = 5) {
|
|
252606
|
+
return points.slice().sort((a, b) => b.value - a.value).slice(0, n2);
|
|
252607
|
+
}
|
|
252608
|
+
var import_crypto9, ETW_PROVIDERS, now0, EtwService;
|
|
252609
|
+
var init_etwService = __esm({
|
|
252610
|
+
"packages/backend/src/services/etw/etwService.ts"() {
|
|
252611
|
+
"use strict";
|
|
252612
|
+
import_crypto9 = require("crypto");
|
|
252613
|
+
ETW_PROVIDERS = {
|
|
252614
|
+
network: "Microsoft-Windows-Kernel-Network",
|
|
252615
|
+
file: "Microsoft-Windows-Kernel-File",
|
|
252616
|
+
registry: "Microsoft-Windows-Kernel-Registry",
|
|
252617
|
+
process: "Microsoft-Windows-Kernel-Process",
|
|
252618
|
+
dns: "Microsoft-Windows-DNS-Client",
|
|
252619
|
+
power: "Microsoft-Windows-Kernel-Power"
|
|
252620
|
+
};
|
|
252621
|
+
now0 = () => Date.now();
|
|
252622
|
+
EtwService = class {
|
|
252623
|
+
sessions = /* @__PURE__ */ new Map();
|
|
252624
|
+
now;
|
|
252625
|
+
constructor(deps = {}) {
|
|
252626
|
+
this.now = deps.now ?? now0;
|
|
252627
|
+
}
|
|
252628
|
+
/** Create a session descriptor (commands are built from it by buildStartCommands). */
|
|
252629
|
+
createSession(name, providers, outDir = "C:\\temp") {
|
|
252630
|
+
const clean = name.replace(/[^A-Za-z0-9_-]/g, "");
|
|
252631
|
+
const s = {
|
|
252632
|
+
id: `etw-${(0, import_crypto9.randomUUID)().slice(0, 8)}`,
|
|
252633
|
+
name: clean,
|
|
252634
|
+
providers,
|
|
252635
|
+
outFile: `${outDir}\\${clean}`,
|
|
252636
|
+
createdAt: this.now()
|
|
252637
|
+
};
|
|
252638
|
+
this.sessions.set(s.id, s);
|
|
252639
|
+
return s;
|
|
252640
|
+
}
|
|
252641
|
+
session(id) {
|
|
252642
|
+
return this.sessions.get(id);
|
|
252643
|
+
}
|
|
252644
|
+
sessions_() {
|
|
252645
|
+
return Array.from(this.sessions.values());
|
|
252646
|
+
}
|
|
252647
|
+
removeSession(id) {
|
|
252648
|
+
return this.sessions.delete(id);
|
|
252649
|
+
}
|
|
252650
|
+
clear() {
|
|
252651
|
+
this.sessions.clear();
|
|
252652
|
+
}
|
|
252653
|
+
};
|
|
252654
|
+
}
|
|
252655
|
+
});
|
|
252656
|
+
|
|
252186
252657
|
// packages/backend/src/services/history/HistorySqliteStore.ts
|
|
252187
252658
|
var HistorySqliteStore_exports = {};
|
|
252188
252659
|
__export(HistorySqliteStore_exports, {
|
|
@@ -254755,7 +255226,7 @@ var require_websocket = __commonJS({
|
|
|
254755
255226
|
var http2 = require("http");
|
|
254756
255227
|
var net2 = require("net");
|
|
254757
255228
|
var tls = require("tls");
|
|
254758
|
-
var { randomBytes: randomBytes3, createHash:
|
|
255229
|
+
var { randomBytes: randomBytes3, createHash: createHash7 } = require("crypto");
|
|
254759
255230
|
var { Duplex, Readable } = require("stream");
|
|
254760
255231
|
var { URL: URL5 } = require("url");
|
|
254761
255232
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -255415,7 +255886,7 @@ var require_websocket = __commonJS({
|
|
|
255415
255886
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
255416
255887
|
return;
|
|
255417
255888
|
}
|
|
255418
|
-
const digest =
|
|
255889
|
+
const digest = createHash7("sha1").update(key + GUID).digest("base64");
|
|
255419
255890
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
255420
255891
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
255421
255892
|
return;
|
|
@@ -255782,7 +256253,7 @@ var require_websocket_server = __commonJS({
|
|
|
255782
256253
|
var EventEmitter4 = require("events");
|
|
255783
256254
|
var http2 = require("http");
|
|
255784
256255
|
var { Duplex } = require("stream");
|
|
255785
|
-
var { createHash:
|
|
256256
|
+
var { createHash: createHash7 } = require("crypto");
|
|
255786
256257
|
var extension = require_extension();
|
|
255787
256258
|
var PerMessageDeflate = require_permessage_deflate();
|
|
255788
256259
|
var subprotocol = require_subprotocol();
|
|
@@ -256083,7 +256554,7 @@ var require_websocket_server = __commonJS({
|
|
|
256083
256554
|
);
|
|
256084
256555
|
}
|
|
256085
256556
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
256086
|
-
const digest =
|
|
256557
|
+
const digest = createHash7("sha1").update(key + GUID).digest("base64");
|
|
256087
256558
|
const headers = [
|
|
256088
256559
|
"HTTP/1.1 101 Switching Protocols",
|
|
256089
256560
|
"Upgrade: websocket",
|
|
@@ -342379,6 +342850,30 @@ var BUILTIN_TOOL_INFO = [
|
|
|
342379
342850
|
{
|
|
342380
342851
|
name: "get_live_dashboard",
|
|
342381
342852
|
description: "Live multi-client dashboard \u2014 read the current unified dashboard state/summary, or the number of connected dashboard subscribers."
|
|
342853
|
+
},
|
|
342854
|
+
{
|
|
342855
|
+
name: "ingest_apm_spans",
|
|
342856
|
+
description: "Ingest OTLP/HTTP-JSON distributed-trace spans into the APM trace store (feeds bottleneck/slowest-trace analysis and the dashboard APM section)."
|
|
342857
|
+
},
|
|
342858
|
+
{
|
|
342859
|
+
name: "get_apm_summary",
|
|
342860
|
+
description: "Read the APM summary \u2014 traces, spans, per-service error rates and p95 latency."
|
|
342861
|
+
},
|
|
342862
|
+
{
|
|
342863
|
+
name: "ingest_dem_beacon",
|
|
342864
|
+
description: "Ingest a Core Web Vitals RUM beacon (page, LCP/INP/CLS/TTFB, JS errors) into the DEM store (feeds per-page p75 + error rate and the dashboard DEM section)."
|
|
342865
|
+
},
|
|
342866
|
+
{
|
|
342867
|
+
name: "get_dem_summary",
|
|
342868
|
+
description: "Read the DEM summary \u2014 sessions, pages, p75 Core Web Vitals, error rate."
|
|
342869
|
+
},
|
|
342870
|
+
{
|
|
342871
|
+
name: "collect_infra",
|
|
342872
|
+
description: "Collect Kubernetes cluster health \u2014 runs `kubectl get pods -A -o json` (or accepts the payload), feeds the infra monitor (pod readiness, restarts, CrashLoopBackOff)."
|
|
342873
|
+
},
|
|
342874
|
+
{
|
|
342875
|
+
name: "manage_etw",
|
|
342876
|
+
description: "Windows ETW diagnostics \u2014 start/stop a trace (logman), parse captured Get-WinEvent/Get-Counter output, list sessions. Use against a Windows host for network/file/registry/process/DNS diagnostics."
|
|
342382
342877
|
}
|
|
342383
342878
|
];
|
|
342384
342879
|
function buildReadFileDescription(support) {
|
|
@@ -346791,6 +347286,152 @@ async function getLiveDashboard(args, context2) {
|
|
|
346791
347286
|
emit9(context2, "get_live_dashboard", args, out);
|
|
346792
347287
|
return out;
|
|
346793
347288
|
}
|
|
347289
|
+
var ingestApmSpansSchema = external_exports.object({
|
|
347290
|
+
payload: external_exports.any().describe("OTLP/HTTP-JSON payload: {resourceSpans:[...]} with spans (traceId/spanId/name/startTimeUnixNano/endTimeUnixNano/status)."),
|
|
347291
|
+
defaultService: external_exports.string().optional().describe("Fallback service name when a span has none.")
|
|
347292
|
+
});
|
|
347293
|
+
async function ingestApmSpans(args, context2) {
|
|
347294
|
+
const { o, msg } = obs(context2, "ingest_apm_spans", args);
|
|
347295
|
+
if (!o) return msg;
|
|
347296
|
+
const { ingestOtlp: ingestOtlp2 } = await Promise.resolve().then(() => (init_spanLedger(), spanLedger_exports));
|
|
347297
|
+
const n2 = ingestOtlp2(o.spanLedger, args.payload, args.defaultService);
|
|
347298
|
+
const out = `Ingested ${n2} APM span(s) into the trace store.`;
|
|
347299
|
+
emit9(context2, "ingest_apm_spans", args, out);
|
|
347300
|
+
return out;
|
|
347301
|
+
}
|
|
347302
|
+
var getApmSummarySchema = external_exports.object({});
|
|
347303
|
+
async function getApmSummary(_args, context2) {
|
|
347304
|
+
const { o, msg } = obs(context2, "get_apm_summary", _args);
|
|
347305
|
+
if (!o) return msg;
|
|
347306
|
+
const stats = o.spanLedger.serviceStats();
|
|
347307
|
+
const out = stats.length ? `APM: ${o.spanLedger.size()} spans across ${stats.length} service(s). ` + stats.map((x) => `${x.service}(${x.spans}${x.errors ? ", " + x.errors + " err" : ""})`).join(", ") : "APM: no spans ingested yet.";
|
|
347308
|
+
emit9(context2, "get_apm_summary", _args, out);
|
|
347309
|
+
return out;
|
|
347310
|
+
}
|
|
347311
|
+
var ingestDemBeaconSchema = external_exports.object({
|
|
347312
|
+
payload: external_exports.any().describe("RUM beacon: {page, route?, region?, userAgent?, lcpMs?, inpMs?, cls?, ttfbMs?, jsErrors?, at?}.")
|
|
347313
|
+
});
|
|
347314
|
+
async function ingestDemBeacon(args, context2) {
|
|
347315
|
+
const { o, msg } = obs(context2, "ingest_dem_beacon", args);
|
|
347316
|
+
if (!o) return msg;
|
|
347317
|
+
const s = o.rumLedger.ingestBeacon(args.payload);
|
|
347318
|
+
const out = s ? `Ingested RUM beacon for ${s.page}${s.lcpMs ? ` (LCP ${s.lcpMs}ms)` : ""}.` : "Beacon ignored \u2014 needs a `page` field.";
|
|
347319
|
+
emit9(context2, "ingest_dem_beacon", args, out);
|
|
347320
|
+
return out;
|
|
347321
|
+
}
|
|
347322
|
+
var getDemSummarySchema = external_exports.object({});
|
|
347323
|
+
async function getDemSummary(_args, context2) {
|
|
347324
|
+
const { o, msg } = obs(context2, "get_dem_summary", _args);
|
|
347325
|
+
if (!o) return msg;
|
|
347326
|
+
const pages = o.rumLedger.pageStats();
|
|
347327
|
+
const out = pages.length ? `DEM: ${o.rumLedger.size()} sessions across ${pages.length} page(s). ` + pages.map((p) => `${p.page}(${p.sessions}${p.errorRate ? `, ${(p.errorRate * 100).toFixed(0)}% err` : ""})`).join(", ") : "DEM: no RUM sessions ingested yet.";
|
|
347328
|
+
emit9(context2, "get_dem_summary", _args, out);
|
|
347329
|
+
return out;
|
|
347330
|
+
}
|
|
347331
|
+
var collectInfraSchema = external_exports.object({
|
|
347332
|
+
context: external_exports.string().optional().describe("Cluster context name (default 'default')."),
|
|
347333
|
+
kubectlJson: external_exports.any().optional().describe("Parsed `kubectl get pods -A -o json` payload (or its text). If omitted, runs kubectl on the local shell.")
|
|
347334
|
+
});
|
|
347335
|
+
async function collectInfra(args, context2) {
|
|
347336
|
+
const { o, msg } = obs(context2, "collect_infra", args);
|
|
347337
|
+
if (!o) return msg;
|
|
347338
|
+
const { parseKubectlPods: parseKubectlPods2 } = await Promise.resolve().then(() => (init_infraMonitor(), infraMonitor_exports));
|
|
347339
|
+
const clusterCtx = args.context ?? "default";
|
|
347340
|
+
let out;
|
|
347341
|
+
try {
|
|
347342
|
+
let payload = args.kubectlJson;
|
|
347343
|
+
if (payload === void 0) {
|
|
347344
|
+
const { execFile: execFile2 } = await import("node:child_process");
|
|
347345
|
+
payload = await new Promise((resolve2, reject) => {
|
|
347346
|
+
execFile2("kubectl", ["get", "pods", "-A"], { timeout: 3e4, maxBuffer: 16 * 1024 * 1024 }, (err, stdout) => {
|
|
347347
|
+
if (err) return reject(err);
|
|
347348
|
+
resolve2(stdout);
|
|
347349
|
+
});
|
|
347350
|
+
});
|
|
347351
|
+
}
|
|
347352
|
+
const text = typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
347353
|
+
let pods = parseKubectlPods2(text);
|
|
347354
|
+
if (pods.length === 0 && typeof payload === "object" && payload !== null) {
|
|
347355
|
+
const jsonObj = payload;
|
|
347356
|
+
const items = jsonObj.items ?? [];
|
|
347357
|
+
const table = ["NAMESPACE NAME READY STATUS RESTARTS AGE", ...items.map((it) => {
|
|
347358
|
+
const ns = it.metadata?.namespace ?? "default";
|
|
347359
|
+
const name = it.metadata?.name ?? "pod";
|
|
347360
|
+
const cs = it.status?.containerStatuses ?? [];
|
|
347361
|
+
const ready = `${cs.filter((c) => c.ready).length}/${cs.length || 1}`;
|
|
347362
|
+
const status = it.status?.phase ?? "Unknown";
|
|
347363
|
+
const restarts = String(cs.reduce((s, c) => s + (c.restartCount ?? 0), 0));
|
|
347364
|
+
return `${ns} ${name} ${ready} ${status} ${restarts} 1d`;
|
|
347365
|
+
})].join("\n");
|
|
347366
|
+
pods = parseKubectlPods2(table);
|
|
347367
|
+
}
|
|
347368
|
+
const health = o.infraMonitor.recordCluster(clusterCtx, pods, []);
|
|
347369
|
+
out = `k8s ${clusterCtx}: ${pods.length} pods, ${health.notReadyPods} not-ready, ${health.crashLoopPods} CrashLoopBackOff.`;
|
|
347370
|
+
} catch (e) {
|
|
347371
|
+
out = `infra collect failed (kubectl or cluster unavailable): ${e instanceof Error ? e.message : String(e)}`;
|
|
347372
|
+
}
|
|
347373
|
+
emit9(context2, "collect_infra", args, out);
|
|
347374
|
+
return out;
|
|
347375
|
+
}
|
|
347376
|
+
var manageEtwSchema = external_exports.object({
|
|
347377
|
+
action: external_exports.enum(["start", "stop", "parse", "sessions"]).describe("start a trace, stop it, parse captured output, or list sessions."),
|
|
347378
|
+
name: external_exports.string().optional().describe("Trace name (start)."),
|
|
347379
|
+
providers: external_exports.array(external_exports.enum(["network", "file", "registry", "process", "dns", "power"])).optional().describe("ETW providers to trace (start)."),
|
|
347380
|
+
sessionId: external_exports.string().optional().describe("Session id (stop)."),
|
|
347381
|
+
output: external_exports.string().optional().describe("Captured Get-WinEvent/Get-Counter output (parse)."),
|
|
347382
|
+
format: external_exports.enum(["winevent", "counter"]).optional().describe("Parse format (parse).")
|
|
347383
|
+
});
|
|
347384
|
+
async function manageEtw(args, context2) {
|
|
347385
|
+
const { o, msg } = obs(context2, "manage_etw", args);
|
|
347386
|
+
if (!o) return msg;
|
|
347387
|
+
const svc = o.etwService;
|
|
347388
|
+
let out;
|
|
347389
|
+
try {
|
|
347390
|
+
if (args.action === "start") {
|
|
347391
|
+
if (!args.name || !args.providers?.length) {
|
|
347392
|
+
out = "start requires name + providers.";
|
|
347393
|
+
} else {
|
|
347394
|
+
const s = svc.createSession(args.name, args.providers);
|
|
347395
|
+
const { buildStartCommands: buildStartCommands2 } = await Promise.resolve().then(() => (init_etwService(), etwService_exports));
|
|
347396
|
+
out = `ETW session ${s.id} created (${args.providers.join(", ")}). Start commands:
|
|
347397
|
+
${buildStartCommands2(s).join("\n")}`;
|
|
347398
|
+
}
|
|
347399
|
+
} else if (args.action === "stop") {
|
|
347400
|
+
if (!args.sessionId) {
|
|
347401
|
+
out = "stop requires sessionId.";
|
|
347402
|
+
} else {
|
|
347403
|
+
const s = svc.session(args.sessionId);
|
|
347404
|
+
if (!s) {
|
|
347405
|
+
out = `No ETW session ${args.sessionId}.`;
|
|
347406
|
+
} else {
|
|
347407
|
+
const { buildStopCommands: buildStopCommands2 } = await Promise.resolve().then(() => (init_etwService(), etwService_exports));
|
|
347408
|
+
out = `Stop commands for ${args.sessionId}:
|
|
347409
|
+
${buildStopCommands2(s).join("\n")}`;
|
|
347410
|
+
}
|
|
347411
|
+
}
|
|
347412
|
+
} else if (args.action === "parse") {
|
|
347413
|
+
if (!args.output) {
|
|
347414
|
+
out = "parse requires output.";
|
|
347415
|
+
} else {
|
|
347416
|
+
const { parseWinEventJson: parseWinEventJson2, parseWinEventText: parseWinEventText2, parseCounterJson: parseCounterJson2 } = await Promise.resolve().then(() => (init_etwService(), etwService_exports));
|
|
347417
|
+
if (args.format === "counter") {
|
|
347418
|
+
const c = parseCounterJson2(args.output);
|
|
347419
|
+
out = `${c.length} counter sample(s).`;
|
|
347420
|
+
} else {
|
|
347421
|
+
const ev = parseWinEventJson2(args.output) ?? parseWinEventText2(args.output);
|
|
347422
|
+
out = `${ev.length} event(s) parsed.`;
|
|
347423
|
+
}
|
|
347424
|
+
}
|
|
347425
|
+
} else {
|
|
347426
|
+
const sessions = svc.sessions_();
|
|
347427
|
+
out = sessions.length ? sessions.map((s) => `- ${s.id} (${s.name}): ${s.providers.join(",")}`).join("\n") : "No ETW sessions.";
|
|
347428
|
+
}
|
|
347429
|
+
} catch (e) {
|
|
347430
|
+
out = `etw error: ${e instanceof Error ? e.message : String(e)}`;
|
|
347431
|
+
}
|
|
347432
|
+
emit9(context2, "manage_etw", args, out);
|
|
347433
|
+
return out;
|
|
347434
|
+
}
|
|
346794
347435
|
|
|
346795
347436
|
// packages/backend/src/services/AgentHelper/tools/skill_tools.ts
|
|
346796
347437
|
var skillToolSchema = external_exports.object({
|
|
@@ -347104,6 +347745,36 @@ function buildToolsForModel(readFileSupport) {
|
|
|
347104
347745
|
name: "get_live_dashboard",
|
|
347105
347746
|
description: "Live multi-client dashboard \u2014 read the current unified dashboard state/summary, or the number of connected dashboard subscribers.",
|
|
347106
347747
|
schema: getLiveDashboardSchema
|
|
347748
|
+
},
|
|
347749
|
+
{
|
|
347750
|
+
name: "ingest_apm_spans",
|
|
347751
|
+
description: "Ingest OTLP/HTTP-JSON distributed-trace spans into the APM trace store (feeds bottleneck/slowest-trace analysis and the dashboard APM section).",
|
|
347752
|
+
schema: ingestApmSpansSchema
|
|
347753
|
+
},
|
|
347754
|
+
{
|
|
347755
|
+
name: "get_apm_summary",
|
|
347756
|
+
description: "Read the APM summary \u2014 traces, spans, per-service error rates and p95 latency.",
|
|
347757
|
+
schema: getApmSummarySchema
|
|
347758
|
+
},
|
|
347759
|
+
{
|
|
347760
|
+
name: "ingest_dem_beacon",
|
|
347761
|
+
description: "Ingest a Core Web Vitals RUM beacon (page, LCP/INP/CLS/TTFB, JS errors) into the DEM store (feeds per-page p75 + error rate and the dashboard DEM section).",
|
|
347762
|
+
schema: ingestDemBeaconSchema
|
|
347763
|
+
},
|
|
347764
|
+
{
|
|
347765
|
+
name: "get_dem_summary",
|
|
347766
|
+
description: "Read the DEM summary \u2014 sessions, pages, p75 Core Web Vitals, error rate.",
|
|
347767
|
+
schema: getDemSummarySchema
|
|
347768
|
+
},
|
|
347769
|
+
{
|
|
347770
|
+
name: "collect_infra",
|
|
347771
|
+
description: "Collect Kubernetes cluster health \u2014 runs `kubectl get pods -A -o json` (or accepts the payload), feeds the infra monitor (pod readiness, restarts, CrashLoopBackOff).",
|
|
347772
|
+
schema: collectInfraSchema
|
|
347773
|
+
},
|
|
347774
|
+
{
|
|
347775
|
+
name: "manage_etw",
|
|
347776
|
+
description: "Windows ETW diagnostics \u2014 start/stop a trace (logman), parse captured Get-WinEvent/Get-Counter output, list sessions. Use against a Windows host for network/file/registry/process/DNS diagnostics.",
|
|
347777
|
+
schema: manageEtwSchema
|
|
347107
347778
|
}
|
|
347108
347779
|
].map((tool2) => convertToOpenAITool(tool2));
|
|
347109
347780
|
}
|
|
@@ -347149,6 +347820,12 @@ var toolImplementations = {
|
|
|
347149
347820
|
managePlaybookVersion,
|
|
347150
347821
|
getCloudInventory,
|
|
347151
347822
|
getLiveDashboard,
|
|
347823
|
+
ingestApmSpans,
|
|
347824
|
+
getApmSummary,
|
|
347825
|
+
ingestDemBeacon,
|
|
347826
|
+
getDemSummary,
|
|
347827
|
+
collectInfra,
|
|
347828
|
+
manageEtw,
|
|
347152
347829
|
writeFile,
|
|
347153
347830
|
editFile,
|
|
347154
347831
|
writeAndEdit,
|
|
@@ -361696,6 +362373,60 @@ Actually, your intention might be different. Please re-read the description of t
|
|
|
361696
362373
|
}
|
|
361697
362374
|
break;
|
|
361698
362375
|
}
|
|
362376
|
+
case "ingest_apm_spans": {
|
|
362377
|
+
try {
|
|
362378
|
+
const validatedArgs = ingestApmSpansSchema.parse(toolCall.args || {});
|
|
362379
|
+
result = await toolImplementations.ingestApmSpans(validatedArgs, executionContext);
|
|
362380
|
+
} catch (err) {
|
|
362381
|
+
result = `Parameter validation error for ingest_apm_spans: ${err.message}`;
|
|
362382
|
+
}
|
|
362383
|
+
break;
|
|
362384
|
+
}
|
|
362385
|
+
case "get_apm_summary": {
|
|
362386
|
+
try {
|
|
362387
|
+
const validatedArgs = getApmSummarySchema.parse(toolCall.args || {});
|
|
362388
|
+
result = await toolImplementations.getApmSummary(validatedArgs, executionContext);
|
|
362389
|
+
} catch (err) {
|
|
362390
|
+
result = `Parameter validation error for get_apm_summary: ${err.message}`;
|
|
362391
|
+
}
|
|
362392
|
+
break;
|
|
362393
|
+
}
|
|
362394
|
+
case "ingest_dem_beacon": {
|
|
362395
|
+
try {
|
|
362396
|
+
const validatedArgs = ingestDemBeaconSchema.parse(toolCall.args || {});
|
|
362397
|
+
result = await toolImplementations.ingestDemBeacon(validatedArgs, executionContext);
|
|
362398
|
+
} catch (err) {
|
|
362399
|
+
result = `Parameter validation error for ingest_dem_beacon: ${err.message}`;
|
|
362400
|
+
}
|
|
362401
|
+
break;
|
|
362402
|
+
}
|
|
362403
|
+
case "get_dem_summary": {
|
|
362404
|
+
try {
|
|
362405
|
+
const validatedArgs = getDemSummarySchema.parse(toolCall.args || {});
|
|
362406
|
+
result = await toolImplementations.getDemSummary(validatedArgs, executionContext);
|
|
362407
|
+
} catch (err) {
|
|
362408
|
+
result = `Parameter validation error for get_dem_summary: ${err.message}`;
|
|
362409
|
+
}
|
|
362410
|
+
break;
|
|
362411
|
+
}
|
|
362412
|
+
case "collect_infra": {
|
|
362413
|
+
try {
|
|
362414
|
+
const validatedArgs = collectInfraSchema.parse(toolCall.args || {});
|
|
362415
|
+
result = await toolImplementations.collectInfra(validatedArgs, executionContext);
|
|
362416
|
+
} catch (err) {
|
|
362417
|
+
result = `Parameter validation error for collect_infra: ${err.message}`;
|
|
362418
|
+
}
|
|
362419
|
+
break;
|
|
362420
|
+
}
|
|
362421
|
+
case "manage_etw": {
|
|
362422
|
+
try {
|
|
362423
|
+
const validatedArgs = manageEtwSchema.parse(toolCall.args || {});
|
|
362424
|
+
result = await toolImplementations.manageEtw(validatedArgs, executionContext);
|
|
362425
|
+
} catch (err) {
|
|
362426
|
+
result = `Parameter validation error for manage_etw: ${err.message}`;
|
|
362427
|
+
}
|
|
362428
|
+
break;
|
|
362429
|
+
}
|
|
361699
362430
|
case "manage_device_memory": {
|
|
361700
362431
|
try {
|
|
361701
362432
|
const validatedArgs = manageDeviceMemorySchema.parse(toolCall.args || {});
|
|
@@ -377698,7 +378429,7 @@ var AgentSettingProfileService = class {
|
|
|
377698
378429
|
};
|
|
377699
378430
|
|
|
377700
378431
|
// packages/backend/src/services/automation/triggerEngine.ts
|
|
377701
|
-
var
|
|
378432
|
+
var import_crypto10 = require("crypto");
|
|
377702
378433
|
var DEFAULT_COOLDOWN_S = 300;
|
|
377703
378434
|
var HISTORY_LIMIT_DEFAULT2 = 200;
|
|
377704
378435
|
var MAX_CONCURRENT_DEFAULT = 3;
|
|
@@ -377742,7 +378473,7 @@ var TriggerEngine = class {
|
|
|
377742
378473
|
}
|
|
377743
378474
|
const entry = {
|
|
377744
378475
|
...input,
|
|
377745
|
-
id: input.id ?? `trg-${(0,
|
|
378476
|
+
id: input.id ?? `trg-${(0, import_crypto10.randomUUID)().slice(0, 8)}`,
|
|
377746
378477
|
createdAt: this.now(),
|
|
377747
378478
|
fireCount: 0
|
|
377748
378479
|
};
|
|
@@ -377847,7 +378578,7 @@ var TriggerEngine = class {
|
|
|
377847
378578
|
t.lastFiredAt = now;
|
|
377848
378579
|
t.fireCount = (t.fireCount ?? 0) + 1;
|
|
377849
378580
|
const rec = {
|
|
377850
|
-
id: `fire-${(0,
|
|
378581
|
+
id: `fire-${(0, import_crypto10.randomUUID)().slice(0, 8)}`,
|
|
377851
378582
|
triggerId: t.id,
|
|
377852
378583
|
triggerName: t.name,
|
|
377853
378584
|
at: now,
|
|
@@ -377939,7 +378670,7 @@ var import_node_module2 = require("node:module");
|
|
|
377939
378670
|
var import_node_path27 = __toESM(require("node:path"), 1);
|
|
377940
378671
|
|
|
377941
378672
|
// packages/backend/src/services/sre/metricsLedger.ts
|
|
377942
|
-
var
|
|
378673
|
+
var DEFAULT_LIMIT2 = 1e4;
|
|
377943
378674
|
function flattenSnapshot(host, snap) {
|
|
377944
378675
|
const p = { host, at: snap.timestamp };
|
|
377945
378676
|
if (snap.cpu && typeof snap.cpu.usagePercent === "number") p.cpuUsagePercent = snap.cpu.usagePercent;
|
|
@@ -377963,7 +378694,7 @@ var MetricsLedger = class {
|
|
|
377963
378694
|
points = /* @__PURE__ */ new Map();
|
|
377964
378695
|
perHostLimit;
|
|
377965
378696
|
constructor(opts = {}) {
|
|
377966
|
-
this.perHostLimit = opts.perHostLimit ??
|
|
378697
|
+
this.perHostLimit = opts.perHostLimit ?? DEFAULT_LIMIT2;
|
|
377967
378698
|
}
|
|
377968
378699
|
/** Ingest a resource snapshot for a host. Returns the stored point. */
|
|
377969
378700
|
record(host, snap) {
|
|
@@ -378042,7 +378773,7 @@ var MetricsLedger = class {
|
|
|
378042
378773
|
|
|
378043
378774
|
// packages/backend/src/services/sre/goldenSignals.ts
|
|
378044
378775
|
var DEFAULT_WINDOW = 36e5;
|
|
378045
|
-
function
|
|
378776
|
+
function percentile2(sorted, p) {
|
|
378046
378777
|
if (sorted.length === 0) return void 0;
|
|
378047
378778
|
const rank = Math.max(1, Math.ceil(p / 100 * sorted.length));
|
|
378048
378779
|
return sorted[Math.min(rank, sorted.length) - 1];
|
|
@@ -378071,9 +378802,9 @@ var GoldenSignals = class {
|
|
|
378071
378802
|
if (this.deps.latencyFor) {
|
|
378072
378803
|
const samples = this.deps.latencyFor(host, since).map((s) => s.ms).sort((a, b) => a - b);
|
|
378073
378804
|
if (samples.length > 0) {
|
|
378074
|
-
r.latencyP50Ms =
|
|
378075
|
-
r.latencyP95Ms =
|
|
378076
|
-
r.latencyP99Ms =
|
|
378805
|
+
r.latencyP50Ms = percentile2(samples, 50);
|
|
378806
|
+
r.latencyP95Ms = percentile2(samples, 95);
|
|
378807
|
+
r.latencyP99Ms = percentile2(samples, 99);
|
|
378077
378808
|
}
|
|
378078
378809
|
}
|
|
378079
378810
|
if (this.deps.errorRateFor) {
|
|
@@ -378104,7 +378835,7 @@ var GoldenSignals = class {
|
|
|
378104
378835
|
};
|
|
378105
378836
|
|
|
378106
378837
|
// packages/backend/src/services/sre/sloService.ts
|
|
378107
|
-
var
|
|
378838
|
+
var import_crypto11 = require("crypto");
|
|
378108
378839
|
var DEFAULT_FAST_BURN = 2;
|
|
378109
378840
|
var SloService = class {
|
|
378110
378841
|
constructor(deps) {
|
|
@@ -378128,7 +378859,7 @@ var SloService = class {
|
|
|
378128
378859
|
}
|
|
378129
378860
|
const entry = {
|
|
378130
378861
|
...def,
|
|
378131
|
-
id: def.id ?? `slo-${(0,
|
|
378862
|
+
id: def.id ?? `slo-${(0, import_crypto11.randomUUID)().slice(0, 8)}`,
|
|
378132
378863
|
createdAt: this.now()
|
|
378133
378864
|
};
|
|
378134
378865
|
this.slos.set(entry.id, entry);
|
|
@@ -378195,7 +378926,7 @@ var SloService = class {
|
|
|
378195
378926
|
};
|
|
378196
378927
|
|
|
378197
378928
|
// packages/backend/src/services/sre/uptimeWatchdog.ts
|
|
378198
|
-
var
|
|
378929
|
+
var import_crypto12 = require("crypto");
|
|
378199
378930
|
var UptimeWatchdog = class {
|
|
378200
378931
|
constructor(deps) {
|
|
378201
378932
|
this.deps = deps;
|
|
@@ -378207,7 +378938,7 @@ var UptimeWatchdog = class {
|
|
|
378207
378938
|
upsert(target) {
|
|
378208
378939
|
const t = {
|
|
378209
378940
|
...target,
|
|
378210
|
-
id: target.id ?? `wt-${(0,
|
|
378941
|
+
id: target.id ?? `wt-${(0, import_crypto12.randomUUID)().slice(0, 8)}`,
|
|
378211
378942
|
downAfter: target.downAfter ?? 3,
|
|
378212
378943
|
intervalMs: target.intervalMs ?? 6e4
|
|
378213
378944
|
};
|
|
@@ -378306,7 +379037,7 @@ var UptimeWatchdog = class {
|
|
|
378306
379037
|
};
|
|
378307
379038
|
|
|
378308
379039
|
// packages/backend/src/services/sre/alertService.ts
|
|
378309
|
-
var
|
|
379040
|
+
var import_crypto13 = require("crypto");
|
|
378310
379041
|
var SEV_ORDER = { info: 0, warning: 1, critical: 2 };
|
|
378311
379042
|
var DEFAULT_DEDUPE_MS = 3e5;
|
|
378312
379043
|
var DEFAULT_HISTORY = 200;
|
|
@@ -378331,7 +379062,7 @@ var AlertService = class {
|
|
|
378331
379062
|
}
|
|
378332
379063
|
/** Create a silence that suppresses matching alerts until `untilMs`. */
|
|
378333
379064
|
silence(matcher, untilMs, opts = {}) {
|
|
378334
|
-
const s = { id: `sil-${(0,
|
|
379065
|
+
const s = { id: `sil-${(0, import_crypto13.randomUUID)().slice(0, 8)}`, matcher, until: untilMs, ...opts };
|
|
378335
379066
|
this.silences.set(s.id, s);
|
|
378336
379067
|
return s;
|
|
378337
379068
|
}
|
|
@@ -378428,8 +379159,8 @@ var AlertService = class {
|
|
|
378428
379159
|
};
|
|
378429
379160
|
|
|
378430
379161
|
// packages/backend/src/services/sre/incidentLedger.ts
|
|
378431
|
-
var
|
|
378432
|
-
var
|
|
379162
|
+
var import_crypto14 = require("crypto");
|
|
379163
|
+
var DEFAULT_LIMIT3 = 500;
|
|
378433
379164
|
var IncidentLedger = class {
|
|
378434
379165
|
incidents = /* @__PURE__ */ new Map();
|
|
378435
379166
|
order = [];
|
|
@@ -378437,7 +379168,7 @@ var IncidentLedger = class {
|
|
|
378437
379168
|
historyLimit;
|
|
378438
379169
|
constructor(opts = {}) {
|
|
378439
379170
|
this.now = opts.now ?? (() => Date.now());
|
|
378440
|
-
this.historyLimit = opts.historyLimit ??
|
|
379171
|
+
this.historyLimit = opts.historyLimit ?? DEFAULT_LIMIT3;
|
|
378441
379172
|
}
|
|
378442
379173
|
/** Create (or return the existing open incident for the same title+source). */
|
|
378443
379174
|
create(input) {
|
|
@@ -378450,7 +379181,7 @@ var IncidentLedger = class {
|
|
|
378450
379181
|
}
|
|
378451
379182
|
const at = this.now();
|
|
378452
379183
|
const inc = {
|
|
378453
|
-
id: `inc-${(0,
|
|
379184
|
+
id: `inc-${(0, import_crypto14.randomUUID)().slice(0, 8)}`,
|
|
378454
379185
|
title: input.title,
|
|
378455
379186
|
severity: input.severity ?? "sev3",
|
|
378456
379187
|
status: "open",
|
|
@@ -378550,12 +379281,12 @@ Linked playbook: ${inc.runbookPlaybookId}` : ""
|
|
|
378550
379281
|
};
|
|
378551
379282
|
|
|
378552
379283
|
// packages/backend/src/services/sre/syntheticChecks.ts
|
|
378553
|
-
var
|
|
379284
|
+
var DEFAULT_LIMIT4 = 1e3;
|
|
378554
379285
|
var SyntheticChecks = class {
|
|
378555
379286
|
constructor(deps) {
|
|
378556
379287
|
this.deps = deps;
|
|
378557
379288
|
this.now = deps.now ?? (() => Date.now());
|
|
378558
|
-
this.perCheckLimit = deps.perCheckLimit ??
|
|
379289
|
+
this.perCheckLimit = deps.perCheckLimit ?? DEFAULT_LIMIT4;
|
|
378559
379290
|
}
|
|
378560
379291
|
checks = /* @__PURE__ */ new Map();
|
|
378561
379292
|
results = /* @__PURE__ */ new Map();
|
|
@@ -378673,7 +379404,7 @@ var SyntheticChecks = class {
|
|
|
378673
379404
|
};
|
|
378674
379405
|
|
|
378675
379406
|
// packages/backend/src/services/sre/driftDetector.ts
|
|
378676
|
-
var
|
|
379407
|
+
var import_crypto15 = require("crypto");
|
|
378677
379408
|
function normalize2(text, ignorePatterns = []) {
|
|
378678
379409
|
const lines = text.split(/\r?\n/).map((l) => l.trimEnd()).filter((l) => l.trim() !== "");
|
|
378679
379410
|
const regexes = ignorePatterns.map((p) => {
|
|
@@ -378709,7 +379440,7 @@ var DriftDetector = class {
|
|
|
378709
379440
|
lastResults = /* @__PURE__ */ new Map();
|
|
378710
379441
|
now;
|
|
378711
379442
|
upsert(target) {
|
|
378712
|
-
const t = { ...target, id: target.id ?? `drift-${(0,
|
|
379443
|
+
const t = { ...target, id: target.id ?? `drift-${(0, import_crypto15.randomUUID)().slice(0, 8)}` };
|
|
378713
379444
|
this.targets.set(t.id, t);
|
|
378714
379445
|
return t;
|
|
378715
379446
|
}
|
|
@@ -378769,130 +379500,11 @@ var DriftDetector = class {
|
|
|
378769
379500
|
}
|
|
378770
379501
|
};
|
|
378771
379502
|
|
|
378772
|
-
// packages/backend/src/services/
|
|
378773
|
-
|
|
378774
|
-
function percentile2(sorted, p) {
|
|
378775
|
-
if (sorted.length === 0) return void 0;
|
|
378776
|
-
return sorted[Math.min(sorted.length - 1, Math.floor(p / 100 * sorted.length))];
|
|
378777
|
-
}
|
|
378778
|
-
var SpanLedger = class {
|
|
378779
|
-
spans = /* @__PURE__ */ new Map();
|
|
378780
|
-
// traceId -> spans
|
|
378781
|
-
order = [];
|
|
378782
|
-
// traceIds in insert order
|
|
378783
|
-
spanLimit;
|
|
378784
|
-
totalSpans = 0;
|
|
378785
|
-
constructor(opts = {}) {
|
|
378786
|
-
this.spanLimit = opts.spanLimit ?? DEFAULT_LIMIT4;
|
|
378787
|
-
}
|
|
378788
|
-
/** Ingest one span. */
|
|
378789
|
-
ingest(span) {
|
|
378790
|
-
let arr3 = this.spans.get(span.traceId);
|
|
378791
|
-
if (!arr3) {
|
|
378792
|
-
arr3 = [];
|
|
378793
|
-
this.spans.set(span.traceId, arr3);
|
|
378794
|
-
this.order.push(span.traceId);
|
|
378795
|
-
}
|
|
378796
|
-
arr3.push(span);
|
|
378797
|
-
this.totalSpans += 1;
|
|
378798
|
-
while (this.totalSpans > this.spanLimit && this.order.length > 0) {
|
|
378799
|
-
const oldest = this.order.shift();
|
|
378800
|
-
const old = this.spans.get(oldest) ?? [];
|
|
378801
|
-
this.totalSpans -= old.length;
|
|
378802
|
-
this.spans.delete(oldest);
|
|
378803
|
-
}
|
|
378804
|
-
}
|
|
378805
|
-
/** Ingest many spans. */
|
|
378806
|
-
ingestBatch(spans) {
|
|
378807
|
-
for (const s of spans) this.ingest(s);
|
|
378808
|
-
return spans.length;
|
|
378809
|
-
}
|
|
378810
|
-
/** All spans for a trace. */
|
|
378811
|
-
trace(traceId) {
|
|
378812
|
-
return this.spans.get(traceId) ?? [];
|
|
378813
|
-
}
|
|
378814
|
-
traceIds() {
|
|
378815
|
-
return this.order;
|
|
378816
|
-
}
|
|
378817
|
-
/** Summarize a trace (root service, span count, total duration, error). */
|
|
378818
|
-
summarize(traceId) {
|
|
378819
|
-
const spans = this.spans.get(traceId);
|
|
378820
|
-
if (!spans || spans.length === 0) return void 0;
|
|
378821
|
-
const root = spans.find((s) => !s.parentSpanId) ?? spans[0];
|
|
378822
|
-
const services = Array.from(new Set(spans.map((s) => s.service)));
|
|
378823
|
-
const hasError = spans.some((s) => s.status === "error");
|
|
378824
|
-
const start = Math.min(...spans.map((s) => s.startMs));
|
|
378825
|
-
const end = Math.max(...spans.map((s) => s.startMs + s.durationMs));
|
|
378826
|
-
return {
|
|
378827
|
-
traceId,
|
|
378828
|
-
rootService: root.service,
|
|
378829
|
-
spanCount: spans.length,
|
|
378830
|
-
totalDurationMs: end - start,
|
|
378831
|
-
hasError,
|
|
378832
|
-
services,
|
|
378833
|
-
at: start
|
|
378834
|
-
};
|
|
378835
|
-
}
|
|
378836
|
-
/** Per-service stats over a window. */
|
|
378837
|
-
serviceStats(opts = {}) {
|
|
378838
|
-
const byService = /* @__PURE__ */ new Map();
|
|
378839
|
-
for (const arr3 of this.spans.values()) {
|
|
378840
|
-
for (const s of arr3) {
|
|
378841
|
-
if (opts.sinceMs !== void 0 && s.startMs < opts.sinceMs) continue;
|
|
378842
|
-
if (opts.service && s.service !== opts.service) continue;
|
|
378843
|
-
let e = byService.get(s.service);
|
|
378844
|
-
if (!e) {
|
|
378845
|
-
e = { durations: [], errors: 0 };
|
|
378846
|
-
byService.set(s.service, e);
|
|
378847
|
-
}
|
|
378848
|
-
e.durations.push(s.durationMs);
|
|
378849
|
-
if (s.status === "error") e.errors += 1;
|
|
378850
|
-
}
|
|
378851
|
-
}
|
|
378852
|
-
const out = [];
|
|
378853
|
-
for (const [service, e] of byService) {
|
|
378854
|
-
const durations = e.durations.slice().sort((a, b) => a - b);
|
|
378855
|
-
out.push({
|
|
378856
|
-
service,
|
|
378857
|
-
spanCount: durations.length,
|
|
378858
|
-
errorCount: e.errors,
|
|
378859
|
-
errorRate: durations.length > 0 ? e.errors / durations.length : 0,
|
|
378860
|
-
p50Ms: percentile2(durations, 50),
|
|
378861
|
-
p95Ms: percentile2(durations, 95),
|
|
378862
|
-
p99Ms: percentile2(durations, 99),
|
|
378863
|
-
maxMs: durations.length > 0 ? durations[durations.length - 1] : void 0
|
|
378864
|
-
});
|
|
378865
|
-
}
|
|
378866
|
-
return out.sort((a, b) => (b.p95Ms ?? 0) - (a.p95Ms ?? 0));
|
|
378867
|
-
}
|
|
378868
|
-
/** Slowest traces by total duration. */
|
|
378869
|
-
slowestTraces(limit2 = 10, opts = {}) {
|
|
378870
|
-
const summaries = [];
|
|
378871
|
-
for (const id of this.order) {
|
|
378872
|
-
const s = this.summarize(id);
|
|
378873
|
-
if (!s) continue;
|
|
378874
|
-
if (opts.sinceMs !== void 0 && s.at < opts.sinceMs) continue;
|
|
378875
|
-
summaries.push(s);
|
|
378876
|
-
}
|
|
378877
|
-
return summaries.sort((a, b) => b.totalDurationMs - a.totalDurationMs).slice(0, limit2);
|
|
378878
|
-
}
|
|
378879
|
-
/** Services ranked by total error count (bottleneck/failing services). */
|
|
378880
|
-
bottleneckServices(opts = {}) {
|
|
378881
|
-
return this.serviceStats(opts).sort((a, b) => b.errorCount - a.errorCount);
|
|
378882
|
-
}
|
|
378883
|
-
/** Total stored spans. */
|
|
378884
|
-
size() {
|
|
378885
|
-
return this.totalSpans;
|
|
378886
|
-
}
|
|
378887
|
-
clear() {
|
|
378888
|
-
this.spans.clear();
|
|
378889
|
-
this.order.length = 0;
|
|
378890
|
-
this.totalSpans = 0;
|
|
378891
|
-
}
|
|
378892
|
-
};
|
|
379503
|
+
// packages/backend/src/services/observability.ts
|
|
379504
|
+
init_spanLedger();
|
|
378893
379505
|
|
|
378894
379506
|
// packages/backend/src/services/dem/rumLedger.ts
|
|
378895
|
-
var
|
|
379507
|
+
var import_crypto16 = require("crypto");
|
|
378896
379508
|
var DEFAULT_LIMIT5 = 5e4;
|
|
378897
379509
|
function percentile3(sorted, p) {
|
|
378898
379510
|
if (sorted.length === 0) return void 0;
|
|
@@ -378910,7 +379522,7 @@ var RumLedger = class {
|
|
|
378910
379522
|
ingest(session) {
|
|
378911
379523
|
const s = {
|
|
378912
379524
|
...session,
|
|
378913
|
-
id: session.id ?? `rum-${(0,
|
|
379525
|
+
id: session.id ?? `rum-${(0, import_crypto16.randomUUID)().slice(0, 12)}`,
|
|
378914
379526
|
at: session.at ?? this.now()
|
|
378915
379527
|
};
|
|
378916
379528
|
this.sessions.push(s);
|
|
@@ -378988,116 +379600,9 @@ var RumLedger = class {
|
|
|
378988
379600
|
}
|
|
378989
379601
|
};
|
|
378990
379602
|
|
|
378991
|
-
// packages/backend/src/services/
|
|
378992
|
-
|
|
378993
|
-
|
|
378994
|
-
const notReady = pods.filter((p) => !p.ready).length;
|
|
378995
|
-
const crashLoop = pods.filter((p) => p.restarts >= 5 || p.phase === "Unknown" && p.restarts > 0).length;
|
|
378996
|
-
const totalRestarts = pods.reduce((s, p) => s + p.restarts, 0);
|
|
378997
|
-
const nodesReady = nodes.filter((n2) => n2.ready).length;
|
|
378998
|
-
let cpuPct;
|
|
378999
|
-
let memPct;
|
|
379000
|
-
const withCpu = pods.filter((p) => typeof p.cpuMillicores === "number" && typeof p.cpuLimitMillicores === "number" && p.cpuLimitMillicores > 0);
|
|
379001
|
-
if (withCpu.length > 0) {
|
|
379002
|
-
const used = withCpu.reduce((s, p) => s + (p.cpuMillicores ?? 0), 0);
|
|
379003
|
-
const limit2 = withCpu.reduce((s, p) => s + (p.cpuLimitMillicores ?? 0), 0);
|
|
379004
|
-
cpuPct = limit2 > 0 ? used / limit2 * 100 : void 0;
|
|
379005
|
-
}
|
|
379006
|
-
const withMem = pods.filter((p) => typeof p.memMiB === "number" && typeof p.memLimitMiB === "number" && p.memLimitMiB > 0);
|
|
379007
|
-
if (withMem.length > 0) {
|
|
379008
|
-
const used = withMem.reduce((s, p) => s + (p.memMiB ?? 0), 0);
|
|
379009
|
-
const limit2 = withMem.reduce((s, p) => s + (p.memLimitMiB ?? 0), 0);
|
|
379010
|
-
memPct = limit2 > 0 ? used / limit2 * 100 : void 0;
|
|
379011
|
-
}
|
|
379012
|
-
return {
|
|
379013
|
-
context: context2,
|
|
379014
|
-
totalPods: pods.length,
|
|
379015
|
-
runningPods: running.length,
|
|
379016
|
-
notReadyPods: notReady,
|
|
379017
|
-
crashLoopPods: crashLoop,
|
|
379018
|
-
totalRestarts,
|
|
379019
|
-
nodesReady,
|
|
379020
|
-
nodesTotal: nodes.length,
|
|
379021
|
-
...cpuPct !== void 0 ? { cpuUsagePercentOfLimit: cpuPct } : {},
|
|
379022
|
-
...memPct !== void 0 ? { memUsagePercentOfLimit: memPct } : {}
|
|
379023
|
-
};
|
|
379024
|
-
}
|
|
379025
|
-
function podUnhealthy(p) {
|
|
379026
|
-
return !p.ready || p.phase === "Failed" || p.phase === "Unknown" || p.restarts >= 5;
|
|
379027
|
-
}
|
|
379028
|
-
var InfraMonitor = class {
|
|
379029
|
-
clusters = /* @__PURE__ */ new Map();
|
|
379030
|
-
instances = /* @__PURE__ */ new Map();
|
|
379031
|
-
constructor(_deps = {}) {
|
|
379032
|
-
}
|
|
379033
|
-
/** Record a cluster health snapshot. */
|
|
379034
|
-
recordCluster(context2, pods, nodes) {
|
|
379035
|
-
const h = clusterHealth(context2, pods, nodes);
|
|
379036
|
-
this.clusters.set(context2, h);
|
|
379037
|
-
return h;
|
|
379038
|
-
}
|
|
379039
|
-
cluster(context2) {
|
|
379040
|
-
return this.clusters.get(context2);
|
|
379041
|
-
}
|
|
379042
|
-
clusters_() {
|
|
379043
|
-
return Array.from(this.clusters.values());
|
|
379044
|
-
}
|
|
379045
|
-
/** Unhealthy pods for a cluster (for alerting). */
|
|
379046
|
-
unhealthyPods(pods) {
|
|
379047
|
-
return pods.filter(podUnhealthy);
|
|
379048
|
-
}
|
|
379049
|
-
/** Record a cloud instance state. */
|
|
379050
|
-
recordInstance(inst) {
|
|
379051
|
-
this.instances.set(inst.id, inst);
|
|
379052
|
-
}
|
|
379053
|
-
instance(id) {
|
|
379054
|
-
return this.instances.get(id);
|
|
379055
|
-
}
|
|
379056
|
-
/** Instances that are not healthy (stopped/failed). */
|
|
379057
|
-
unhealthyInstances() {
|
|
379058
|
-
return Array.from(this.instances.values()).filter((i) => i.statusOk === false || /stopped|terminated|failed/i.test(i.state));
|
|
379059
|
-
}
|
|
379060
|
-
clear() {
|
|
379061
|
-
this.clusters.clear();
|
|
379062
|
-
this.instances.clear();
|
|
379063
|
-
}
|
|
379064
|
-
};
|
|
379065
|
-
|
|
379066
|
-
// packages/backend/src/services/etw/etwService.ts
|
|
379067
|
-
var import_crypto14 = require("crypto");
|
|
379068
|
-
var now0 = () => Date.now();
|
|
379069
|
-
var EtwService = class {
|
|
379070
|
-
sessions = /* @__PURE__ */ new Map();
|
|
379071
|
-
now;
|
|
379072
|
-
constructor(deps = {}) {
|
|
379073
|
-
this.now = deps.now ?? now0;
|
|
379074
|
-
}
|
|
379075
|
-
/** Create a session descriptor (commands are built from it by buildStartCommands). */
|
|
379076
|
-
createSession(name, providers, outDir = "C:\\temp") {
|
|
379077
|
-
const clean = name.replace(/[^A-Za-z0-9_-]/g, "");
|
|
379078
|
-
const s = {
|
|
379079
|
-
id: `etw-${(0, import_crypto14.randomUUID)().slice(0, 8)}`,
|
|
379080
|
-
name: clean,
|
|
379081
|
-
providers,
|
|
379082
|
-
outFile: `${outDir}\\${clean}`,
|
|
379083
|
-
createdAt: this.now()
|
|
379084
|
-
};
|
|
379085
|
-
this.sessions.set(s.id, s);
|
|
379086
|
-
return s;
|
|
379087
|
-
}
|
|
379088
|
-
session(id) {
|
|
379089
|
-
return this.sessions.get(id);
|
|
379090
|
-
}
|
|
379091
|
-
sessions_() {
|
|
379092
|
-
return Array.from(this.sessions.values());
|
|
379093
|
-
}
|
|
379094
|
-
removeSession(id) {
|
|
379095
|
-
return this.sessions.delete(id);
|
|
379096
|
-
}
|
|
379097
|
-
clear() {
|
|
379098
|
-
this.sessions.clear();
|
|
379099
|
-
}
|
|
379100
|
-
};
|
|
379603
|
+
// packages/backend/src/services/observability.ts
|
|
379604
|
+
init_infraMonitor();
|
|
379605
|
+
init_etwService();
|
|
379101
379606
|
|
|
379102
379607
|
// packages/backend/src/services/dashboard/dashboardService.ts
|
|
379103
379608
|
var DEFAULT_LIMIT6 = 10;
|
|
@@ -381916,7 +382421,7 @@ var safeLoadAll = renamed("safeLoadAll", "loadAll");
|
|
|
381916
382421
|
var safeDump = renamed("safeDump", "dump");
|
|
381917
382422
|
|
|
381918
382423
|
// packages/backend/src/services/dagu/daguParser.ts
|
|
381919
|
-
var
|
|
382424
|
+
var import_crypto17 = require("crypto");
|
|
381920
382425
|
init_dagScheduler();
|
|
381921
382426
|
function stepId(step, index2) {
|
|
381922
382427
|
return (step.id ?? step.name ?? `step-${index2 + 1}`).toString().replace(/[^A-Za-z0-9_-]/g, "-");
|
|
@@ -381979,7 +382484,7 @@ function parseDaguWorkflow(doc, opts = {}) {
|
|
|
381979
382484
|
return { name, ...d !== "" ? { defaultValue: d } : {} };
|
|
381980
382485
|
}) : void 0;
|
|
381981
382486
|
const playbook = {
|
|
381982
|
-
id: `dagu-${(0,
|
|
382487
|
+
id: `dagu-${(0, import_crypto17.randomUUID)().slice(0, 8)}`,
|
|
381983
382488
|
name: opts.name ?? doc.name ?? "dagu workflow",
|
|
381984
382489
|
steps,
|
|
381985
382490
|
...doc.description || opts.description ? { description: opts.description ?? doc.description } : {},
|
|
@@ -382008,7 +382513,7 @@ function daguExecutionPlan(playbook) {
|
|
|
382008
382513
|
// packages/backend/src/services/plugin/pluginRegistry.ts
|
|
382009
382514
|
var import_node_path26 = __toESM(require("node:path"), 1);
|
|
382010
382515
|
var import_node_fs11 = require("node:fs");
|
|
382011
|
-
var
|
|
382516
|
+
var import_crypto18 = require("crypto");
|
|
382012
382517
|
var DEFAULT_ENTRY_CANDIDATES = ["index.js", "index.ts", "index.mjs"];
|
|
382013
382518
|
var PluginRegistry = class {
|
|
382014
382519
|
constructor(opts) {
|
|
@@ -382075,7 +382580,7 @@ var PluginRegistry = class {
|
|
|
382075
382580
|
this.plugins.delete(existing.id);
|
|
382076
382581
|
}
|
|
382077
382582
|
const record2 = {
|
|
382078
|
-
id: `plugin-${(0,
|
|
382583
|
+
id: `plugin-${(0, import_crypto18.randomUUID)().slice(0, 8)}`,
|
|
382079
382584
|
dir,
|
|
382080
382585
|
manifest,
|
|
382081
382586
|
enabled: true,
|
|
@@ -382170,7 +382675,7 @@ var PluginRegistry = class {
|
|
|
382170
382675
|
};
|
|
382171
382676
|
|
|
382172
382677
|
// packages/backend/src/services/evals/evalHarness.ts
|
|
382173
|
-
var
|
|
382678
|
+
var import_crypto19 = require("crypto");
|
|
382174
382679
|
function subset(needles, haystack) {
|
|
382175
382680
|
return needles.every((n2) => haystack.includes(n2));
|
|
382176
382681
|
}
|
|
@@ -382233,7 +382738,7 @@ var EvalHarness = class {
|
|
|
382233
382738
|
return arr3.length > 0 ? arr3.filter((r) => r.pass).length / arr3.length * 100 : void 0;
|
|
382234
382739
|
};
|
|
382235
382740
|
return {
|
|
382236
|
-
id: `eval-${(0,
|
|
382741
|
+
id: `eval-${(0, import_crypto19.randomUUID)().slice(0, 8)}`,
|
|
382237
382742
|
at: this.now(),
|
|
382238
382743
|
total: results.length,
|
|
382239
382744
|
passed,
|
|
@@ -382516,7 +383021,7 @@ var BehaviorLedger = class {
|
|
|
382516
383021
|
};
|
|
382517
383022
|
|
|
382518
383023
|
// packages/backend/src/services/aperf/aperfService.ts
|
|
382519
|
-
var
|
|
383024
|
+
var import_crypto20 = require("crypto");
|
|
382520
383025
|
var DEFAULT_HOST_DIR = "/tmp/aperf";
|
|
382521
383026
|
var DEFAULT_INTERVAL = 1;
|
|
382522
383027
|
var DEFAULT_PERIOD = 60;
|
|
@@ -382615,7 +383120,7 @@ var AperfService = class {
|
|
|
382615
383120
|
now;
|
|
382616
383121
|
/** Full deep-dive: install aperf if needed, record, report, parse, return. */
|
|
382617
383122
|
async deepDive(host, opts = {}) {
|
|
382618
|
-
const runName = `rterm-${(0,
|
|
383123
|
+
const runName = `rterm-${(0, import_crypto20.randomUUID)().slice(0, 8)}`;
|
|
382619
383124
|
const plan = {
|
|
382620
383125
|
runName,
|
|
382621
383126
|
intervalSec: opts.intervalSec ?? DEFAULT_INTERVAL,
|
|
@@ -382658,18 +383163,18 @@ function aperfSummaryToMetricPoint(result) {
|
|
|
382658
383163
|
}
|
|
382659
383164
|
|
|
382660
383165
|
// packages/backend/src/services/audit/auditLedger.ts
|
|
382661
|
-
var
|
|
383166
|
+
var import_crypto21 = require("crypto");
|
|
382662
383167
|
var GENESIS_HASH = "0".repeat(64);
|
|
382663
383168
|
function computeRecordHash(kind, actor, target, summary, detail, at, seq2) {
|
|
382664
383169
|
const payload = JSON.stringify({ kind, actor, target, summary, detail, at, seq: seq2 });
|
|
382665
|
-
return (0,
|
|
383170
|
+
return (0, import_crypto21.createHash)("sha256").update(payload).digest("hex");
|
|
382666
383171
|
}
|
|
382667
383172
|
var AuditLedger = class _AuditLedger {
|
|
382668
383173
|
records = [];
|
|
382669
383174
|
hashFn;
|
|
382670
383175
|
now;
|
|
382671
383176
|
constructor(deps = {}) {
|
|
382672
|
-
this.hashFn = deps.hashFn ?? ((data) => (0,
|
|
383177
|
+
this.hashFn = deps.hashFn ?? ((data) => (0, import_crypto21.createHash)("sha256").update(data).digest("hex"));
|
|
382673
383178
|
this.now = deps.now ?? (() => Date.now());
|
|
382674
383179
|
}
|
|
382675
383180
|
/** Append an event to the audit ledger. Returns the record with hash + chain. */
|
|
@@ -382686,9 +383191,9 @@ var AuditLedger = class _AuditLedger {
|
|
|
382686
383191
|
at,
|
|
382687
383192
|
seq2
|
|
382688
383193
|
);
|
|
382689
|
-
const hash2 = (0,
|
|
383194
|
+
const hash2 = (0, import_crypto21.createHash)("sha256").update(contentHash + prevHash).digest("hex");
|
|
382690
383195
|
const record2 = {
|
|
382691
|
-
id: `audit-${(0,
|
|
383196
|
+
id: `audit-${(0, import_crypto21.randomUUID)().slice(0, 12)}`,
|
|
382692
383197
|
kind: event.kind,
|
|
382693
383198
|
actor: event.actor,
|
|
382694
383199
|
target: event.target,
|
|
@@ -382739,7 +383244,7 @@ var AuditLedger = class _AuditLedger {
|
|
|
382739
383244
|
record2.at,
|
|
382740
383245
|
record2.seq
|
|
382741
383246
|
);
|
|
382742
|
-
const expectedHash = (0,
|
|
383247
|
+
const expectedHash = (0, import_crypto21.createHash)("sha256").update(expectedContentHash + record2.prevHash).digest("hex");
|
|
382743
383248
|
if (record2.hash !== expectedHash) {
|
|
382744
383249
|
return { valid: false, brokenAt: record2.seq, detail: `hash mismatch at seq ${record2.seq}` };
|
|
382745
383250
|
}
|
|
@@ -382786,7 +383291,7 @@ var AuditLedger = class _AuditLedger {
|
|
|
382786
383291
|
};
|
|
382787
383292
|
|
|
382788
383293
|
// packages/backend/src/services/audit/evidenceSealer.ts
|
|
382789
|
-
var
|
|
383294
|
+
var import_crypto22 = require("crypto");
|
|
382790
383295
|
function computeMerkleRoot(hashes) {
|
|
382791
383296
|
if (hashes.length === 0) return "0".repeat(64);
|
|
382792
383297
|
if (hashes.length === 1) return hashes[0];
|
|
@@ -382794,7 +383299,7 @@ function computeMerkleRoot(hashes) {
|
|
|
382794
383299
|
for (let i = 0; i < hashes.length; i += 2) {
|
|
382795
383300
|
const left = hashes[i];
|
|
382796
383301
|
const right = i + 1 < hashes.length ? hashes[i + 1] : left;
|
|
382797
|
-
nextLevel.push((0,
|
|
383302
|
+
nextLevel.push((0, import_crypto22.createHash)("sha256").update(left + right).digest("hex"));
|
|
382798
383303
|
}
|
|
382799
383304
|
return computeMerkleRoot(nextLevel);
|
|
382800
383305
|
}
|
|
@@ -383275,17 +383780,17 @@ var OtelExporter = class {
|
|
|
383275
383780
|
};
|
|
383276
383781
|
|
|
383277
383782
|
// packages/backend/src/services/secrets/secretsVault.ts
|
|
383278
|
-
var
|
|
383783
|
+
var import_crypto23 = require("crypto");
|
|
383279
383784
|
var KEY_RE = /^[a-zA-Z0-9][a-zA-Z0-9._/-]{0,127}$/;
|
|
383280
383785
|
var NONCE_LEN = 12;
|
|
383281
383786
|
function deriveKey(masterKey, salt) {
|
|
383282
|
-
return (0,
|
|
383787
|
+
return (0, import_crypto23.scryptSync)(masterKey, salt, 32);
|
|
383283
383788
|
}
|
|
383284
383789
|
function defaultSalt(masterKey) {
|
|
383285
|
-
return (0,
|
|
383790
|
+
return (0, import_crypto23.createHash)("sha256").update(Buffer.concat([Buffer.from("rterm-secrets-v1"), Buffer.from(masterKey)])).digest().subarray(0, 16);
|
|
383286
383791
|
}
|
|
383287
383792
|
function encryptSecret(plaintext, key, nonce) {
|
|
383288
|
-
const cipher = (0,
|
|
383793
|
+
const cipher = (0, import_crypto23.createCipheriv)("aes-256-gcm", key, nonce);
|
|
383289
383794
|
const ct = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
383290
383795
|
const tag = cipher.getAuthTag();
|
|
383291
383796
|
return Buffer.concat([nonce, tag, ct]).toString("base64");
|
|
@@ -383296,7 +383801,7 @@ function decryptSecret(blob, key) {
|
|
|
383296
383801
|
const nonce = buf.subarray(0, NONCE_LEN);
|
|
383297
383802
|
const tag = buf.subarray(NONCE_LEN, NONCE_LEN + 16);
|
|
383298
383803
|
const ct = buf.subarray(NONCE_LEN + 16);
|
|
383299
|
-
const decipher = (0,
|
|
383804
|
+
const decipher = (0, import_crypto23.createDecipheriv)("aes-256-gcm", key, nonce);
|
|
383300
383805
|
decipher.setAuthTag(tag);
|
|
383301
383806
|
return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
|
|
383302
383807
|
}
|
|
@@ -383308,7 +383813,7 @@ var SecretsVault = class {
|
|
|
383308
383813
|
onAudit;
|
|
383309
383814
|
constructor(opts = {}) {
|
|
383310
383815
|
this.now = opts.now ?? Date.now;
|
|
383311
|
-
this.rand = opts.randomBytes ??
|
|
383816
|
+
this.rand = opts.randomBytes ?? import_crypto23.randomBytes;
|
|
383312
383817
|
this.onAudit = opts.onAudit;
|
|
383313
383818
|
if (opts.masterKey !== void 0) {
|
|
383314
383819
|
const salt = opts.salt ?? defaultSalt(opts.masterKey);
|
|
@@ -383424,7 +383929,7 @@ var SecretsVault = class {
|
|
|
383424
383929
|
};
|
|
383425
383930
|
|
|
383426
383931
|
// packages/backend/src/services/oncall/escalationService.ts
|
|
383427
|
-
var
|
|
383932
|
+
var import_crypto24 = require("crypto");
|
|
383428
383933
|
var EscalationService = class {
|
|
383429
383934
|
policies = /* @__PURE__ */ new Map();
|
|
383430
383935
|
pages = /* @__PURE__ */ new Map();
|
|
@@ -383464,7 +383969,7 @@ var EscalationService = class {
|
|
|
383464
383969
|
if (!policy) throw new Error(`unknown escalation policy: ${input.policyId}`);
|
|
383465
383970
|
const at = this.now();
|
|
383466
383971
|
const page = {
|
|
383467
|
-
id: (0,
|
|
383972
|
+
id: (0, import_crypto24.randomUUID)(),
|
|
383468
383973
|
incidentId: input.incidentId,
|
|
383469
383974
|
policyId: input.policyId,
|
|
383470
383975
|
levelIndex: 0,
|
|
@@ -383678,7 +384183,7 @@ var CostBudgetService = class {
|
|
|
383678
384183
|
};
|
|
383679
384184
|
|
|
383680
384185
|
// packages/backend/src/services/recording/sessionRecorder.ts
|
|
383681
|
-
var
|
|
384186
|
+
var import_crypto25 = require("crypto");
|
|
383682
384187
|
function toAsciinema(rec) {
|
|
383683
384188
|
const header = {
|
|
383684
384189
|
version: 2,
|
|
@@ -383707,7 +384212,7 @@ var SessionRecorder = class {
|
|
|
383707
384212
|
}
|
|
383708
384213
|
/** Start recording a terminal. Returns the recording id. */
|
|
383709
384214
|
start(terminalId, opts = {}) {
|
|
383710
|
-
const id = (0,
|
|
384215
|
+
const id = (0, import_crypto25.randomUUID)();
|
|
383711
384216
|
this.recordings.set(id, {
|
|
383712
384217
|
id,
|
|
383713
384218
|
terminalId,
|
|
@@ -383772,7 +384277,7 @@ var SessionRecorder = class {
|
|
|
383772
384277
|
};
|
|
383773
384278
|
|
|
383774
384279
|
// packages/backend/src/services/gitops/gitOpsService.ts
|
|
383775
|
-
var
|
|
384280
|
+
var import_crypto26 = require("crypto");
|
|
383776
384281
|
function stableStringify(v) {
|
|
383777
384282
|
if (v === null || typeof v !== "object") return JSON.stringify(v);
|
|
383778
384283
|
if (Array.isArray(v)) return `[${v.map(stableStringify).join(",")}]`;
|
|
@@ -383780,11 +384285,11 @@ function stableStringify(v) {
|
|
|
383780
384285
|
return `{${Object.keys(o).sort().map((k) => `${JSON.stringify(k)}:${stableStringify(o[k])}`).join(",")}}`;
|
|
383781
384286
|
}
|
|
383782
384287
|
function specHash(spec) {
|
|
383783
|
-
return (0,
|
|
384288
|
+
return (0, import_crypto26.createHash)("sha256").update(stableStringify(spec)).digest("hex").slice(0, 12);
|
|
383784
384289
|
}
|
|
383785
384290
|
function buildManifest(entities) {
|
|
383786
384291
|
const sorted = [...entities].sort((a, b) => a.id.localeCompare(b.id));
|
|
383787
|
-
const stateHash = (0,
|
|
384292
|
+
const stateHash = (0, import_crypto26.createHash)("sha256").update(sorted.map((e) => `${e.id}:${specHash(e.spec)}`).join("\n")).digest("hex");
|
|
383788
384293
|
return { version: 1, stateHash, entities: sorted };
|
|
383789
384294
|
}
|
|
383790
384295
|
function specDiff(repo, live) {
|
|
@@ -383877,9 +384382,9 @@ var GitOpsService = class {
|
|
|
383877
384382
|
};
|
|
383878
384383
|
|
|
383879
384384
|
// packages/backend/src/services/automation/playbookVersioning.ts
|
|
383880
|
-
var
|
|
384385
|
+
var import_crypto27 = require("crypto");
|
|
383881
384386
|
function hashDef(def) {
|
|
383882
|
-
return (0,
|
|
384387
|
+
return (0, import_crypto27.createHash)("sha256").update(JSON.stringify(def)).digest("hex").slice(0, 16);
|
|
383883
384388
|
}
|
|
383884
384389
|
function lintPlaybook(def) {
|
|
383885
384390
|
const issues = [];
|
|
@@ -384070,7 +384575,7 @@ function diffText(aText, bText, aLabel = "a", bLabel = "b") {
|
|
|
384070
384575
|
}
|
|
384071
384576
|
|
|
384072
384577
|
// packages/backend/src/services/cloud/cloudInventory.ts
|
|
384073
|
-
var
|
|
384578
|
+
var import_crypto28 = require("crypto");
|
|
384074
384579
|
function parseAwsInstances(payload, accountId = "") {
|
|
384075
384580
|
const out = [];
|
|
384076
384581
|
const reservations = payload?.Reservations ?? [];
|
|
@@ -384083,7 +384588,7 @@ function parseAwsInstances(payload, accountId = "") {
|
|
|
384083
384588
|
if (t?.Key) tags[t.Key] = t.Value ?? "";
|
|
384084
384589
|
}
|
|
384085
384590
|
out.push({
|
|
384086
|
-
id: `aws:${accountId}:${String(i.InstanceId ?? (0,
|
|
384591
|
+
id: `aws:${accountId}:${String(i.InstanceId ?? (0, import_crypto28.randomUUID)())}`,
|
|
384087
384592
|
provider: "aws",
|
|
384088
384593
|
kind: "instance",
|
|
384089
384594
|
name: tags["Name"] ?? String(i.InstanceId ?? ""),
|
|
@@ -384115,7 +384620,7 @@ function parseGcpInstances(payload, accountId = "") {
|
|
|
384115
384620
|
const accessCfgs = nics[0]?.accessConfigs ?? [];
|
|
384116
384621
|
const publicIp = accessCfgs[0]?.natIP;
|
|
384117
384622
|
out.push({
|
|
384118
|
-
id: `gcp:${accountId}:${String(i.id ?? i.name ?? (0,
|
|
384623
|
+
id: `gcp:${accountId}:${String(i.id ?? i.name ?? (0, import_crypto28.randomUUID)())}`,
|
|
384119
384624
|
provider: "gcp",
|
|
384120
384625
|
kind: "instance",
|
|
384121
384626
|
name: String(i.name ?? ""),
|
|
@@ -384137,7 +384642,7 @@ function parseAzureVms(payload, accountId = "") {
|
|
|
384137
384642
|
const v = vm;
|
|
384138
384643
|
const props = v.properties ?? {};
|
|
384139
384644
|
out.push({
|
|
384140
|
-
id: `azure:${accountId}:${String(v.id ?? v.name ?? (0,
|
|
384645
|
+
id: `azure:${accountId}:${String(v.id ?? v.name ?? (0, import_crypto28.randomUUID)())}`,
|
|
384141
384646
|
provider: "azure",
|
|
384142
384647
|
kind: "vm",
|
|
384143
384648
|
name: String(v.name ?? ""),
|
|
@@ -384760,6 +385265,69 @@ function createObservabilityBridge(deps) {
|
|
|
384760
385265
|
requireObs(deps).cloud.addAccount(params);
|
|
384761
385266
|
return { ok: true };
|
|
384762
385267
|
},
|
|
385268
|
+
// ── APM (OTLP span ingestion) ───────────────────────────────────────────
|
|
385269
|
+
apmIngestSpans: async (params) => {
|
|
385270
|
+
const { ingestOtlp: ingestOtlp2 } = await Promise.resolve().then(() => (init_spanLedger(), spanLedger_exports));
|
|
385271
|
+
const count = ingestOtlp2(requireObs(deps).spanLedger, params.payload, params.defaultService);
|
|
385272
|
+
return { ingested: count };
|
|
385273
|
+
},
|
|
385274
|
+
apmSummary: async () => ({
|
|
385275
|
+
spans: requireObs(deps).spanLedger.size(),
|
|
385276
|
+
traces: requireObs(deps).spanLedger.traceIds().length,
|
|
385277
|
+
byService: requireObs(deps).spanLedger.serviceStats()
|
|
385278
|
+
}),
|
|
385279
|
+
// ── DEM (RUM beacon ingestion) ──────────────────────────────────────────
|
|
385280
|
+
demIngestBeacon: async (params) => {
|
|
385281
|
+
const s = requireObs(deps).rumLedger.ingestBeacon(params.payload);
|
|
385282
|
+
return { ingested: s !== void 0, id: s?.id };
|
|
385283
|
+
},
|
|
385284
|
+
demSummary: async () => ({
|
|
385285
|
+
sessions: requireObs(deps).rumLedger.size(),
|
|
385286
|
+
byPage: requireObs(deps).rumLedger.pageStats()
|
|
385287
|
+
}),
|
|
385288
|
+
// ── Infra (k8s collect) ─────────────────────────────────────────────────
|
|
385289
|
+
infraCollect: async (params) => {
|
|
385290
|
+
const { parseKubectlPods: parseKubectlPods2 } = await Promise.resolve().then(() => (init_infraMonitor(), infraMonitor_exports));
|
|
385291
|
+
const context2 = params.context ?? "default";
|
|
385292
|
+
let podsPayload = params.kubectlJson;
|
|
385293
|
+
if (podsPayload === void 0) {
|
|
385294
|
+
if (!params.execKubectl) throw new Error("infraCollect needs kubectlJson or an injected execKubectl");
|
|
385295
|
+
podsPayload = await params.execKubectl();
|
|
385296
|
+
}
|
|
385297
|
+
const text = typeof podsPayload === "string" ? podsPayload : JSON.stringify(podsPayload);
|
|
385298
|
+
let pods = parseKubectlPods2(text);
|
|
385299
|
+
if (pods.length === 0 && typeof podsPayload === "object" && podsPayload !== null) {
|
|
385300
|
+
const items = podsPayload.items ?? [];
|
|
385301
|
+
const table = ["NAMESPACE NAME READY STATUS RESTARTS AGE", ...items.map((it) => {
|
|
385302
|
+
const ns = it.metadata?.namespace ?? "default";
|
|
385303
|
+
const name = it.metadata?.name ?? "pod";
|
|
385304
|
+
const cs = it.status?.containerStatuses ?? [];
|
|
385305
|
+
const ready = `${cs.filter((c) => c.ready).length}/${cs.length || 1}`;
|
|
385306
|
+
const status = it.status?.phase ?? "Unknown";
|
|
385307
|
+
const restarts = String(cs.reduce((s, c) => s + (c.restartCount ?? 0), 0));
|
|
385308
|
+
return `${ns} ${name} ${ready} ${status} ${restarts} 1d`;
|
|
385309
|
+
})].join("\n");
|
|
385310
|
+
pods = parseKubectlPods2(table);
|
|
385311
|
+
}
|
|
385312
|
+
const health = requireObs(deps).infraMonitor.recordCluster(context2, pods, []);
|
|
385313
|
+
return { context: context2, pods: pods.length, notReady: health.notReadyPods, crashLoop: health.crashLoopPods };
|
|
385314
|
+
},
|
|
385315
|
+
infraClusters: async () => requireObs(deps).infraMonitor.clusters_(),
|
|
385316
|
+
infraUnhealthy: async () => requireObs(deps).infraMonitor.unhealthyInstances(),
|
|
385317
|
+
// ── ETW (Windows trace) ─────────────────────────────────────────────────
|
|
385318
|
+
etwStartTrace: async (params) => requireObs(deps).etwService.createSession(params.name, params.providers, params.outDir),
|
|
385319
|
+
etwStopTrace: async (params) => {
|
|
385320
|
+
const s = requireObs(deps).etwService.session(params.sessionId);
|
|
385321
|
+
if (!s) throw new Error(`etw session not found: ${params.sessionId}`);
|
|
385322
|
+
const { buildStopCommands: buildStopCommands2 } = await Promise.resolve().then(() => (init_etwService(), etwService_exports));
|
|
385323
|
+
return { commands: buildStopCommands2(s) };
|
|
385324
|
+
},
|
|
385325
|
+
etwParse: async (params) => {
|
|
385326
|
+
const { parseWinEventJson: parseWinEventJson2, parseWinEventText: parseWinEventText2, parseCounterJson: parseCounterJson2 } = await Promise.resolve().then(() => (init_etwService(), etwService_exports));
|
|
385327
|
+
if (params.format === "counter") return { counters: parseCounterJson2(params.output) };
|
|
385328
|
+
return { events: parseWinEventJson2(params.output) ?? parseWinEventText2(params.output) };
|
|
385329
|
+
},
|
|
385330
|
+
etwSessions: async () => requireObs(deps).etwService.sessions_(),
|
|
384763
385331
|
// ── live dashboard hub ──────────────────────────────────────────────────
|
|
384764
385332
|
liveDashboardState: async () => requireObs(deps).liveDashboard.lastState() ?? await requireObs(deps).dashboard.state(),
|
|
384765
385333
|
liveDashboardSubscriberCount: async () => ({ count: requireObs(deps).liveDashboard.subscriberCount() }),
|