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 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: createHash6 } = require("crypto");
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 = createHash6("sha1").update(key + GUID).digest("base64");
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: createHash6 } = require("crypto");
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 = createHash6("sha1").update(key + GUID).digest("base64");
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 import_crypto7 = require("crypto");
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, import_crypto7.randomUUID)().slice(0, 8)}`,
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, import_crypto7.randomUUID)().slice(0, 8)}`,
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 DEFAULT_LIMIT = 1e4;
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 ?? DEFAULT_LIMIT;
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 percentile(sorted, p) {
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 = percentile(samples, 50);
378075
- r.latencyP95Ms = percentile(samples, 95);
378076
- r.latencyP99Ms = percentile(samples, 99);
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 import_crypto8 = require("crypto");
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, import_crypto8.randomUUID)().slice(0, 8)}`,
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 import_crypto9 = require("crypto");
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, import_crypto9.randomUUID)().slice(0, 8)}`,
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 import_crypto10 = require("crypto");
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, import_crypto10.randomUUID)().slice(0, 8)}`, matcher, until: untilMs, ...opts };
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 import_crypto11 = require("crypto");
378432
- var DEFAULT_LIMIT2 = 500;
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 ?? DEFAULT_LIMIT2;
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, import_crypto11.randomUUID)().slice(0, 8)}`,
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 DEFAULT_LIMIT3 = 1e3;
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 ?? DEFAULT_LIMIT3;
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 import_crypto12 = require("crypto");
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, import_crypto12.randomUUID)().slice(0, 8)}` };
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/apm/spanLedger.ts
378773
- var DEFAULT_LIMIT4 = 5e4;
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 import_crypto13 = require("crypto");
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, import_crypto13.randomUUID)().slice(0, 12)}`,
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/infra/infraMonitor.ts
378992
- function clusterHealth(context2, pods, nodes) {
378993
- const running = pods.filter((p) => p.phase === "Running");
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 import_crypto15 = require("crypto");
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, import_crypto15.randomUUID)().slice(0, 8)}`,
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 import_crypto16 = require("crypto");
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, import_crypto16.randomUUID)().slice(0, 8)}`,
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 import_crypto17 = require("crypto");
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, import_crypto17.randomUUID)().slice(0, 8)}`,
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 import_crypto18 = require("crypto");
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, import_crypto18.randomUUID)().slice(0, 8)}`;
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 import_crypto19 = require("crypto");
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, import_crypto19.createHash)("sha256").update(payload).digest("hex");
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, import_crypto19.createHash)("sha256").update(data).digest("hex"));
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, import_crypto19.createHash)("sha256").update(contentHash + prevHash).digest("hex");
383194
+ const hash2 = (0, import_crypto21.createHash)("sha256").update(contentHash + prevHash).digest("hex");
382690
383195
  const record2 = {
382691
- id: `audit-${(0, import_crypto19.randomUUID)().slice(0, 12)}`,
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, import_crypto19.createHash)("sha256").update(expectedContentHash + record2.prevHash).digest("hex");
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 import_crypto20 = require("crypto");
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, import_crypto20.createHash)("sha256").update(left + right).digest("hex"));
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 import_crypto21 = require("crypto");
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, import_crypto21.scryptSync)(masterKey, salt, 32);
383787
+ return (0, import_crypto23.scryptSync)(masterKey, salt, 32);
383283
383788
  }
383284
383789
  function defaultSalt(masterKey) {
383285
- return (0, import_crypto21.createHash)("sha256").update(Buffer.concat([Buffer.from("rterm-secrets-v1"), Buffer.from(masterKey)])).digest().subarray(0, 16);
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, import_crypto21.createCipheriv)("aes-256-gcm", key, nonce);
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, import_crypto21.createDecipheriv)("aes-256-gcm", key, nonce);
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 ?? import_crypto21.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 import_crypto22 = require("crypto");
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, import_crypto22.randomUUID)(),
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 import_crypto23 = require("crypto");
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, import_crypto23.randomUUID)();
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 import_crypto24 = require("crypto");
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, import_crypto24.createHash)("sha256").update(stableStringify(spec)).digest("hex").slice(0, 12);
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, import_crypto24.createHash)("sha256").update(sorted.map((e) => `${e.id}:${specHash(e.spec)}`).join("\n")).digest("hex");
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 import_crypto25 = require("crypto");
384385
+ var import_crypto27 = require("crypto");
383881
384386
  function hashDef(def) {
383882
- return (0, import_crypto25.createHash)("sha256").update(JSON.stringify(def)).digest("hex").slice(0, 16);
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 import_crypto26 = require("crypto");
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, import_crypto26.randomUUID)())}`,
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, import_crypto26.randomUUID)())}`,
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, import_crypto26.randomUUID)())}`,
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() }),