@camstack/addon-pipeline 1.2.136 → 1.2.138

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 (41) hide show
  1. package/dist/audio-analyzer/index.js +7 -7
  2. package/dist/audio-analyzer/index.mjs +4 -4
  3. package/dist/detection-pipeline/index.js +61 -23
  4. package/dist/detection-pipeline/index.mjs +53 -15
  5. package/dist/{dist-BzLiQ8Ue.js → dist-BuIP0499.js} +315 -25
  6. package/dist/{dist-C1dXLLQq.mjs → dist-CmEYRK7G.mjs} +304 -26
  7. package/dist/{event-loop-stall-monitor-DjV4Bow7.js → event-loop-stall-monitor-Bef2jXMX.js} +1 -1
  8. package/dist/{event-loop-stall-monitor-CU-xxX5c.mjs → event-loop-stall-monitor-JGTFb0Uv.mjs} +1 -1
  9. package/dist/{lazy-sharp-DxWmhTqk.js → lazy-sharp-DH2eVehm.js} +3 -3
  10. package/dist/motion-wasm/index.js +3 -3
  11. package/dist/motion-wasm/index.mjs +3 -3
  12. package/dist/node-ChdX9lv7.js +721 -0
  13. package/dist/node-J07GBWT3.mjs +690 -0
  14. package/dist/pipeline-runner/index.js +87 -18
  15. package/dist/pipeline-runner/index.mjs +87 -18
  16. package/dist/{process-memory-CZK3D3kM.js → process-memory-CJoZemF4.js} +2 -2
  17. package/dist/{process-memory-CaEwi5Cd.mjs → process-memory-DAKxUb9d.mjs} +2 -2
  18. package/dist/recorder/index.js +39 -7
  19. package/dist/recorder/index.mjs +36 -4
  20. package/dist/{segment-demux-js-BbpqygHL.js → segment-demux-js-BgXbXZnp.js} +1 -1
  21. package/dist/{segment-demux-js-njRO85gd.mjs → segment-demux-js-Ck9ly4bX.mjs} +1 -1
  22. package/dist/session-decode/decode-worker-child.js +115 -5
  23. package/dist/session-decode/decode-worker-child.mjs +115 -5
  24. package/dist/stream-broker/_stub.js +2 -2
  25. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CLtMmF1E.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Cad8960O.mjs} +3 -3
  26. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-xdmO8wYp.mjs +26 -0
  27. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BrTM_tsb.mjs +26 -0
  28. package/dist/stream-broker/demux-worker-child.js +1 -1
  29. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  30. package/dist/stream-broker/{hostInit-CP7Xhd8J.mjs → hostInit-Gd3OcDIa.mjs} +3 -3
  31. package/dist/stream-broker/index.js +245 -535
  32. package/dist/stream-broker/index.mjs +242 -530
  33. package/dist/stream-broker/remoteEntry.js +1 -1
  34. package/dist/{worker-protocol-DvTZBvh2.js → worker-protocol-Bpz62eyB.js} +2 -1
  35. package/dist/{worker-protocol-DxsVx0G7.mjs → worker-protocol-wMS29PG9.mjs} +2 -1
  36. package/package.json +17 -3
  37. package/dist/addon-utils-CKf8kbwh.js +0 -625
  38. package/dist/addon-utils-CgBCF-mE.mjs +0 -583
  39. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DqplWP1i.mjs +0 -26
  40. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DKMXG57X.mjs +0 -26
  41. package/dist/{lazy-sharp-BtT5x-qP.mjs → lazy-sharp-DXsqwpph.mjs} +1 -1
@@ -2,13 +2,13 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-BzLiQ8Ue.js");
6
- const require_process_memory = require("../process-memory-CZK3D3kM.js");
7
- const require_addon_utils = require("../addon-utils-CKf8kbwh.js");
8
- let node_path = require("node:path");
9
- node_path = require_dist.__toESM(node_path);
5
+ const require_dist = require("../dist-BuIP0499.js");
6
+ const require_process_memory = require("../process-memory-CJoZemF4.js");
10
7
  let node_fs = require("node:fs");
11
8
  node_fs = require_dist.__toESM(node_fs);
9
+ let node_path = require("node:path");
10
+ node_path = require_dist.__toESM(node_path);
11
+ let _camstack_system_addon_utils = require("@camstack/system/addon-utils");
12
12
  //#region src/audio-analyzer/audio-pipeline.ts
13
13
  /**
14
14
  * Create the appropriate audio pipeline.
@@ -83,7 +83,7 @@ var YamnetPythonPipeline = class {
83
83
  url: YAMNET_MODEL_URL,
84
84
  dest: modelPath
85
85
  } });
86
- await require_addon_utils.downloadFile(YAMNET_MODEL_URL, modelPath);
86
+ await (0, _camstack_system_addon_utils.downloadFile)(YAMNET_MODEL_URL, modelPath);
87
87
  this.log.info("YAMNet ONNX model downloaded", { meta: { sizeBytes: node_fs.statSync(modelPath).size } });
88
88
  }
89
89
  if (!node_fs.existsSync(labelsPath)) {
@@ -91,7 +91,7 @@ var YamnetPythonPipeline = class {
91
91
  url: YAMNET_LABELS_URL,
92
92
  dest: labelsPath
93
93
  } });
94
- await require_addon_utils.downloadFile(YAMNET_LABELS_URL, labelsPath);
94
+ await (0, _camstack_system_addon_utils.downloadFile)(YAMNET_LABELS_URL, labelsPath);
95
95
  }
96
96
  const pythonDir = resolveAudioPythonDir();
97
97
  if (this.installPythonRequirements) await this.installPythonRequirements(node_path.join(pythonDir, "requirements-audio.txt"));
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { A as audioAnalysisCapability, Nt as hydrateSchema, Ot as BaseAddon, S as PoolMemoryWatchdog, St as errMsg, et as mapAudioLabelToMacro, ht as resolvePoolMemoryPolicy, j as audioAnalyzerCapability, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, v as HF_BASE_URL } from "../dist-C1dXLLQq.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-CaEwi5Cd.mjs";
4
- import { i as downloadFile } from "../addon-utils-CgBCF-mE.mjs";
5
- import * as path$1 from "node:path";
2
+ import { A as audioAnalysisCapability, At as BaseAddon, Ct as errMsg, Ft as hydrateSchema, S as PoolMemoryWatchdog, gt as resolvePoolMemoryPolicy, j as audioAnalyzerCapability, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, tt as mapAudioLabelToMacro, v as HF_BASE_URL } from "../dist-CmEYRK7G.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DAKxUb9d.mjs";
6
4
  import * as fs from "node:fs";
5
+ import * as path$1 from "node:path";
6
+ import { downloadFile } from "@camstack/system/addon-utils";
7
7
  //#region src/audio-analyzer/audio-pipeline.ts
8
8
  /**
9
9
  * Create the appropriate audio pipeline.
@@ -2,20 +2,21 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-BzLiQ8Ue.js");
6
- const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DjV4Bow7.js");
7
- const require_lazy_sharp = require("../lazy-sharp-DxWmhTqk.js");
8
- const require_process_memory = require("../process-memory-CZK3D3kM.js");
9
- const require_addon_utils = require("../addon-utils-CKf8kbwh.js");
10
- let sharp = require("sharp");
11
- sharp = require_dist.__toESM(sharp);
12
- let node_child_process = require("node:child_process");
5
+ const require_dist = require("../dist-BuIP0499.js");
6
+ const require_node = require("../node-ChdX9lv7.js");
7
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-Bef2jXMX.js");
8
+ const require_lazy_sharp = require("../lazy-sharp-DH2eVehm.js");
9
+ const require_process_memory = require("../process-memory-CJoZemF4.js");
10
+ let node_fs = require("node:fs");
11
+ node_fs = require_dist.__toESM(node_fs);
13
12
  let node_path = require("node:path");
14
13
  node_path = require_dist.__toESM(node_path);
14
+ let node_child_process = require("node:child_process");
15
+ let sharp = require("sharp");
16
+ sharp = require_dist.__toESM(sharp);
15
17
  let node_os = require("node:os");
16
18
  node_os = require_dist.__toESM(node_os);
17
- let node_fs = require("node:fs");
18
- node_fs = require_dist.__toESM(node_fs);
19
+ let _camstack_system_addon_utils = require("@camstack/system/addon-utils");
19
20
  //#region src/detection-pipeline/runtimes.ts
20
21
  var KNOWN_PLATFORMS = [
21
22
  "darwin",
@@ -6313,6 +6314,36 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
6313
6314
  * never mutates shared state, so concurrent multi-device sessions don't race.
6314
6315
  */
6315
6316
  factoriesByDevice = /* @__PURE__ */ new Map();
6317
+ /**
6318
+ * This addon's `load-contribution`: the shared inference pool, DECLARING
6319
+ * that it cannot be attributed to a camera.
6320
+ *
6321
+ * The renunciation is data, not a deduction. One python process per (node,
6322
+ * runtime, hardware device) serves every camera on the node, so no
6323
+ * `deviceId` is true of it — `deviceId: null` and
6324
+ * `attribution: 'unattributable'` say exactly that, and a consumer that
6325
+ * plots per-camera load must exclude it rather than apportion it. The pool's
6326
+ * pids are included so the node's process snapshot can mark those processes
6327
+ * CLAIMED-but-shared instead of unknown; without them a reader cannot tell
6328
+ * "shared cost, reported" from "process nobody knows about".
6329
+ *
6330
+ * Per-camera inference MILLISECONDS are counted elsewhere and are a
6331
+ * different quantity — how much of the pool a camera asked for, never how
6332
+ * many CPU seconds it cost. They are deliberately not smuggled in here.
6333
+ */
6334
+ async loadContributions() {
6335
+ const factories = [...this.engineFactory === null ? [] : [["default", this.engineFactory]], ...this.factoriesByDevice.entries()];
6336
+ const out = [];
6337
+ for (const [deviceKey, factory] of factories) for (const pid of factory.getPoolPids()) out.push({
6338
+ role: "detection",
6339
+ deviceId: null,
6340
+ attribution: "unattributable",
6341
+ unit: `inference pool ${deviceKey}`,
6342
+ pid,
6343
+ ...await require_node.readProcessCost(pid)
6344
+ });
6345
+ return out;
6346
+ }
6316
6347
  executor = null;
6317
6348
  currentSteps = null;
6318
6349
  currentEngine;
@@ -6867,7 +6898,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
6867
6898
  if (!step.enabled) continue;
6868
6899
  const modelEntry = await this.resolveModelEntry(step.addonId, step.modelId);
6869
6900
  if (!modelEntry) continue;
6870
- if (require_addon_utils.isModelDownloaded(this.modelsDir, modelEntry, format)) continue;
6901
+ if ((0, _camstack_system_addon_utils.isModelDownloaded)(this.modelsDir, modelEntry, format)) continue;
6871
6902
  await this.downloadWithRetry(modelEntry, format, 3);
6872
6903
  }
6873
6904
  }
@@ -7244,7 +7275,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
7244
7275
  const formats = {};
7245
7276
  for (const [formatKey, entry] of Object.entries(m.formats)) {
7246
7277
  if (!entry) continue;
7247
- const downloaded = require_addon_utils.isModelDownloaded(this.modelsDir, m, formatKey);
7278
+ const downloaded = (0, _camstack_system_addon_utils.isModelDownloaded)(this.modelsDir, m, formatKey);
7248
7279
  formats[formatKey] = {
7249
7280
  url: entry.url,
7250
7281
  sizeMB: entry.sizeMB,
@@ -7367,7 +7398,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
7367
7398
  const { modelId, format, addonId } = input;
7368
7399
  const modelEntry = await this.resolveModelEntry(addonId, modelId);
7369
7400
  if (!modelEntry) throw new Error(`Model "${modelId}" not found in step "${addonId}" catalog`);
7370
- if (!require_addon_utils.deleteModelFromDisk(this.modelsDir, modelEntry, format)) throw new Error(`Model "${modelId}" (${format}) is not downloaded — nothing to delete`);
7401
+ if (!(0, _camstack_system_addon_utils.deleteModelFromDisk)(this.modelsDir, modelEntry, format)) throw new Error(`Model "${modelId}" (${format}) is not downloaded — nothing to delete`);
7371
7402
  this.log.info("Model deleted from disk", { meta: {
7372
7403
  modelId,
7373
7404
  format
@@ -8184,7 +8215,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8184
8215
  const work = (async () => {
8185
8216
  for (const step of needed) {
8186
8217
  const modelEntry = await this.resolveModelEntry(step.addonId, step.modelId);
8187
- if (modelEntry && !require_addon_utils.isModelDownloaded(this.modelsDir, modelEntry, format)) {
8218
+ if (modelEntry && !(0, _camstack_system_addon_utils.isModelDownloaded)(this.modelsDir, modelEntry, format)) {
8188
8219
  if (modelEntry.formats[format] === void 0) throw new Error(`Model "${modelEntry.id}" has no ${format} format build (available: ${Object.keys(modelEntry.formats).join(", ") || "none"}) — not retrying a permanent format mismatch`);
8189
8220
  if (modelEntry.formats[format]?.url.startsWith("camstack-local://") === true) throw new Error(`Custom model "${modelEntry.id}" (${format}) is not present in this node's models directory — distribute it to this node from Model Studio before selecting it here`);
8190
8221
  this.log.info("Downloading model for step", { meta: {
@@ -8211,7 +8242,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8211
8242
  /** Download a model with retry + exponential backoff */
8212
8243
  async downloadWithRetry(entry, format, maxRetries, onProgress) {
8213
8244
  for (let attempt = 1; attempt <= maxRetries; attempt++) try {
8214
- await require_addon_utils.ensureModel(this.modelsDir, entry, format, onProgress);
8245
+ await (0, _camstack_system_addon_utils.ensureModel)(this.modelsDir, entry, format, onProgress);
8215
8246
  this.log.info("Model downloaded successfully", { meta: { modelId: entry.id } });
8216
8247
  return;
8217
8248
  } catch (err) {
@@ -9206,7 +9237,7 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
9206
9237
  id: m.id,
9207
9238
  name: m.name,
9208
9239
  formats: Object.fromEntries(Object.entries(m.formats).map(([f, entry]) => [f, {
9209
- downloaded: require_addon_utils.isModelDownloaded(modelsDir, m, f),
9240
+ downloaded: (0, _camstack_system_addon_utils.isModelDownloaded)(modelsDir, m, f),
9210
9241
  sizeMB: entry.sizeMB
9211
9242
  }])),
9212
9243
  ...m.group ? { group: m.group } : {},
@@ -9884,13 +9915,20 @@ var DetectionPipelineAddon = class extends require_dist.BaseAddon {
9884
9915
  await this.provider.warmPool();
9885
9916
  this.engineMetricsTimer = setInterval(() => this.emitEngineMetricsSnapshot(), ENGINE_METRICS_SNAPSHOT_INTERVAL_MS);
9886
9917
  this.lastAppliedOverride = this.resolveOperatorOverride();
9887
- return [{
9888
- capability: require_dist.pipelineExecutorCapability,
9889
- provider: this.provider
9890
- }, {
9891
- capability: require_dist.detectionPipelineCapability,
9892
- provider: this.provider
9893
- }];
9918
+ return [
9919
+ {
9920
+ capability: require_dist.pipelineExecutorCapability,
9921
+ provider: this.provider
9922
+ },
9923
+ {
9924
+ capability: require_dist.detectionPipelineCapability,
9925
+ provider: this.provider
9926
+ },
9927
+ {
9928
+ capability: require_dist.loadContributionCapability,
9929
+ provider: { list: async () => await this.provider?.loadContributions() ?? [] }
9930
+ }
9931
+ ];
9894
9932
  }
9895
9933
  /**
9896
9934
  * Emit a single `pipeline.engine-metrics-snapshot` event with the
@@ -1,14 +1,15 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as EventCategory, Lt as nodePin, Mt as createEvent, Nt as hydrateSchema, O as YAMNET_TO_MACRO, Ot as BaseAddon, Qt as union, Rt as parseJsonUnknown, S as PoolMemoryWatchdog, St as errMsg, Ut as array, Vt as sleep, W as detectionPipelineCapability, Y as evaluateZoneRules, Yt as object, Z as inferModelProvider, Zt as string, _t as runtimeDevices$1, at as pickClusterStepModels, bt as supportedRuntimes$1, c as DEFAULT_CLUSTER_STEP_MODELS, ht as resolvePoolMemoryPolicy, l as DEFAULT_CLUSTER_STEP_SETTINGS, lt as pipelineExecutorCapability, m as DEVICE_BACKEND_TO_FORMAT, ot as pickClusterStepSettings, pt as resolveClusterStepModelId, q as enumerateInferenceDevices, rt as overlayClusterStepSettings, t as APPLE_SA_TO_MACRO, z as defaultDeviceFor$1 } from "../dist-C1dXLLQq.mjs";
3
- import { a as ALL_PIPELINE_STEPS, c as getDefaultModelForFormatFromDef, d as resolveModelForFormat, f as landmarkPrecisionVerdict, l as getStep, n as startEventLoopStallMonitor, o as ALL_STEPS, r as localFrameRegistry, s as getDefaultModelForFormat, u as getStepDefinition } from "../event-loop-stall-monitor-CU-xxX5c.mjs";
4
- import { t as getSharp } from "../lazy-sharp-BtT5x-qP.mjs";
5
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-CaEwi5Cd.mjs";
6
- import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../addon-utils-CgBCF-mE.mjs";
7
- import sharp from "sharp";
8
- import { spawn } from "node:child_process";
2
+ import { $ as loadContributionCapability, $t as string, At as BaseAddon, Bt as parseJsonUnknown, Ct as errMsg, Ft as hydrateSchema, Gt as array, O as YAMNET_TO_MACRO, Pt as createEvent, S as PoolMemoryWatchdog, Ut as sleep, W as detectionPipelineCapability, Y as evaluateZoneRules, Z as inferModelProvider, Zt as object, c as DEFAULT_CLUSTER_STEP_MODELS, en as union, gt as resolvePoolMemoryPolicy, it as overlayClusterStepSettings, l as DEFAULT_CLUSTER_STEP_SETTINGS, m as DEVICE_BACKEND_TO_FORMAT, mt as resolveClusterStepModelId, ot as pickClusterStepModels, q as enumerateInferenceDevices, st as pickClusterStepSettings, t as APPLE_SA_TO_MACRO, tn as EventCategory, ut as pipelineExecutorCapability, vt as runtimeDevices$1, xt as supportedRuntimes$1, z as defaultDeviceFor$1, zt as nodePin } from "../dist-CmEYRK7G.mjs";
3
+ import { a as readProcessCost } from "../node-J07GBWT3.mjs";
4
+ import { a as ALL_PIPELINE_STEPS, c as getDefaultModelForFormatFromDef, d as resolveModelForFormat, f as landmarkPrecisionVerdict, l as getStep, n as startEventLoopStallMonitor, o as ALL_STEPS, r as localFrameRegistry, s as getDefaultModelForFormat, u as getStepDefinition } from "../event-loop-stall-monitor-JGTFb0Uv.mjs";
5
+ import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DAKxUb9d.mjs";
7
+ import * as fs from "node:fs";
9
8
  import * as path$1 from "node:path";
9
+ import { spawn } from "node:child_process";
10
+ import sharp from "sharp";
10
11
  import * as os from "node:os";
11
- import * as fs from "node:fs";
12
+ import { deleteModelFromDisk, ensureModel, isModelDownloaded } from "@camstack/system/addon-utils";
12
13
  //#region src/detection-pipeline/runtimes.ts
13
14
  var KNOWN_PLATFORMS = [
14
15
  "darwin",
@@ -6306,6 +6307,36 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
6306
6307
  * never mutates shared state, so concurrent multi-device sessions don't race.
6307
6308
  */
6308
6309
  factoriesByDevice = /* @__PURE__ */ new Map();
6310
+ /**
6311
+ * This addon's `load-contribution`: the shared inference pool, DECLARING
6312
+ * that it cannot be attributed to a camera.
6313
+ *
6314
+ * The renunciation is data, not a deduction. One python process per (node,
6315
+ * runtime, hardware device) serves every camera on the node, so no
6316
+ * `deviceId` is true of it — `deviceId: null` and
6317
+ * `attribution: 'unattributable'` say exactly that, and a consumer that
6318
+ * plots per-camera load must exclude it rather than apportion it. The pool's
6319
+ * pids are included so the node's process snapshot can mark those processes
6320
+ * CLAIMED-but-shared instead of unknown; without them a reader cannot tell
6321
+ * "shared cost, reported" from "process nobody knows about".
6322
+ *
6323
+ * Per-camera inference MILLISECONDS are counted elsewhere and are a
6324
+ * different quantity — how much of the pool a camera asked for, never how
6325
+ * many CPU seconds it cost. They are deliberately not smuggled in here.
6326
+ */
6327
+ async loadContributions() {
6328
+ const factories = [...this.engineFactory === null ? [] : [["default", this.engineFactory]], ...this.factoriesByDevice.entries()];
6329
+ const out = [];
6330
+ for (const [deviceKey, factory] of factories) for (const pid of factory.getPoolPids()) out.push({
6331
+ role: "detection",
6332
+ deviceId: null,
6333
+ attribution: "unattributable",
6334
+ unit: `inference pool ${deviceKey}`,
6335
+ pid,
6336
+ ...await readProcessCost(pid)
6337
+ });
6338
+ return out;
6339
+ }
6309
6340
  executor = null;
6310
6341
  currentSteps = null;
6311
6342
  currentEngine;
@@ -9877,13 +9908,20 @@ var DetectionPipelineAddon = class extends BaseAddon {
9877
9908
  await this.provider.warmPool();
9878
9909
  this.engineMetricsTimer = setInterval(() => this.emitEngineMetricsSnapshot(), ENGINE_METRICS_SNAPSHOT_INTERVAL_MS);
9879
9910
  this.lastAppliedOverride = this.resolveOperatorOverride();
9880
- return [{
9881
- capability: pipelineExecutorCapability,
9882
- provider: this.provider
9883
- }, {
9884
- capability: detectionPipelineCapability,
9885
- provider: this.provider
9886
- }];
9911
+ return [
9912
+ {
9913
+ capability: pipelineExecutorCapability,
9914
+ provider: this.provider
9915
+ },
9916
+ {
9917
+ capability: detectionPipelineCapability,
9918
+ provider: this.provider
9919
+ },
9920
+ {
9921
+ capability: loadContributionCapability,
9922
+ provider: { list: async () => await this.provider?.loadContributions() ?? [] }
9923
+ }
9924
+ ];
9887
9925
  }
9888
9926
  /**
9889
9927
  * Emit a single `pipeline.engine-metrics-snapshot` event with the