@camstack/addon-pipeline 1.2.77 → 1.2.79

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 (31) hide show
  1. package/dist/{addon-utils-bZcwLaVW.js → addon-utils-BZQxAJ1G.js} +1 -1
  2. package/dist/audio-analyzer/index.js +2 -2
  3. package/dist/audio-analyzer/index.mjs +1 -1
  4. package/dist/detection-pipeline/index.js +4 -4
  5. package/dist/detection-pipeline/index.mjs +2 -2
  6. package/dist/{dist-DQZzL0Ri.js → dist-BUIpqu3E.js} +125 -7
  7. package/dist/{dist-HhcoV-Ky.mjs → dist-BfTf6doa.mjs} +125 -7
  8. package/dist/{event-loop-stall-monitor-CBOo1oh_.js → event-loop-stall-monitor-CGLQP0by.js} +1 -1
  9. package/dist/{event-loop-stall-monitor-CqBEWGSZ.mjs → event-loop-stall-monitor-CmrHj0i9.mjs} +1 -1
  10. package/dist/{lazy-sharp-DIC1rpea.js → lazy-sharp-BZVhL9Lw.js} +1 -1
  11. package/dist/motion-wasm/index.js +2 -2
  12. package/dist/motion-wasm/index.mjs +1 -1
  13. package/dist/pipeline-runner/index.js +4 -4
  14. package/dist/pipeline-runner/index.mjs +3 -3
  15. package/dist/recorder/index.js +293 -34
  16. package/dist/recorder/index.mjs +292 -33
  17. package/dist/session-decode/decode-worker-child.js +2 -2
  18. package/dist/session-decode/decode-worker-child.mjs +1 -1
  19. package/dist/stream-broker/_stub.js +2 -2
  20. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-De_xzvjU.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BohtrVou.mjs} +2 -2
  21. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-y8ehJPoY.mjs +26 -0
  22. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Dxr14lIu.mjs +26 -0
  23. package/dist/stream-broker/{hostInit-CDS5frmk.mjs → hostInit-pDANS0x0.mjs} +2 -2
  24. package/dist/stream-broker/index.js +347 -42
  25. package/dist/stream-broker/index.mjs +347 -42
  26. package/dist/stream-broker/remoteEntry.js +1 -1
  27. package/dist/{worker-protocol-DZVGVAPU.js → worker-protocol-BaLcYcOo.js} +1 -1
  28. package/dist/{worker-protocol-BNlLGLBV.mjs → worker-protocol-BdOv9Ujl.mjs} +1 -1
  29. package/package.json +1 -1
  30. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DHJSxHH1.mjs +0 -26
  31. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Dg08SxUW.mjs +0 -26
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-DQZzL0Ri.js");
1
+ const require_dist = require("./dist-BUIpqu3E.js");
2
2
  require("node:crypto");
3
3
  let node_path = require("node:path");
4
4
  node_path = require_dist.__toESM(node_path, 1);
@@ -2,9 +2,9 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-DQZzL0Ri.js");
5
+ const require_dist = require("../dist-BUIpqu3E.js");
6
6
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
7
- const require_addon_utils = require("../addon-utils-bZcwLaVW.js");
7
+ const require_addon_utils = require("../addon-utils-BZQxAJ1G.js");
8
8
  let node_path = require("node:path");
9
9
  node_path = require_dist.__toESM(node_path);
10
10
  let node_fs = require("node:fs");
@@ -1,5 +1,5 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { B as mapAudioLabelToMacro, E as audioAnalyzerCapability, T as audioAnalysisCapability, ft as hydrateSchema, m as HF_BASE_URL, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG, st as BaseAddon, tt as errMsg } from "../dist-HhcoV-Ky.mjs";
2
+ import { B as mapAudioLabelToMacro, E as audioAnalyzerCapability, T as audioAnalysisCapability, ft as hydrateSchema, m as HF_BASE_URL, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG, st as BaseAddon, tt as errMsg } from "../dist-BfTf6doa.mjs";
3
3
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
4
4
  import { i as downloadFile } from "../addon-utils-A2S9D7pu.mjs";
5
5
  import * as path$1 from "node:path";
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-DQZzL0Ri.js");
6
- const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-CBOo1oh_.js");
7
- const require_lazy_sharp = require("../lazy-sharp-DIC1rpea.js");
5
+ const require_dist = require("../dist-BUIpqu3E.js");
6
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-CGLQP0by.js");
7
+ const require_lazy_sharp = require("../lazy-sharp-BZVhL9Lw.js");
8
8
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
9
- const require_addon_utils = require("../addon-utils-bZcwLaVW.js");
9
+ const require_addon_utils = require("../addon-utils-BZQxAJ1G.js");
10
10
  let sharp = require("sharp");
11
11
  sharp = require_dist.__toESM(sharp);
12
12
  let node_child_process = require("node:child_process");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $ as supportedRuntimes$1, A as defaultDeviceFor$1, At as string, C as YAMNET_TO_MACRO, G as pipelineExecutorCapability, L as enumerateInferenceDevices, Mt as EventCategory, Ot as object, P as detectionPipelineCapability, R as evaluateZoneRules, St as array, X as runtimeDevices$1, _t as parseJsonUnknown, bt as sleep, dt as createEvent, ft as hydrateSchema, gt as nodePin, jt as union, st as BaseAddon, t as APPLE_SA_TO_MACRO, tt as errMsg, u as DEVICE_BACKEND_TO_FORMAT } from "../dist-HhcoV-Ky.mjs";
3
- import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-CqBEWGSZ.mjs";
2
+ import { $ as supportedRuntimes$1, A as defaultDeviceFor$1, At as string, C as YAMNET_TO_MACRO, G as pipelineExecutorCapability, L as enumerateInferenceDevices, Mt as EventCategory, Ot as object, P as detectionPipelineCapability, R as evaluateZoneRules, St as array, X as runtimeDevices$1, _t as parseJsonUnknown, bt as sleep, dt as createEvent, ft as hydrateSchema, gt as nodePin, jt as union, st as BaseAddon, t as APPLE_SA_TO_MACRO, tt as errMsg, u as DEVICE_BACKEND_TO_FORMAT } from "../dist-BfTf6doa.mjs";
3
+ import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-CmrHj0i9.mjs";
4
4
  import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
5
5
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
6
6
  import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../addon-utils-A2S9D7pu.mjs";
@@ -13905,9 +13905,12 @@ var LlmProfileSchema = object({
13905
13905
  systemPrompt: string().optional(),
13906
13906
  /** Total generation bound — the only one a unary call has. */
13907
13907
  timeoutMs: number().int().positive().default(6e4),
13908
- /** Wait for response headers only. */
13908
+ /** The TCP handshake only — "is the port even open". NOT the wait for
13909
+ * response headers: on the LM Studio / llama-server wire those are written
13910
+ * once the model has finished loading, so they belong to the bound below. */
13909
13911
  connectTimeoutMs: number().int().positive().default(1e4),
13910
- /** Accepted, but no output yet — a cold GPU load lives here. */
13912
+ /** Accepted, but no output yet — response headers included, because a cold
13913
+ * GPU load is exactly what happens before them. */
13911
13914
  firstTokenTimeoutMs: number().int().positive().default(12e4),
13912
13915
  /** Output started then stopped. */
13913
13916
  idleTimeoutMs: number().int().positive().default(6e4),
@@ -16245,13 +16248,81 @@ var NcRuleActionsSchema = object({
16245
16248
  */
16246
16249
  buttons: array(NcRuleNotificationButtonSchema).max(8).optional()
16247
16250
  });
16251
+ /**
16252
+ * "This rule applies only while `deviceId` is in one of `states`."
16253
+ *
16254
+ * The states are the DEVICE's own vocabulary — `AlarmState` for a panel,
16255
+ * `on`/`off` for a switch — not a normalised set, because normalising would
16256
+ * make the condition lie about devices whose states have no equivalent.
16257
+ *
16258
+ * An unreadable state does NOT match: see the engine's fail-closed gate. A
16259
+ * condition that fired on "I could not read it" would be worse than no gate.
16260
+ */
16261
+ var NcDeviceStateConditionSchema = object({
16262
+ deviceId: number().int(),
16263
+ /** Any of these matches. */
16264
+ states: array(string().min(1)).min(1)
16265
+ });
16266
+ /**
16267
+ * "This rule applies only while scene `sceneId` is `matched` / `diverged`."
16268
+ *
16269
+ * A GATE, not a trigger. `occupancy` and `audio` each DISCRIMINATE their rule —
16270
+ * carrying one makes the rule fire on that subject and nothing else. Scene is
16271
+ * the other shape entirely, the `deviceState` shape: it narrows a rule that
16272
+ * already has a trigger ("tell me about a person at the front door, but only
16273
+ * while the bin is still out"). That is why it composes with every delivery
16274
+ * instead of owning one, and why no new `NcDelivery` member and no new subject
16275
+ * kind exist for it — see D159.
16276
+ *
16277
+ * ── Identity ───────────────────────────────────────────────────────────────
16278
+ * `sceneId` is `SceneMonitor.id`, a `randomUUID()` minted by `createScene` —
16279
+ * globally unique, so it needs no device to disambiguate it. `deviceId` is
16280
+ * carried as a HINT for the editor and for the log line, never as part of the
16281
+ * lookup key: a rule whose hint drifted must still gate correctly.
16282
+ *
16283
+ * ── Which boolean ──────────────────────────────────────────────────────────
16284
+ * `latched` ABSENT means "whatever the scene itself says" — `SceneMonitor.emit`
16285
+ * already declares which boolean drives notification rules, and a second knob
16286
+ * that could disagree with it is exactly the D62 failure. Set it only to
16287
+ * override one rule against the scene's own default.
16288
+ *
16289
+ * - LIVE reading (`emit`/`latched` resolve to live): passes iff
16290
+ * `verdict === requiredState`. `unknown` — no reference for this light, view
16291
+ * shifted, no snapshot — passes NEITHER. A scene that cannot judge is not
16292
+ * evidence, in either direction.
16293
+ * - LATCHED reading: passes iff `latched === (requiredState === 'diverged')`.
16294
+ * The latch is a durable fact about the past ("it has diverged since I armed
16295
+ * it"), so a camera that has gone dark does not clear it — that is the whole
16296
+ * reason the operator asked for a latch.
16297
+ *
16298
+ * The gate reads an in-memory mirror (`NcSceneStateCache`) refreshed OFF the
16299
+ * event path, never the cap: D49. A mirror that has never loaded, or a scene it
16300
+ * does not carry, reads absent and the rule does NOT fire — fail closed, and
16301
+ * said out loud in the log rather than dropped in silence.
16302
+ */
16303
+ var NcSceneConditionSchema = object({
16304
+ /** `SceneMonitor.id` — the uuid the cap mints. The whole lookup key. */
16305
+ sceneId: string().min(1),
16306
+ /** The camera the scene lives on. A hint for the editor and the log line. */
16307
+ deviceId: number().int().optional(),
16308
+ /** The state the scene must be in for the rule to fire. */
16309
+ requiredState: _enum(["matched", "diverged"]),
16310
+ /**
16311
+ * Read the LATCH (`true`) or the LIVE verdict (`false`). Absent = follow the
16312
+ * scene's own `emit` field, which is the only place that decision belongs.
16313
+ */
16314
+ latched: boolean().optional()
16315
+ });
16248
16316
  var NcConditionsSchema = object({
16249
16317
  /** Gate on ANOTHER device's current state (the alarm armed, a switch on). */
16250
- deviceState: object({
16251
- deviceId: number().int(),
16252
- /** Any of these matches. */
16253
- states: array(string().min(1)).min(1)
16254
- }).optional(),
16318
+ deviceState: NcDeviceStateConditionSchema.optional(),
16319
+ /**
16320
+ * Gate on a SCENE's state — "only while the bin is still out". Composes with
16321
+ * every trigger (detection, occupancy, audio, sensor, package, track-end);
16322
+ * unlike `occupancy`/`audio` it discriminates nothing. See
16323
+ * {@link NcSceneCondition} and D159.
16324
+ */
16325
+ scene: NcSceneConditionSchema.optional(),
16255
16326
  /** Device scope — absent = all devices. */
16256
16327
  devices: array(number()).optional(),
16257
16328
  /** Detector class names (any overlap with the record's class set). */
@@ -16889,6 +16960,7 @@ var NcConditionDescriptorSchema = object({
16889
16960
  "occupancy",
16890
16961
  "audio",
16891
16962
  "deviceState",
16963
+ "scene",
16892
16964
  "systemEvent"
16893
16965
  ]),
16894
16966
  operator: _enum([
@@ -26630,6 +26702,33 @@ var recordingExportCapability = {
26630
26702
  * as `unknown`, never guessed. A day reference scored against an IR frame
26631
26703
  * collapses the cosine and would latch a false alarm every single night. */
26632
26704
  var SceneConditionSchema = string();
26705
+ /**
26706
+ * What a scene does when the CURRENT light has no reference of its own.
26707
+ *
26708
+ * The lighting variants are not equally likely to exist. Almost every operator
26709
+ * captures daylight and then never stands outside at 22:00 to capture IR, and a
26710
+ * scene that is only ever going to be asked about a daytime question ("is the
26711
+ * bin still on the kerb at 08:00") does not need a night reference at all. The
26712
+ * night half must therefore be OPTIONAL, and optional means the scene keeps
26713
+ * working without it rather than degrading into a permanent complaint.
26714
+ *
26715
+ * - `skip` (default) — the check in that light is not made. Not a verdict, not
26716
+ * an alarm, not even an `unknown`: the live state simply stays whatever the
26717
+ * last covered light left it at, the latch is untouched, and the hysteresis
26718
+ * run is neither spent nor cleared. The scene resumes by itself at first
26719
+ * light. This is the only behaviour under which "I never captured IR" is a
26720
+ * configuration choice instead of a nightly fault.
26721
+ * - `judge-anyway` — score against the OTHER conditions' references. Available
26722
+ * for cameras whose IR frame is close enough to daylight (a floodlit
26723
+ * driveway, an always-white-light doorbell), and wrong for everything else:
26724
+ * cross-condition cosines are not comparable, so a day reference against a
26725
+ * true IR frame collapses and the scene reports a theft at 21:40.
26726
+ *
26727
+ * Never applies when the scene has NO comparable reference at all — that is
26728
+ * "not armed yet", it is reported as `no-reference-for-condition`, and silence
26729
+ * there would hide a scene the operator never finished setting up.
26730
+ */
26731
+ var SceneUncoveredPolicySchema = _enum(["skip", "judge-anyway"]);
26633
26732
  /** `matched` = the baseline is what we see; `diverged` = it demonstrably is not;
26634
26733
  * `unknown` = we cannot judge (no reference for this condition, encoder model
26635
26734
  * changed, view shifted, no snapshot). `unknown` is a real value, not a null,
@@ -26685,6 +26784,9 @@ var SceneCheckSchema = discriminatedUnion("mode", [object({
26685
26784
  hysteresisCount: number().int().positive()
26686
26785
  })]);
26687
26786
  var SCENE_DEFAULT_ANCHOR_THRESHOLD = .85;
26787
+ /** Night is OPTIONAL. A scene with only a daylight reference sits the IR hours
26788
+ * out in silence rather than reporting a fault every night. */
26789
+ var SCENE_DEFAULT_UNCOVERED_POLICY = "skip";
26688
26790
  /**
26689
26791
  * Vision-model adjudication of a candidate flip. Field names deliberately
26690
26792
  * mirror `NcConfirmSchema` so an operator meets one vocabulary, not two.
@@ -26751,6 +26853,21 @@ var SceneMonitorSchema = object({
26751
26853
  * automation can react to the bin coming back without the operator's own
26752
26854
  * alarm silently clearing itself. */
26753
26855
  autoRestore: boolean().default(false),
26856
+ /** What to do when the current light has no reference of its own. See
26857
+ * {@link SceneUncoveredPolicySchema} — the default makes night OPTIONAL. */
26858
+ onUncoveredCondition: SceneUncoveredPolicySchema.default(SCENE_DEFAULT_UNCOVERED_POLICY),
26859
+ /**
26860
+ * The light whose checks are currently being SAT OUT under
26861
+ * `onUncoveredCondition: 'skip'` — `null` when the scene is checking normally.
26862
+ *
26863
+ * Engine-reported and advisory only: it moves no verdict, no latch and no
26864
+ * hysteresis. It exists so the card can say *"night (IR) — checks paused,
26865
+ * nothing captured in this light"* in the same calm voice as the coverage
26866
+ * line, because the alternative is a scene that silently stops answering
26867
+ * after sunset with nothing anywhere saying why. A skipped check must never
26868
+ * read as a broken one.
26869
+ */
26870
+ suspendedCondition: SceneConditionSchema.nullable().default(null),
26754
26871
  /** Named cause when `verdict === 'unknown'`. */
26755
26872
  unavailable: SceneUnavailableSchema.nullable(),
26756
26873
  /** Conditions that have at least one comparable reference — the coverage line
@@ -26794,6 +26911,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSche
26794
26911
  minObservationSpacingSec: number().int().min(0).max(3600).optional(),
26795
26912
  anchorThreshold: number().min(0).max(1).optional(),
26796
26913
  autoRestore: boolean().optional(),
26914
+ onUncoveredCondition: SceneUncoveredPolicySchema.optional(),
26797
26915
  /** `null` clears the vision-model adjudicator. */
26798
26916
  confirm: SceneConfirmSchema.nullable().optional()
26799
26917
  })
@@ -13882,9 +13882,12 @@ var LlmProfileSchema = object({
13882
13882
  systemPrompt: string().optional(),
13883
13883
  /** Total generation bound — the only one a unary call has. */
13884
13884
  timeoutMs: number().int().positive().default(6e4),
13885
- /** Wait for response headers only. */
13885
+ /** The TCP handshake only — "is the port even open". NOT the wait for
13886
+ * response headers: on the LM Studio / llama-server wire those are written
13887
+ * once the model has finished loading, so they belong to the bound below. */
13886
13888
  connectTimeoutMs: number().int().positive().default(1e4),
13887
- /** Accepted, but no output yet — a cold GPU load lives here. */
13889
+ /** Accepted, but no output yet — response headers included, because a cold
13890
+ * GPU load is exactly what happens before them. */
13888
13891
  firstTokenTimeoutMs: number().int().positive().default(12e4),
13889
13892
  /** Output started then stopped. */
13890
13893
  idleTimeoutMs: number().int().positive().default(6e4),
@@ -16222,13 +16225,81 @@ var NcRuleActionsSchema = object({
16222
16225
  */
16223
16226
  buttons: array(NcRuleNotificationButtonSchema).max(8).optional()
16224
16227
  });
16228
+ /**
16229
+ * "This rule applies only while `deviceId` is in one of `states`."
16230
+ *
16231
+ * The states are the DEVICE's own vocabulary — `AlarmState` for a panel,
16232
+ * `on`/`off` for a switch — not a normalised set, because normalising would
16233
+ * make the condition lie about devices whose states have no equivalent.
16234
+ *
16235
+ * An unreadable state does NOT match: see the engine's fail-closed gate. A
16236
+ * condition that fired on "I could not read it" would be worse than no gate.
16237
+ */
16238
+ var NcDeviceStateConditionSchema = object({
16239
+ deviceId: number().int(),
16240
+ /** Any of these matches. */
16241
+ states: array(string().min(1)).min(1)
16242
+ });
16243
+ /**
16244
+ * "This rule applies only while scene `sceneId` is `matched` / `diverged`."
16245
+ *
16246
+ * A GATE, not a trigger. `occupancy` and `audio` each DISCRIMINATE their rule —
16247
+ * carrying one makes the rule fire on that subject and nothing else. Scene is
16248
+ * the other shape entirely, the `deviceState` shape: it narrows a rule that
16249
+ * already has a trigger ("tell me about a person at the front door, but only
16250
+ * while the bin is still out"). That is why it composes with every delivery
16251
+ * instead of owning one, and why no new `NcDelivery` member and no new subject
16252
+ * kind exist for it — see D159.
16253
+ *
16254
+ * ── Identity ───────────────────────────────────────────────────────────────
16255
+ * `sceneId` is `SceneMonitor.id`, a `randomUUID()` minted by `createScene` —
16256
+ * globally unique, so it needs no device to disambiguate it. `deviceId` is
16257
+ * carried as a HINT for the editor and for the log line, never as part of the
16258
+ * lookup key: a rule whose hint drifted must still gate correctly.
16259
+ *
16260
+ * ── Which boolean ──────────────────────────────────────────────────────────
16261
+ * `latched` ABSENT means "whatever the scene itself says" — `SceneMonitor.emit`
16262
+ * already declares which boolean drives notification rules, and a second knob
16263
+ * that could disagree with it is exactly the D62 failure. Set it only to
16264
+ * override one rule against the scene's own default.
16265
+ *
16266
+ * - LIVE reading (`emit`/`latched` resolve to live): passes iff
16267
+ * `verdict === requiredState`. `unknown` — no reference for this light, view
16268
+ * shifted, no snapshot — passes NEITHER. A scene that cannot judge is not
16269
+ * evidence, in either direction.
16270
+ * - LATCHED reading: passes iff `latched === (requiredState === 'diverged')`.
16271
+ * The latch is a durable fact about the past ("it has diverged since I armed
16272
+ * it"), so a camera that has gone dark does not clear it — that is the whole
16273
+ * reason the operator asked for a latch.
16274
+ *
16275
+ * The gate reads an in-memory mirror (`NcSceneStateCache`) refreshed OFF the
16276
+ * event path, never the cap: D49. A mirror that has never loaded, or a scene it
16277
+ * does not carry, reads absent and the rule does NOT fire — fail closed, and
16278
+ * said out loud in the log rather than dropped in silence.
16279
+ */
16280
+ var NcSceneConditionSchema = object({
16281
+ /** `SceneMonitor.id` — the uuid the cap mints. The whole lookup key. */
16282
+ sceneId: string().min(1),
16283
+ /** The camera the scene lives on. A hint for the editor and the log line. */
16284
+ deviceId: number().int().optional(),
16285
+ /** The state the scene must be in for the rule to fire. */
16286
+ requiredState: _enum(["matched", "diverged"]),
16287
+ /**
16288
+ * Read the LATCH (`true`) or the LIVE verdict (`false`). Absent = follow the
16289
+ * scene's own `emit` field, which is the only place that decision belongs.
16290
+ */
16291
+ latched: boolean().optional()
16292
+ });
16225
16293
  var NcConditionsSchema = object({
16226
16294
  /** Gate on ANOTHER device's current state (the alarm armed, a switch on). */
16227
- deviceState: object({
16228
- deviceId: number().int(),
16229
- /** Any of these matches. */
16230
- states: array(string().min(1)).min(1)
16231
- }).optional(),
16295
+ deviceState: NcDeviceStateConditionSchema.optional(),
16296
+ /**
16297
+ * Gate on a SCENE's state — "only while the bin is still out". Composes with
16298
+ * every trigger (detection, occupancy, audio, sensor, package, track-end);
16299
+ * unlike `occupancy`/`audio` it discriminates nothing. See
16300
+ * {@link NcSceneCondition} and D159.
16301
+ */
16302
+ scene: NcSceneConditionSchema.optional(),
16232
16303
  /** Device scope — absent = all devices. */
16233
16304
  devices: array(number()).optional(),
16234
16305
  /** Detector class names (any overlap with the record's class set). */
@@ -16866,6 +16937,7 @@ var NcConditionDescriptorSchema = object({
16866
16937
  "occupancy",
16867
16938
  "audio",
16868
16939
  "deviceState",
16940
+ "scene",
16869
16941
  "systemEvent"
16870
16942
  ]),
16871
16943
  operator: _enum([
@@ -26607,6 +26679,33 @@ var recordingExportCapability = {
26607
26679
  * as `unknown`, never guessed. A day reference scored against an IR frame
26608
26680
  * collapses the cosine and would latch a false alarm every single night. */
26609
26681
  var SceneConditionSchema = string();
26682
+ /**
26683
+ * What a scene does when the CURRENT light has no reference of its own.
26684
+ *
26685
+ * The lighting variants are not equally likely to exist. Almost every operator
26686
+ * captures daylight and then never stands outside at 22:00 to capture IR, and a
26687
+ * scene that is only ever going to be asked about a daytime question ("is the
26688
+ * bin still on the kerb at 08:00") does not need a night reference at all. The
26689
+ * night half must therefore be OPTIONAL, and optional means the scene keeps
26690
+ * working without it rather than degrading into a permanent complaint.
26691
+ *
26692
+ * - `skip` (default) — the check in that light is not made. Not a verdict, not
26693
+ * an alarm, not even an `unknown`: the live state simply stays whatever the
26694
+ * last covered light left it at, the latch is untouched, and the hysteresis
26695
+ * run is neither spent nor cleared. The scene resumes by itself at first
26696
+ * light. This is the only behaviour under which "I never captured IR" is a
26697
+ * configuration choice instead of a nightly fault.
26698
+ * - `judge-anyway` — score against the OTHER conditions' references. Available
26699
+ * for cameras whose IR frame is close enough to daylight (a floodlit
26700
+ * driveway, an always-white-light doorbell), and wrong for everything else:
26701
+ * cross-condition cosines are not comparable, so a day reference against a
26702
+ * true IR frame collapses and the scene reports a theft at 21:40.
26703
+ *
26704
+ * Never applies when the scene has NO comparable reference at all — that is
26705
+ * "not armed yet", it is reported as `no-reference-for-condition`, and silence
26706
+ * there would hide a scene the operator never finished setting up.
26707
+ */
26708
+ var SceneUncoveredPolicySchema = _enum(["skip", "judge-anyway"]);
26610
26709
  /** `matched` = the baseline is what we see; `diverged` = it demonstrably is not;
26611
26710
  * `unknown` = we cannot judge (no reference for this condition, encoder model
26612
26711
  * changed, view shifted, no snapshot). `unknown` is a real value, not a null,
@@ -26662,6 +26761,9 @@ var SceneCheckSchema = discriminatedUnion("mode", [object({
26662
26761
  hysteresisCount: number().int().positive()
26663
26762
  })]);
26664
26763
  var SCENE_DEFAULT_ANCHOR_THRESHOLD = .85;
26764
+ /** Night is OPTIONAL. A scene with only a daylight reference sits the IR hours
26765
+ * out in silence rather than reporting a fault every night. */
26766
+ var SCENE_DEFAULT_UNCOVERED_POLICY = "skip";
26665
26767
  /**
26666
26768
  * Vision-model adjudication of a candidate flip. Field names deliberately
26667
26769
  * mirror `NcConfirmSchema` so an operator meets one vocabulary, not two.
@@ -26728,6 +26830,21 @@ var SceneMonitorSchema = object({
26728
26830
  * automation can react to the bin coming back without the operator's own
26729
26831
  * alarm silently clearing itself. */
26730
26832
  autoRestore: boolean().default(false),
26833
+ /** What to do when the current light has no reference of its own. See
26834
+ * {@link SceneUncoveredPolicySchema} — the default makes night OPTIONAL. */
26835
+ onUncoveredCondition: SceneUncoveredPolicySchema.default(SCENE_DEFAULT_UNCOVERED_POLICY),
26836
+ /**
26837
+ * The light whose checks are currently being SAT OUT under
26838
+ * `onUncoveredCondition: 'skip'` — `null` when the scene is checking normally.
26839
+ *
26840
+ * Engine-reported and advisory only: it moves no verdict, no latch and no
26841
+ * hysteresis. It exists so the card can say *"night (IR) — checks paused,
26842
+ * nothing captured in this light"* in the same calm voice as the coverage
26843
+ * line, because the alternative is a scene that silently stops answering
26844
+ * after sunset with nothing anywhere saying why. A skipped check must never
26845
+ * read as a broken one.
26846
+ */
26847
+ suspendedCondition: SceneConditionSchema.nullable().default(null),
26731
26848
  /** Named cause when `verdict === 'unknown'`. */
26732
26849
  unavailable: SceneUnavailableSchema.nullable(),
26733
26850
  /** Conditions that have at least one comparable reference — the coverage line
@@ -26771,6 +26888,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSche
26771
26888
  minObservationSpacingSec: number().int().min(0).max(3600).optional(),
26772
26889
  anchorThreshold: number().min(0).max(1).optional(),
26773
26890
  autoRestore: boolean().optional(),
26891
+ onUncoveredCondition: SceneUncoveredPolicySchema.optional(),
26774
26892
  /** `null` clears the vision-model adjudicator. */
26775
26893
  confirm: SceneConfirmSchema.nullable().optional()
26776
26894
  })
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-DQZzL0Ri.js");
1
+ const require_dist = require("./dist-BUIpqu3E.js");
2
2
  let node_perf_hooks = require("node:perf_hooks");
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- import { a as COCO_TO_MACRO, i as COCO_80_LABELS, r as AUDIO_MACRO_LABELS, z as hfModelUrl } from "./dist-HhcoV-Ky.mjs";
1
+ import { a as COCO_TO_MACRO, i as COCO_80_LABELS, r as AUDIO_MACRO_LABELS, z as hfModelUrl } from "./dist-BfTf6doa.mjs";
2
2
  import { PerformanceObserver } from "node:perf_hooks";
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-DQZzL0Ri.js");
1
+ const require_dist = require("./dist-BUIpqu3E.js");
2
2
  let node_url = require("node:url");
3
3
  let node_module = require("node:module");
4
4
  let node_path = require("node:path");
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-DQZzL0Ri.js");
6
- const require_lazy_sharp = require("../lazy-sharp-DIC1rpea.js");
5
+ const require_dist = require("../dist-BUIpqu3E.js");
6
+ const require_lazy_sharp = require("../lazy-sharp-BZVhL9Lw.js");
7
7
  let node_path = require("node:path");
8
8
  let node_fs = require("node:fs");
9
9
  //#region src/motion-wasm/wasm-motion-detector.ts
@@ -1,4 +1,4 @@
1
- import { H as motionDetectionCapability, R as evaluateZoneRules, ft as hydrateSchema, st as BaseAddon, ut as DeviceType } from "../dist-HhcoV-Ky.mjs";
1
+ import { H as motionDetectionCapability, R as evaluateZoneRules, ft as hydrateSchema, st as BaseAddon, ut as DeviceType } from "../dist-BfTf6doa.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
3
3
  import { join } from "node:path";
4
4
  import { readFileSync } from "node:fs";
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-DQZzL0Ri.js");
6
- const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-CBOo1oh_.js");
7
- const require_worker_protocol = require("../worker-protocol-DZVGVAPU.js");
5
+ const require_dist = require("../dist-BUIpqu3E.js");
6
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-CGLQP0by.js");
7
+ const require_worker_protocol = require("../worker-protocol-BaLcYcOo.js");
8
8
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
9
- const require_lazy_sharp = require("../lazy-sharp-DIC1rpea.js");
9
+ const require_lazy_sharp = require("../lazy-sharp-BZVhL9Lw.js");
10
10
  const require_remote_restream = require("../remote-restream-BYbAsgUf.js");
11
11
  let sharp = require("sharp");
12
12
  sharp = require_dist.__toESM(sharp);
@@ -1,6 +1,6 @@
1
- import { At as string, Ct as boolean, Dt as number, Et as literal, K as pipelineRunnerCapability, M as deriveDetailCropRect, Mt as EventCategory, Ot as object, St as array, Tt as lazy, U as pickDetailCropConvention, W as pickNativeLeaseOverride, dt as createEvent, gt as nodePin, j as defineCustomActions, k as customAction, s as DEFAULT_DETAIL_CROP_CONVENTION, st as BaseAddon, tt as errMsg, u as DEVICE_BACKEND_TO_FORMAT, xt as _enum } from "../dist-HhcoV-Ky.mjs";
2
- import { c as getStepDefinition, t as attributeStall } from "../event-loop-stall-monitor-CqBEWGSZ.mjs";
3
- import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-BNlLGLBV.mjs";
1
+ import { At as string, Ct as boolean, Dt as number, Et as literal, K as pipelineRunnerCapability, M as deriveDetailCropRect, Mt as EventCategory, Ot as object, St as array, Tt as lazy, U as pickDetailCropConvention, W as pickNativeLeaseOverride, dt as createEvent, gt as nodePin, j as defineCustomActions, k as customAction, s as DEFAULT_DETAIL_CROP_CONVENTION, st as BaseAddon, tt as errMsg, u as DEVICE_BACKEND_TO_FORMAT, xt as _enum } from "../dist-BfTf6doa.mjs";
2
+ import { c as getStepDefinition, t as attributeStall } from "../event-loop-stall-monitor-CmrHj0i9.mjs";
3
+ import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-BdOv9Ujl.mjs";
4
4
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
6
6
  import { i as withDetectionIntent, n as profileForStreamId, t as isRemoteRestream } from "../remote-restream-Ci7RXNGb.mjs";