@camstack/addon-pipeline 1.2.37 → 1.2.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/audio-analyzer/index.js +1 -1
  2. package/dist/audio-analyzer/index.mjs +1 -1
  3. package/dist/detection-pipeline/index.js +145 -175
  4. package/dist/detection-pipeline/index.mjs +120 -150
  5. package/dist/{dist-BvFLZyhW.js → dist-BtAvtroH.js} +260 -108
  6. package/dist/{dist-Du7_SNiR.mjs → dist-COgGdFMv.mjs} +260 -108
  7. package/dist/{step-definitions-C8tk9fPJ.mjs → event-loop-stall-monitor-naFYvcOO.mjs} +139 -2
  8. package/dist/{step-definitions-i8O-hxyI.js → event-loop-stall-monitor-shfwi1_b.js} +150 -1
  9. package/dist/lazy-sharp-B-mb8uWx.mjs +20 -0
  10. package/dist/lazy-sharp-CcYuXtsa.js +25 -0
  11. package/dist/motion-wasm/index.js +3 -3
  12. package/dist/motion-wasm/index.mjs +3 -3
  13. package/dist/pipeline-runner/index.js +3316 -2428
  14. package/dist/pipeline-runner/index.mjs +3315 -2428
  15. package/dist/recorder/index.js +102 -664
  16. package/dist/recorder/index.mjs +102 -658
  17. package/dist/stream-broker/_stub.js +2 -2
  18. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C5m4hC2K.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CjrKd4xX.mjs} +3 -3
  19. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B59GNAJq.mjs +26 -0
  20. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-83qNzMSL.mjs +26 -0
  21. package/dist/stream-broker/{hostInit-WXFrgppm.mjs → hostInit-BFH17kSk.mjs} +3 -3
  22. package/dist/stream-broker/index.js +717 -211
  23. package/dist/stream-broker/index.mjs +717 -211
  24. package/dist/stream-broker/remoteEntry.js +1 -1
  25. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-Dx-Vrpyt.js → MaskShapeCanvas-DI4BY7W2-yeSHfpUy.js} +1 -1
  26. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-9D-BWwQP.js → MotionZonesSettings-NcxxQN8r-Df4WxM6N.js} +1 -1
  27. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-HvAetfA4.js → PrivacyMaskSettings-APgPLF7p-COHSiTGq.js} +1 -1
  28. package/embed-dist/assets/index-4fJzjj4H.css +2 -0
  29. package/embed-dist/assets/index-Ct9M2v5n.js +112 -0
  30. package/embed-dist/index.html +2 -2
  31. package/package.json +2 -2
  32. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-ByHi7ZAe.mjs +0 -26
  33. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CscpvIRR.mjs +0 -26
  34. package/embed-dist/assets/index-9Ob2YrIf.js +0 -343
  35. package/embed-dist/assets/index-CAe6Dg-X.css +0 -2
  36. package/python/__pycache__/inference_pool.cpython-312.pyc +0 -0
  37. package/python/__pycache__/inference_pool.cpython-313.pyc +0 -0
  38. package/python/__pycache__/inference_pool.cpython-314.pyc +0 -0
  39. package/python/__pycache__/test_inference_pool_backpressure.cpython-314.pyc +0 -0
  40. package/python/__pycache__/test_inference_pool_coreml_cache.cpython-314.pyc +0 -0
  41. package/python/__pycache__/test_inference_pool_device_selection.cpython-314.pyc +0 -0
  42. package/python/__pycache__/test_inference_pool_layout.cpython-314.pyc +0 -0
  43. package/python/__pycache__/test_inference_pool_preprocess.cpython-314.pyc +0 -0
  44. package/python/__pycache__/yamnet_audio.cpython-314.pyc +0 -0
  45. package/python/postprocessors/__pycache__/__init__.cpython-312.pyc +0 -0
  46. package/python/postprocessors/__pycache__/__init__.cpython-313.pyc +0 -0
  47. package/python/postprocessors/__pycache__/__init__.cpython-314.pyc +0 -0
  48. package/python/postprocessors/__pycache__/_safety.cpython-313.pyc +0 -0
  49. package/python/postprocessors/__pycache__/arcface.cpython-312.pyc +0 -0
  50. package/python/postprocessors/__pycache__/arcface.cpython-313.pyc +0 -0
  51. package/python/postprocessors/__pycache__/arcface.cpython-314.pyc +0 -0
  52. package/python/postprocessors/__pycache__/clip.cpython-312.pyc +0 -0
  53. package/python/postprocessors/__pycache__/clip.cpython-313.pyc +0 -0
  54. package/python/postprocessors/__pycache__/clip.cpython-314.pyc +0 -0
  55. package/python/postprocessors/__pycache__/ctc.cpython-312.pyc +0 -0
  56. package/python/postprocessors/__pycache__/ctc.cpython-313.pyc +0 -0
  57. package/python/postprocessors/__pycache__/ctc.cpython-314.pyc +0 -0
  58. package/python/postprocessors/__pycache__/saliency.cpython-312.pyc +0 -0
  59. package/python/postprocessors/__pycache__/saliency.cpython-313.pyc +0 -0
  60. package/python/postprocessors/__pycache__/saliency.cpython-314.pyc +0 -0
  61. package/python/postprocessors/__pycache__/scrfd.cpython-312.pyc +0 -0
  62. package/python/postprocessors/__pycache__/scrfd.cpython-313.pyc +0 -0
  63. package/python/postprocessors/__pycache__/scrfd.cpython-314.pyc +0 -0
  64. package/python/postprocessors/__pycache__/softmax.cpython-312.pyc +0 -0
  65. package/python/postprocessors/__pycache__/softmax.cpython-313.pyc +0 -0
  66. package/python/postprocessors/__pycache__/softmax.cpython-314.pyc +0 -0
  67. package/python/postprocessors/__pycache__/ssd.cpython-312.pyc +0 -0
  68. package/python/postprocessors/__pycache__/ssd.cpython-313.pyc +0 -0
  69. package/python/postprocessors/__pycache__/ssd.cpython-314.pyc +0 -0
  70. package/python/postprocessors/__pycache__/test_clip.cpython-312-pytest-9.1.1.pyc +0 -0
  71. package/python/postprocessors/__pycache__/test_clip.cpython-313-pytest-9.1.1.pyc +0 -0
  72. package/python/postprocessors/__pycache__/test_ctc.cpython-312-pytest-9.1.1.pyc +0 -0
  73. package/python/postprocessors/__pycache__/test_ctc.cpython-312.pyc +0 -0
  74. package/python/postprocessors/__pycache__/test_ctc.cpython-313-pytest-9.1.1.pyc +0 -0
  75. package/python/postprocessors/__pycache__/test_ctc.cpython-313.pyc +0 -0
  76. package/python/postprocessors/__pycache__/test_saliency.cpython-312-pytest-9.1.1.pyc +0 -0
  77. package/python/postprocessors/__pycache__/test_saliency.cpython-313-pytest-9.1.1.pyc +0 -0
  78. package/python/postprocessors/__pycache__/test_softmax.cpython-312-pytest-9.1.1.pyc +0 -0
  79. package/python/postprocessors/__pycache__/test_yolo_nms.cpython-312-pytest-9.1.1.pyc +0 -0
  80. package/python/postprocessors/__pycache__/test_yolo_nms.cpython-39.pyc +0 -0
  81. package/python/postprocessors/__pycache__/yamnet.cpython-312.pyc +0 -0
  82. package/python/postprocessors/__pycache__/yamnet.cpython-313.pyc +0 -0
  83. package/python/postprocessors/__pycache__/yamnet.cpython-314.pyc +0 -0
  84. package/python/postprocessors/__pycache__/yolo.cpython-312.pyc +0 -0
  85. package/python/postprocessors/__pycache__/yolo.cpython-313.pyc +0 -0
  86. package/python/postprocessors/__pycache__/yolo.cpython-314.pyc +0 -0
  87. package/python/postprocessors/__pycache__/yolo.cpython-39.pyc +0 -0
  88. package/python/postprocessors/__pycache__/yolo_seg.cpython-312.pyc +0 -0
  89. package/python/postprocessors/__pycache__/yolo_seg.cpython-313.pyc +0 -0
  90. package/python/postprocessors/__pycache__/yolo_seg.cpython-314.pyc +0 -0
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-BvFLZyhW.js");
6
+ const require_dist = require("../dist-BtAvtroH.js");
7
7
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
8
8
  const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-fsdDExML.js");
9
9
  let node_fs = require("node:fs");
@@ -1,5 +1,5 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { B as errMsg, K as hydrateSchema, O as mapAudioLabelToMacro, V as BaseAddon, _ as audioAnalysisCapability, d as HF_BASE_URL, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG, v as audioAnalyzerCapability } from "../dist-Du7_SNiR.mjs";
2
+ import { B as errMsg, K as hydrateSchema, O as mapAudioLabelToMacro, V as BaseAddon, _ as audioAnalysisCapability, d as HF_BASE_URL, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG, v as audioAnalyzerCapability } from "../dist-COgGdFMv.mjs";
3
3
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
4
4
  import { i as downloadFile } from "../model-download-service-Cp9f4dk6-CwUb5v3Y.mjs";
5
5
  import * as fs from "node:fs";
@@ -3,20 +3,20 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-BvFLZyhW.js");
7
- const require_step_definitions = require("../step-definitions-i8O-hxyI.js");
6
+ const require_dist = require("../dist-BtAvtroH.js");
7
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-shfwi1_b.js");
8
+ const require_lazy_sharp = require("../lazy-sharp-CcYuXtsa.js");
8
9
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
9
10
  const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-fsdDExML.js");
10
- let node_os = require("node:os");
11
- node_os = require_chunk.__toESM(node_os);
12
- let node_child_process = require("node:child_process");
13
11
  let sharp = require("sharp");
14
12
  sharp = require_chunk.__toESM(sharp);
13
+ let node_child_process = require("node:child_process");
14
+ let node_os = require("node:os");
15
+ node_os = require_chunk.__toESM(node_os);
15
16
  let node_fs = require("node:fs");
16
17
  node_fs = require_chunk.__toESM(node_fs);
17
18
  let node_path = require("node:path");
18
19
  node_path = require_chunk.__toESM(node_path);
19
- let node_perf_hooks = require("node:perf_hooks");
20
20
  //#region src/detection-pipeline/runtimes.ts
21
21
  var KNOWN_PLATFORMS = [
22
22
  "darwin",
@@ -313,7 +313,7 @@ function classifyAccelerator(backend, device) {
313
313
  * missing-build fallback branch is unit-testable without a live catalog —
314
314
  * mirrors `collectZeroBuildIssues`' injection seam.
315
315
  */
316
- function resolveDefaultDetectionModel(backend, device, format, getStepDef = require_step_definitions.getStepDefinition) {
316
+ function resolveDefaultDetectionModel(backend, device, format, getStepDef = require_event_loop_stall_monitor.getStepDefinition) {
317
317
  let def;
318
318
  try {
319
319
  def = getStepDef(OBJECT_DETECTION_STEP_ID$1);
@@ -325,7 +325,7 @@ function resolveDefaultDetectionModel(backend, device, format, getStepDef = requ
325
325
  const entry = def.models.find((m) => m.id === candidate);
326
326
  if (entry && entry.formats[format] !== void 0) return candidate;
327
327
  }
328
- return require_step_definitions.getDefaultModelForFormatFromDef(def, format);
328
+ return require_event_loop_stall_monitor.getDefaultModelForFormatFromDef(def, format);
329
329
  }
330
330
  //#endregion
331
331
  //#region src/detection-pipeline/engine/shared-inference-pool.ts
@@ -1875,7 +1875,7 @@ var EngineFactory = class {
1875
1875
  await this.poolManager.applyConfig(steps);
1876
1876
  }
1877
1877
  buildPoolModelConfig(stepId, modelId, poolRuntime) {
1878
- const def = require_step_definitions.getStepDefinition(stepId);
1878
+ const def = require_event_loop_stall_monitor.getStepDefinition(stepId);
1879
1879
  const modelEntry = def.models.find((m) => m.id === modelId);
1880
1880
  if (!modelEntry) throw new Error(`Model "${modelId}" not found in step "${stepId}" catalog`);
1881
1881
  const format = RUNTIME_TO_FORMAT[poolRuntime];
@@ -2246,6 +2246,89 @@ function normalizeOutput(output) {
2246
2246
  };
2247
2247
  }
2248
2248
  //#endregion
2249
+ //#region src/detection-pipeline/pipeline/drop-sampler.ts
2250
+ /**
2251
+ * drop-sampler — keep the record of a dropped detection without the flood.
2252
+ *
2253
+ * ## Why
2254
+ *
2255
+ * The full-frame phantom guard logs every detection it removes, on purpose: a
2256
+ * branch that drops work silently reads as "never happened", and this repo has
2257
+ * paid for that twice. Its own comment set the bound honestly — *"Bounded by
2258
+ * how rare full-frame phantoms are, which is the point: if this floods, that is
2259
+ * itself the finding."*
2260
+ *
2261
+ * It flooded. Camera 615 emits a persistent full-frame `vehicle` phantom
2262
+ * (score ~0.62, areaRatio 0.949) and the guard was writing **dozens of INFO
2263
+ * lines a second** on 2026-08-02. So the finding stands — that camera has a
2264
+ * standing phantom worth investigating — but the log volume is now costing more
2265
+ * than the record is worth, and it drowns everything else in the same stream.
2266
+ *
2267
+ * ## The shape
2268
+ *
2269
+ * FIRST occurrence of each `(deviceId, macroClass)` logs in full: the example
2270
+ * is what makes the finding actionable — the bbox, the score, the ratios.
2271
+ * After that the pair is counted and a SUMMARY is emitted per interval, so the
2272
+ * question "how often does this fire, and on what?" is still answerable — from
2273
+ * a counter rather than from N identical lines.
2274
+ *
2275
+ * Deliberately per `(device, class)` and not global: a phantom on one camera
2276
+ * must not mask a new one appearing on another, which a single global counter
2277
+ * would do.
2278
+ */
2279
+ /** How often an active drop pattern re-reports, with its count. */
2280
+ var DROP_SUMMARY_INTERVAL_MS = 6e4;
2281
+ /**
2282
+ * Decides, per `(deviceId, class)`, whether this drop is worth a line.
2283
+ *
2284
+ * Pure-ish and clock-injected so the interval logic is testable without
2285
+ * waiting a minute.
2286
+ */
2287
+ var DropSampler = class {
2288
+ seen = /* @__PURE__ */ new Map();
2289
+ now;
2290
+ intervalMs;
2291
+ constructor(intervalMs = DROP_SUMMARY_INTERVAL_MS, now = () => Date.now()) {
2292
+ this.intervalMs = intervalMs;
2293
+ this.now = now;
2294
+ }
2295
+ /**
2296
+ * Record one drop. Returns what to log.
2297
+ *
2298
+ * The first sighting of a pair yields the example. Afterwards the count
2299
+ * accumulates and a summary is released once per interval — carrying the
2300
+ * number suppressed, so nothing about the RATE is lost even though the lines
2301
+ * are.
2302
+ */
2303
+ record(deviceId, macroClass) {
2304
+ const key = `${deviceId}:${macroClass}`;
2305
+ const at = this.now();
2306
+ const prev = this.seen.get(key);
2307
+ if (prev === void 0) {
2308
+ this.seen.set(key, {
2309
+ count: 0,
2310
+ lastReportedAt: at
2311
+ });
2312
+ return {
2313
+ logExample: true,
2314
+ summaryCount: null
2315
+ };
2316
+ }
2317
+ prev.count += 1;
2318
+ if (at - prev.lastReportedAt < this.intervalMs) return {
2319
+ logExample: false,
2320
+ summaryCount: null
2321
+ };
2322
+ const n = prev.count;
2323
+ prev.count = 0;
2324
+ prev.lastReportedAt = at;
2325
+ return {
2326
+ logExample: false,
2327
+ summaryCount: n
2328
+ };
2329
+ }
2330
+ };
2331
+ //#endregion
2249
2332
  //#region src/detection-pipeline/pipeline/execution-trace.ts
2250
2333
  var traceCounter = 0;
2251
2334
  var ExecutionTraceBuilder = class {
@@ -3302,6 +3385,10 @@ function buildFrameResult(input) {
3302
3385
  height: input.height,
3303
3386
  detections,
3304
3387
  ...input.discarded !== void 0 && input.discarded.length > 0 ? { discarded: input.discarded } : {},
3388
+ ...input.shed !== void 0 ? {
3389
+ shed: true,
3390
+ shedReason: input.shed.reason
3391
+ } : {},
3305
3392
  debug: frameDebug
3306
3393
  };
3307
3394
  }
@@ -3424,6 +3511,9 @@ function reprojectCropZoneDetections(output, cropOrigin) {
3424
3511
  }
3425
3512
  var PipelineExecutor = class {
3426
3513
  opts;
3514
+ /** Bounds the full-frame-guard drop log: first example per (device,
3515
+ * class), then a counted summary per minute. See `drop-sampler.ts`. */
3516
+ dropSampler = new DropSampler();
3427
3517
  constructor(opts) {
3428
3518
  this.opts = opts;
3429
3519
  }
@@ -3495,11 +3585,15 @@ var PipelineExecutor = class {
3495
3585
  details
3496
3586
  };
3497
3587
  let discarded;
3588
+ const rootShed = {
3589
+ count: 0,
3590
+ reasons: []
3591
+ };
3498
3592
  for (const rootStep of tree.roots) {
3499
3593
  if (debug) console.log(`[executor] rootStep=${rootStep.stepId} settings=${JSON.stringify(rootStep.settings ?? {})}`);
3500
3594
  const cropPrep = rootStep.definition.extractMode === "crop-zone" && cropZoneBbox !== void 0 ? await this.prepareCropZoneInput(cropZoneBbox, fullFrameJpegProvider, imageWidth, imageHeight, deviceId) : null;
3501
3595
  const rootStart = Date.now();
3502
- const rawRootOutput = await this.executeStep(rootStep, cropPrep?.input ?? rootInput, cropPrep?.width ?? imageWidth, cropPrep?.height ?? imageHeight, "full-frame", void 0, void 0, traceBuilder, stepTimings, poolAgg);
3596
+ const rawRootOutput = await this.executeStep(rootStep, cropPrep?.input ?? rootInput, cropPrep?.width ?? imageWidth, cropPrep?.height ?? imageHeight, "full-frame", void 0, void 0, traceBuilder, stepTimings, poolAgg, rootShed);
3503
3597
  const rootMs = Date.now() - rootStart;
3504
3598
  if (rawRootOutput === null) continue;
3505
3599
  const rootOutput = cropPrep && rawRootOutput.kind === "detections" ? reprojectCropZoneDetections(rawRootOutput, cropPrep.origin) : rawRootOutput;
@@ -3565,7 +3659,17 @@ var PipelineExecutor = class {
3565
3659
  const fullFrameBar = rootStep.settings?.["fullFrameGuardMaxConfidence"];
3566
3660
  const fullFrameHardArea = rootStep.settings?.["fullFrameGuardHardAreaRatio"];
3567
3661
  if (isFullFramePhantomDetection(mutable.bbox, imageWidth, imageHeight, mutable.score, typeof fullFrameBar === "number" ? fullFrameBar : void 0, typeof fullFrameHardArea === "number" ? fullFrameHardArea : void 0)) {
3568
- this.opts.logger?.info("full-frame phantom guard: detection dropped", {
3662
+ const sample = this.dropSampler.record(deviceId, String(mutable.macroClass));
3663
+ if (sample.summaryCount !== null) this.opts.logger?.info("full-frame phantom guard: still dropping", {
3664
+ tags: { deviceId },
3665
+ meta: {
3666
+ macroClass: mutable.macroClass,
3667
+ suppressed: sample.summaryCount,
3668
+ windowMs: DROP_SUMMARY_INTERVAL_MS,
3669
+ hint: "a standing full-frame phantom — check the camera framing / model, not the guard"
3670
+ }
3671
+ });
3672
+ if (sample.logExample) this.opts.logger?.info("full-frame phantom guard: detection dropped", {
3569
3673
  tags: { deviceId },
3570
3674
  meta: {
3571
3675
  macroClass: mutable.macroClass,
@@ -3627,6 +3731,7 @@ var PipelineExecutor = class {
3627
3731
  firstLevel,
3628
3732
  details,
3629
3733
  discarded,
3734
+ ...rootShed.count > 0 ? { shed: { reason: rootShed.reasons[0] ?? "pool-overload" } } : {},
3630
3735
  stepTimings,
3631
3736
  totalMs,
3632
3737
  engine: this.opts.engineRuntime,
@@ -3697,7 +3802,7 @@ var PipelineExecutor = class {
3697
3802
  return null;
3698
3803
  }
3699
3804
  }
3700
- async executeStep(step, input, inputWidth, inputHeight, inputType, _parentBbox, parentClass, traceBuilder, stepTimings, poolAgg) {
3805
+ async executeStep(step, input, inputWidth, inputHeight, inputType, _parentBbox, parentClass, traceBuilder, stepTimings, poolAgg, shedAgg) {
3701
3806
  const preprocessStart = Date.now();
3702
3807
  const preprocessMs = Date.now() - preprocessStart;
3703
3808
  const inferenceStart = Date.now();
@@ -3734,6 +3839,10 @@ var PipelineExecutor = class {
3734
3839
  throw new Error(`Inference failed for step "${step.stepId}": ${errorMsg}`, { cause: err });
3735
3840
  }
3736
3841
  if (engineOutput.dropped === true) {
3842
+ if (shedAgg) {
3843
+ shedAgg.count += 1;
3844
+ shedAgg.reasons.push(engineOutput.shedReason ?? "pool-overload");
3845
+ }
3737
3846
  stepTimings.push({
3738
3847
  source: step.stepId,
3739
3848
  modelId: step.modelId,
@@ -4018,7 +4127,7 @@ function buildExecutableTree(steps, getEngine) {
4018
4127
  return { roots: steps.filter((s) => s.enabled).filter((s) => s.slot !== "audio-classifier").map((s) => buildNode(s, getEngine)) };
4019
4128
  }
4020
4129
  function buildNode(step, getEngine) {
4021
- const definition = require_step_definitions.getStepDefinition(step.addonId);
4130
+ const definition = require_event_loop_stall_monitor.getStepDefinition(step.addonId);
4022
4131
  const engine = getEngine(step.addonId);
4023
4132
  const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildNode(c, getEngine));
4024
4133
  const mergedSettings = {
@@ -4043,7 +4152,7 @@ function buildNode(step, getEngine) {
4043
4152
  * entered recursively. Fields without a declared default are skipped.
4044
4153
  */
4045
4154
  function collectSchemaDefaults(stepId) {
4046
- const schema = require_step_definitions.getStep(stepId).getConfigSchema();
4155
+ const schema = require_event_loop_stall_monitor.getStep(stepId).getConfigSchema();
4047
4156
  const out = {};
4048
4157
  walkFieldsForDefaults(schema, out);
4049
4158
  return out;
@@ -4108,7 +4217,7 @@ function collectSubstitutions(steps, format) {
4108
4217
  for (const step of steps) {
4109
4218
  const chosen = step.modelId;
4110
4219
  if (chosen != null) {
4111
- const running = require_step_definitions.resolveModelForFormat(step.addonId, chosen, format);
4220
+ const running = require_event_loop_stall_monitor.resolveModelForFormat(step.addonId, chosen, format);
4112
4221
  if (running !== chosen) result.push({
4113
4222
  addonId: step.addonId,
4114
4223
  chosen,
@@ -4134,7 +4243,7 @@ function collectSubstitutions(steps, format) {
4134
4243
  * black-box test. Unknown/custom addonIds (no registered `StepDefinition`)
4135
4244
  * are skipped, never thrown.
4136
4245
  */
4137
- function collectZeroBuildIssues(steps, format, getStepDef = require_step_definitions.getStepDefinition) {
4246
+ function collectZeroBuildIssues(steps, format, getStepDef = require_event_loop_stall_monitor.getStepDefinition) {
4138
4247
  const result = [];
4139
4248
  for (const step of steps) {
4140
4249
  let def;
@@ -4160,7 +4269,7 @@ function collectZeroBuildIssues(steps, format, getStepDef = require_step_definit
4160
4269
  * tests can exercise the unknown-addon branch with a fabricated resolver
4161
4270
  * without `vi.mock`.
4162
4271
  */
4163
- function collectUnknownAddonIssues(steps, getStepDef = require_step_definitions.getStepDefinition) {
4272
+ function collectUnknownAddonIssues(steps, getStepDef = require_event_loop_stall_monitor.getStepDefinition) {
4164
4273
  const result = [];
4165
4274
  for (const step of steps) {
4166
4275
  try {
@@ -4200,13 +4309,13 @@ function resolveInputSteps(steps, format, engine) {
4200
4309
  for (const s of steps) {
4201
4310
  let def;
4202
4311
  try {
4203
- def = require_step_definitions.getStepDefinition(s.addonId);
4312
+ def = require_event_loop_stall_monitor.getStepDefinition(s.addonId);
4204
4313
  } catch {
4205
4314
  unknownAddonIds.push(s.addonId);
4206
4315
  continue;
4207
4316
  }
4208
4317
  const chosenModelId = s.modelId ?? null;
4209
- const runningModelId = chosenModelId === null && engine !== void 0 && s.addonId === "object-detection" ? resolveDefaultDetectionModel(engine.backend, engine.device, format) : require_step_definitions.resolveModelForFormat(s.addonId, chosenModelId, format);
4318
+ const runningModelId = chosenModelId === null && engine !== void 0 && s.addonId === "object-detection" ? resolveDefaultDetectionModel(engine.backend, engine.device, format) : require_event_loop_stall_monitor.resolveModelForFormat(s.addonId, chosenModelId, format);
4210
4319
  if (chosenModelId !== null && runningModelId !== chosenModelId) substitutions.push({
4211
4320
  addonId: s.addonId,
4212
4321
  chosen: chosenModelId,
@@ -5076,7 +5185,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5076
5185
  * first, then the custom registry. Returns undefined if neither has it.
5077
5186
  */
5078
5187
  async resolveModelEntry(addonId, modelId) {
5079
- const fromCatalog = require_step_definitions.getStepDefinition(addonId).models.find((m) => m.id === modelId);
5188
+ const fromCatalog = require_event_loop_stall_monitor.getStepDefinition(addonId).models.find((m) => m.id === modelId);
5080
5189
  if (fromCatalog) return fromCatalog;
5081
5190
  return (await this.getCustomModels()).get(addonId)?.find((m) => m.id === modelId);
5082
5191
  }
@@ -5172,7 +5281,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5172
5281
  /** Pure recursive resolver — builds the resolved step tree without touching `modelSubstitutions`. */
5173
5282
  resolveStepModelTree(steps, format) {
5174
5283
  return steps.map((step) => {
5175
- const resolved = require_step_definitions.resolveModelForFormat(step.addonId, step.modelId ?? null, format);
5284
+ const resolved = require_event_loop_stall_monitor.resolveModelForFormat(step.addonId, step.modelId ?? null, format);
5176
5285
  const children = step.children?.length ? this.resolveStepModelTree([...step.children], format) : step.children;
5177
5286
  return resolved === step.modelId && children === step.children ? step : {
5178
5287
  ...step,
@@ -5320,7 +5429,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5320
5429
  for (const step of nodes) {
5321
5430
  if (!step.enabled) continue;
5322
5431
  try {
5323
- if (require_step_definitions.getStepDefinition(step.addonId).slot === "audio-classifier") continue;
5432
+ if (require_event_loop_stall_monitor.getStepDefinition(step.addonId).slot === "audio-classifier") continue;
5324
5433
  } catch {
5325
5434
  continue;
5326
5435
  }
@@ -5340,7 +5449,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5340
5449
  async getCapabilities(_forceRefresh) {
5341
5450
  const agentId = (this.addonCtx?.kernel?.cluster?.broker)?.nodeID ?? node_os.hostname();
5342
5451
  const agentName = agentId;
5343
- const addons = require_step_definitions.ALL_PIPELINE_STEPS.map((s) => ({
5452
+ const addons = require_event_loop_stall_monitor.ALL_PIPELINE_STEPS.map((s) => ({
5344
5453
  id: s.definition.id,
5345
5454
  name: s.definition.name,
5346
5455
  models: s.definition.models.filter((m) => m.legacy !== true).map((m) => {
@@ -5621,8 +5730,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5621
5730
  jpegProvider = async () => data;
5622
5731
  } else if (frame.format === "rgb" || frame.format === "bgr" || frame.format === "gray") {
5623
5732
  const channels = frame.format === "gray" ? 1 : 3;
5624
- const sharp$5 = (await import("sharp")).default;
5625
- const jpeg = await sharp$5(data, { raw: {
5733
+ const jpeg = await (await require_lazy_sharp.getSharp())(data, { raw: {
5626
5734
  width: frame.width,
5627
5735
  height: frame.height,
5628
5736
  channels
@@ -5636,8 +5744,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5636
5744
  };
5637
5745
  jpegProvider = async () => jpeg;
5638
5746
  } else {
5639
- const sharp$6 = (await import("sharp")).default;
5640
- const encoded = await sharp$6(data, { raw: {
5747
+ const encoded = await (await require_lazy_sharp.getSharp())(data, { raw: {
5641
5748
  width: frame.width,
5642
5749
  height: frame.height,
5643
5750
  channels: 3
@@ -6250,8 +6357,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
6250
6357
  /** Parse JPEG/PNG dimensions without decoding the full image */
6251
6358
  async getJpegDimensions(buf) {
6252
6359
  try {
6253
- const sharp$7 = (await import("sharp")).default;
6254
- const { width, height } = await sharp$7(buf).metadata();
6360
+ const { width, height } = await (await require_lazy_sharp.getSharp())(buf).metadata();
6255
6361
  return {
6256
6362
  width: width ?? 640,
6257
6363
  height: height ?? 640
@@ -7008,7 +7114,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
7008
7114
  function buildSchemaSlots(formats, modelsDir, customByStep) {
7009
7115
  const slotMap = /* @__PURE__ */ new Map();
7010
7116
  const formatList = [...formats];
7011
- for (const pipelineStep of require_step_definitions.ALL_PIPELINE_STEPS) {
7117
+ for (const pipelineStep of require_event_loop_stall_monitor.ALL_PIPELINE_STEPS) {
7012
7118
  const step = pipelineStep.definition;
7013
7119
  const availableModels = mergeCustomModels(step.models, customByStep?.get(step.id) ?? []).filter((m) => m.legacy !== true && formatList.some((f) => m.formats[f]));
7014
7120
  if (availableModels.length === 0) continue;
@@ -7095,7 +7201,7 @@ function resolveChildSlots(slot) {
7095
7201
  */
7096
7202
  function buildDefaultStepTree(format, objectDetectionModelId) {
7097
7203
  const makeStep = (stepId, children, opts) => {
7098
- const def = require_step_definitions.getStepDefinition(stepId);
7204
+ const def = require_event_loop_stall_monitor.getStepDefinition(stepId);
7099
7205
  if (!def.models.some((m) => m.formats[format])) return null;
7100
7206
  return {
7101
7207
  addonId: def.id,
@@ -7104,7 +7210,7 @@ function buildDefaultStepTree(format, objectDetectionModelId) {
7104
7210
  inputClasses: def.inputClasses ?? [],
7105
7211
  outputClasses: def.outputClasses,
7106
7212
  enabled: opts?.enabled ?? true,
7107
- modelId: opts?.modelId ?? require_step_definitions.getDefaultModelForFormat(stepId, format),
7213
+ modelId: opts?.modelId ?? require_event_loop_stall_monitor.getDefaultModelForFormat(stepId, format),
7108
7214
  children,
7109
7215
  ...def.group ? { group: def.group } : {}
7110
7216
  };
@@ -7161,7 +7267,7 @@ function flattenSteps(steps) {
7161
7267
  */
7162
7268
  function isDetailPlaneStep(addonId) {
7163
7269
  try {
7164
- return require_step_definitions.getStepDefinition(addonId).inputClasses !== null;
7270
+ return require_event_loop_stall_monitor.getStepDefinition(addonId).inputClasses !== null;
7165
7271
  } catch {
7166
7272
  return false;
7167
7273
  }
@@ -7182,7 +7288,7 @@ function stepHasZeroBuildsFor(addonId, format) {
7182
7288
  */
7183
7289
  function availableFormatsForStep(addonId) {
7184
7290
  try {
7185
- const def = require_step_definitions.getStepDefinition(addonId);
7291
+ const def = require_event_loop_stall_monitor.getStepDefinition(addonId);
7186
7292
  const formats = /* @__PURE__ */ new Set();
7187
7293
  for (const model of def.models) for (const format of Object.keys(model.formats)) formats.add(format);
7188
7294
  return Array.from(formats).toSorted();
@@ -7206,142 +7312,6 @@ function applyDeviceOverridesToTree(tree, rootStepId, overrides) {
7206
7312
  } : root) };
7207
7313
  }
7208
7314
  //#endregion
7209
- //#region src/detection-pipeline/diagnostics/event-loop-stall-monitor.ts
7210
- /**
7211
- * event-loop-stall-monitor — names the thing that freezes the detection process.
7212
- *
7213
- * ## What this exists to settle
7214
- *
7215
- * On 2026-08-01/02 inference across the whole fleet stalled in bursts: 759
7216
- * calls in 90 minutes crossed the runner's 20s deadline, p50 41s and max 80s,
7217
- * and EVERY one of them eventually resolved. Six explanations were killed with
7218
- * telemetry alone:
7219
- *
7220
- * - not a slow GPU or a wedged pool — the work completes, just enormously late;
7221
- * - not CPU starvation — hosts sat at 8-48% during the freezes;
7222
- * - not swap — `pswpin/pswpout` are flat zero on every host;
7223
- * - not a logging artifact — Loki's timestamp trails the in-process one by
7224
- * 0.1-1.0s at p95, so the gaps are real, not buffered delivery;
7225
- * - not the v1.2.30 release — the stalls predate it by a day;
7226
- * - not only the idle-pool recompile — that is real and hub-side, but the
7227
- * agent stalls with no eviction and no compile at all.
7228
- *
7229
- * What IS established: the 10s stats timer — which touches no inference code —
7230
- * stops firing for 22-88s and resumes at the same instant the abandoned calls
7231
- * settle. The event loop itself freezes. From outside the process, GC and a
7232
- * synchronous block are indistinguishable, and guessing between them is how
7233
- * this investigation would go wrong. So measure it.
7234
- *
7235
- * ## How
7236
- *
7237
- * A 1s interval whose LATENESS is the freeze: a tick that arrives 40s late means
7238
- * the loop was blocked ~39s, whatever blocked it. In the same window the GC
7239
- * observer accumulates pause time. The two numbers together answer the question
7240
- * outright:
7241
- *
7242
- * - `gcMs` ≈ `stallMs` → garbage collection. Look at heap growth.
7243
- * - `gcMs` ≈ 0 → something SYNCHRONOUS blocked the loop, and GC is innocent.
7244
- *
7245
- * Heap and RSS ride along because if it is GC, the next question is always
7246
- * "growing since when?".
7247
- *
7248
- * Deliberately not a histogram (`monitorEventLoopDelay`): that reports a
7249
- * distribution, and the question here is about ONE outlier and what coincided
7250
- * with it.
7251
- */
7252
- /** Tick period. Small enough to bound attribution error, large enough to cost
7253
- * nothing on a process already doing frame work. */
7254
- var STALL_TICK_MS = 1e3;
7255
- /**
7256
- * Report a freeze only past this. The runner's own inference deadline is 20s
7257
- * and the observed freezes run 22-88s, so this is far below the signal while
7258
- * staying clear of ordinary scheduling jitter (a busy frame path routinely
7259
- * overruns a 1s timer by tens of ms).
7260
- */
7261
- var STALL_REPORT_MS = 2e3;
7262
- /**
7263
- * Attribute a freeze. Pure, because this is the ONE judgement the whole module
7264
- * exists to make and it must be testable without freezing a real event loop.
7265
- *
7266
- * `gc` when garbage collection accounts for most of the stall; a
7267
- * `synchronous-block` when it accounts for almost none — that verdict points
7268
- * away from the heap entirely and at whatever ran without yielding.
7269
- */
7270
- function attributeStall(stallMs, gcMs, gcCount, longestGcMs) {
7271
- const share = stallMs > 0 ? gcMs / stallMs : 0;
7272
- return {
7273
- stallMs,
7274
- gcMs,
7275
- gcCount,
7276
- longestGcMs,
7277
- cause: share >= .7 ? "gc" : share <= .2 ? "synchronous-block" : "mixed"
7278
- };
7279
- }
7280
- /**
7281
- * Start watching. Returns a stop function; safe to call twice.
7282
- *
7283
- * Never throws into the caller: a diagnostic that can take the detection
7284
- * process down is worse than no diagnostic. `PerformanceObserver` for `gc` is
7285
- * unavailable in some embedded runtimes, and that must degrade to
7286
- * stall-detection-without-attribution rather than a boot failure.
7287
- */
7288
- function startEventLoopStallMonitor(logger, reportThresholdMs = STALL_REPORT_MS) {
7289
- let gc = {
7290
- totalMs: 0,
7291
- count: 0,
7292
- longestMs: 0
7293
- };
7294
- let observer = null;
7295
- try {
7296
- observer = new node_perf_hooks.PerformanceObserver((list) => {
7297
- for (const entry of list.getEntries()) {
7298
- gc.totalMs += entry.duration;
7299
- gc.count += 1;
7300
- if (entry.duration > gc.longestMs) gc.longestMs = entry.duration;
7301
- }
7302
- });
7303
- observer.observe({ entryTypes: ["gc"] });
7304
- } catch {
7305
- observer = null;
7306
- }
7307
- let expected = Date.now() + STALL_TICK_MS;
7308
- const timer = setInterval(() => {
7309
- const now = Date.now();
7310
- const lateBy = now - expected;
7311
- const window = gc;
7312
- gc = {
7313
- totalMs: 0,
7314
- count: 0,
7315
- longestMs: 0
7316
- };
7317
- expected = now + STALL_TICK_MS;
7318
- if (lateBy < reportThresholdMs) return;
7319
- const verdict = attributeStall(lateBy, Math.round(window.totalMs), window.count, Math.round(window.longestMs));
7320
- const mem = process.memoryUsage();
7321
- logger.warn("event loop stalled", { meta: {
7322
- stallMs: verdict.stallMs,
7323
- cause: verdict.cause,
7324
- gcMs: verdict.gcMs,
7325
- gcCount: verdict.gcCount,
7326
- longestGcMs: verdict.longestGcMs,
7327
- gcObserved: observer !== null,
7328
- heapUsedMb: Math.round(mem.heapUsed / 1e6),
7329
- heapTotalMb: Math.round(mem.heapTotal / 1e6),
7330
- rssMb: Math.round(mem.rss / 1e6),
7331
- externalMb: Math.round(mem.external / 1e6),
7332
- arrayBuffersMb: Math.round(mem.arrayBuffers / 1e6)
7333
- } });
7334
- }, STALL_TICK_MS);
7335
- timer.unref?.();
7336
- let stopped = false;
7337
- return () => {
7338
- if (stopped) return;
7339
- stopped = true;
7340
- clearInterval(timer);
7341
- observer?.disconnect();
7342
- };
7343
- }
7344
- //#endregion
7345
7315
  //#region src/detection-pipeline/python-readiness.ts
7346
7316
  /**
7347
7317
  * Resolve the embedded Python once, turning the null/throw failure modes into
@@ -7802,7 +7772,7 @@ var DetectionPipelineAddon = class extends require_dist.BaseAddon {
7802
7772
  async onInitialize() {
7803
7773
  const modelsDir = await this.resolveModelsDir();
7804
7774
  if (!this.ctx.settings) throw new Error("DetectionPipelineAddon: ctx.settings not available");
7805
- this.stopStallMonitor = startEventLoopStallMonitor(this.ctx.logger);
7775
+ this.stopStallMonitor = require_event_loop_stall_monitor.startEventLoopStallMonitor(this.ctx.logger);
7806
7776
  this.pythonAddonDir = resolveAddonPythonDir();
7807
7777
  const py = await ensurePythonReady(this.ctx.deps, this.ctx.logger);
7808
7778
  if (py.ok && py.pythonPath) this.pythonPath = py.pythonPath;
@@ -7855,7 +7825,7 @@ var DetectionPipelineAddon = class extends require_dist.BaseAddon {
7855
7825
  }).catch(() => {});
7856
7826
  }
7857
7827
  getModelCatalog() {
7858
- return require_step_definitions.ALL_STEPS.flatMap((s) => s.models.filter((m) => m.legacy !== true));
7828
+ return require_event_loop_stall_monitor.ALL_STEPS.flatMap((s) => s.models.filter((m) => m.legacy !== true));
7859
7829
  }
7860
7830
  /**
7861
7831
  * Proactively install the OpenVINO Python package when Intel hardware
@@ -7941,9 +7911,9 @@ var DetectionPipelineAddon = class extends require_dist.BaseAddon {
7941
7911
  }
7942
7912
  };
7943
7913
  //#endregion
7944
- exports.ALL_STEPS = require_step_definitions.ALL_STEPS;
7914
+ exports.ALL_STEPS = require_event_loop_stall_monitor.ALL_STEPS;
7945
7915
  exports.DetectionPipelineProvider = DetectionPipelineProvider;
7946
7916
  exports.default = DetectionPipelineAddon;
7947
- exports.getDefaultModelForFormat = require_step_definitions.getDefaultModelForFormat;
7948
- exports.getStepDefinition = require_step_definitions.getStepDefinition;
7917
+ exports.getDefaultModelForFormat = require_event_loop_stall_monitor.getDefaultModelForFormat;
7918
+ exports.getStepDefinition = require_event_loop_stall_monitor.getStepDefinition;
7949
7919
  exports.shouldInstallOpenvino = shouldInstallOpenvino;