@camstack/types 1.2.302 → 1.2.304

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5148,7 +5148,7 @@ function tierLabel(family, baseName) {
5148
5148
  }
5149
5149
  function variantLabel(precision, optimization) {
5150
5150
  const parts = [];
5151
- if (optimization === "fast") parts.push("Fast");
5151
+ if (optimization === "test") parts.push("Test");
5152
5152
  parts.push(precision === "int8" ? "Int8" : "Standard");
5153
5153
  return parts.join(" · ");
5154
5154
  }
@@ -5172,7 +5172,7 @@ var PRECISION_ORDER = ["fp32", "int8"];
5172
5172
  /**
5173
5173
  * Fold a flat catalog into the `family → tier → variant` tree. Deterministic
5174
5174
  * ordering: tiers by the canonical size ladder (unknown tiers appended
5175
- * alphabetically), variants standard-before-int8 and fast last.
5175
+ * alphabetically), variants standard-before-int8 and test last.
5176
5176
  */
5177
5177
  function buildModelVariantGroups(models) {
5178
5178
  const byFamily = /* @__PURE__ */ new Map();
@@ -5203,7 +5203,7 @@ function buildModelVariantGroups(models) {
5203
5203
  };
5204
5204
  }).toSorted((a, b) => {
5205
5205
  if (a.resolution !== b.resolution) return (b.resolution ?? Infinity) - (a.resolution ?? Infinity);
5206
- if (a.optimization !== b.optimization) return a.optimization === "fast" ? 1 : -1;
5206
+ if (a.optimization !== b.optimization) return a.optimization === "test" ? 1 : -1;
5207
5207
  return PRECISION_ORDER.indexOf(a.precision) - PRECISION_ORDER.indexOf(b.precision);
5208
5208
  });
5209
5209
  const base = options.find((o) => o.precision === "fp32" && o.optimization === "standard") ?? options[0];
@@ -5416,11 +5416,11 @@ var ModelVariantGroupSchema = zod.z.object({
5416
5416
  /** Quantization axis. Omit ⇒ the fp32 base build. */
5417
5417
  precision: zod.z.enum(["fp32", "int8"]).optional(),
5418
5418
  /**
5419
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
5420
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
5421
- * future performance variants plug into.
5419
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
5420
+ * an alternate training of the same family (Scrypted `relu_test`); chip
5421
+ * label is "Test".
5422
5422
  */
5423
- optimization: zod.z.enum(["standard", "fast"]).optional(),
5423
+ optimization: zod.z.enum(["standard", "test"]).optional(),
5424
5424
  /**
5425
5425
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
5426
5426
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -5495,9 +5495,10 @@ var ModelLicenseRecordSchema = zod.z.object({
5495
5495
  * are per upstream. A persisted custom-model row written when this field was a
5496
5496
  * string still parses — the string is lifted into `{ weights }`.
5497
5497
  *
5498
- * Every licence surface (the admin "Models and licenses" page,
5499
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
5500
- * these records by `scripts/gen-model-licenses.ts` (D661).
5498
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
5499
+ * model table) is GENERATED from these records by
5500
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
5501
+ * `camstack/docs` → `/docs/detection/models`.
5501
5502
  */
5502
5503
  var ModelLicenseSchema = zod.z.preprocess((value) => typeof value === "string" ? { weights: value } : value, ModelLicenseRecordSchema);
5503
5504
  var ModelCatalogEntrySchema = zod.z.object({
@@ -6008,7 +6009,16 @@ var AutomationActionSchema = zod.z.discriminatedUnion("kind", [
6008
6009
  }),
6009
6010
  zod.z.object({
6010
6011
  kind: zod.z.literal("cap"),
6011
- deviceId: zod.z.union([zod.z.number().int(), zod.z.object({ $var: zod.z.string().min(1) })]),
6012
+ /**
6013
+ * One device, several same-family devices (locks / climate family / …),
6014
+ * or `{ $var }` for the device that triggered the run. An array is
6015
+ * fan-out at codegen — each id gets the same cap.method call.
6016
+ */
6017
+ deviceId: zod.z.union([
6018
+ zod.z.number().int(),
6019
+ zod.z.array(zod.z.number().int()).min(1),
6020
+ zod.z.object({ $var: zod.z.string().min(1) })
6021
+ ]),
6012
6022
  cap: zod.z.string().min(1),
6013
6023
  method: zod.z.string().min(1),
6014
6024
  /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
@@ -6171,7 +6181,14 @@ function emitTrigger(trigger, index) {
6171
6181
  function emitAction(action, index) {
6172
6182
  switch (action.kind) {
6173
6183
  case "wait": return ` case ${index}: await sleep(${j(action.seconds * 1e3)}); break`;
6174
- case "cap": return ` case ${index}: {
6184
+ case "cap":
6185
+ if (Array.isArray(action.deviceId)) return ` case ${index}: {
6186
+ for (const deviceId of ${j(action.deviceId)}) {
6187
+ await actuate(deviceId, ${j(action.cap)}, ${j(action.method)}, ${j(action.args ?? {})}, vars)
6188
+ }
6189
+ break
6190
+ }`;
6191
+ return ` case ${index}: {
6175
6192
  const deviceId = ${typeof action.deviceId === "number" ? j(action.deviceId) : `resolveTarget(vars, ${j(action.deviceId.$var)})`}
6176
6193
  await actuate(deviceId, ${j(action.cap)}, ${j(action.method)}, ${j(action.args ?? {})}, vars)
6177
6194
  break
@@ -6405,11 +6422,13 @@ export default function block(ctx: AddonContext) {
6405
6422
  ): Promise<void> {
6406
6423
  const resolved: Record<string, unknown> = {}
6407
6424
  for (const [k, v] of Object.entries(args)) resolved[k] = substitute(v, vars)
6425
+ // Forked-addon ctx.api namespaces are tRPC Proxies over a noop function
6426
+ // (typeof === 'function'), not plain objects — reject only null/undefined.
6408
6427
  const client: unknown = Reflect.get(ctx.api, capToRouterKey(cap))
6409
6428
  const proc: unknown =
6410
- typeof client === 'object' && client !== null ? Reflect.get(client, method) : undefined
6429
+ client !== null && client !== undefined ? Reflect.get(client as object, method) : undefined
6411
6430
  const mutate: unknown =
6412
- typeof proc === 'object' && proc !== null ? Reflect.get(proc, 'mutate') : undefined
6431
+ proc !== null && proc !== undefined ? Reflect.get(proc as object, 'mutate') : undefined
6413
6432
  if (typeof mutate !== 'function') {
6414
6433
  throw new Error('no such device method: ' + cap + '.' + method)
6415
6434
  }
@@ -12441,7 +12460,7 @@ var detectionPipelineCapability = {
12441
12460
  * This matters here more than anywhere else in the repo, because every provider
12442
12461
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
12443
12462
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
12444
- * and `http://admin:hunter2@192.168.50.139/` is a URL a browser accepts. The
12463
+ * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
12445
12464
  * camera's own page will ask for its own login. That is correct, and pre-
12446
12465
  * filling it is the operator's business, not ours.
12447
12466
  *
@@ -17327,9 +17346,15 @@ var modelConvertCapability = {
17327
17346
  * needs the Moleculer broker + the deploy-stage registry, which a forked addon
17328
17347
  * can't reach. `addon-model-studio` drives it via `ctx.api` and owns the
17329
17348
  * per-node availability map.
17349
+ *
17350
+ * The destination is `targetNodeId`, NOT `nodeId`. Cap routers and the
17351
+ * Moleculer tRPC link strip an input field named `nodeId` and use it as a
17352
+ * route pin (resolve the provider ON that node). Naming the destination
17353
+ * `nodeId` routed the call to the agent — which does not host this
17354
+ * singleton — and handed the provider an input with the destination missing.
17330
17355
  */
17331
17356
  var ModelDistributeInputSchema = zod.z.object({
17332
- nodeId: zod.z.string(),
17357
+ targetNodeId: zod.z.string(),
17333
17358
  modelId: zod.z.string(),
17334
17359
  format: zod.z.enum(MODEL_FORMATS),
17335
17360
  entry: ModelCatalogEntrySchema
@@ -21504,12 +21529,33 @@ var NC_ALARM_NONBLOCKING_MAX = 200;
21504
21529
  var NcAlarmDelaySecSchema = zod.z.number().int().min(0).max(600);
21505
21530
  var NcAlarmTriggeredSecSchema = zod.z.number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
21506
21531
  var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
21532
+ /**
21533
+ * What the panel does when a bounded triggered window ends.
21534
+ * - `rearmAfter` — return to the armed mode
21535
+ * - `disableAfter` — auto-disarm
21536
+ * - `doNothing` — stay triggered until a human disarms
21537
+ */
21538
+ var NcAlarmPostTriggeredActionSchema = zod.z.enum([
21539
+ "rearmAfter",
21540
+ "disableAfter",
21541
+ "doNothing"
21542
+ ]);
21507
21543
  /** One mode's OVERRIDES. An absent field inherits the global value (D697). */
21508
21544
  var NcAlarmModeDelaysSchema = zod.z.object({
21509
21545
  mode: AlarmArmModeSchema,
21510
21546
  exitDelaySec: NcAlarmDelaySecSchema.optional(),
21511
21547
  entryDelaySec: NcAlarmDelaySecSchema.optional(),
21512
- triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
21548
+ /**
21549
+ * Duration of `triggered` before {@link postTriggeredAction}. Kept as the
21550
+ * historical field name so older clients still read/write a number.
21551
+ */
21552
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional(),
21553
+ postTriggeredAction: NcAlarmPostTriggeredActionSchema.optional(),
21554
+ /**
21555
+ * When this mode may be armed. Absent / null = always allowed (same as a
21556
+ * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
21557
+ */
21558
+ schedule: NcScheduleSchema.optional()
21513
21559
  });
21514
21560
  var NcAlarmModeDelaysListSchema = zod.z.array(NcAlarmModeDelaysSchema).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
21515
21561
  /**
@@ -21521,7 +21567,10 @@ var NcAlarmModeDelaysEditSchema = zod.z.object({
21521
21567
  mode: AlarmArmModeSchema,
21522
21568
  exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
21523
21569
  entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
21524
- triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
21570
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
21571
+ postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
21572
+ /** Set a schedule, or `null` to clear (mode always allowed again). */
21573
+ schedule: NcScheduleSchema.nullable().optional()
21525
21574
  });
21526
21575
  var NcAlarmModeDelaysEditListSchema = zod.z.array(NcAlarmModeDelaysEditSchema).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
21527
21576
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
@@ -21594,12 +21643,18 @@ var NcAlarmSettingsSchema = zod.z.object({
21594
21643
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
21595
21644
  entryDelaySec: NcAlarmDelaySecSchema,
21596
21645
  /**
21597
- * How long `triggered` lasts before the panel re-arms itself.
21598
- * **0 = until an operator disarms it** — the behaviour before this field
21599
- * existed, and therefore what an untouched install keeps doing.
21646
+ * How long `triggered` lasts before {@link postTriggeredAction} runs.
21647
+ * Ignored when the action is `doNothing`. Historical name kept so older
21648
+ * clients still round-trip a number.
21600
21649
  */
21601
21650
  triggeredDurationSec: NcAlarmTriggeredSecSchema,
21602
21651
  /**
21652
+ * What happens when the triggered window ends. Absent on a blob older than
21653
+ * this field → derived from {@link triggeredDurationSec} (`>0` ⇒ rearmAfter,
21654
+ * else doNothing).
21655
+ */
21656
+ postTriggeredAction: NcAlarmPostTriggeredActionSchema.optional(),
21657
+ /**
21603
21658
  * Deprecated by D630 — every transition is announced. Parsed, never read;
21604
21659
  * remove after one release. Optional so an older admin's patch (which still
21605
21660
  * sends it) parses rather than failing the whole save.
@@ -22745,39 +22800,19 @@ var CLUSTER_MODEL_SCOPED_STEPS = [{
22745
22800
  label: "Face recognition model",
22746
22801
  defaultModelId: "auraface-r100",
22747
22802
  indexName: "the enrolled face gallery",
22748
- options: [
22749
- {
22750
- id: "auraface-r100",
22751
- label: "AuraFace R100"
22752
- },
22753
- {
22754
- id: "arcface-r100",
22755
- label: "ArcFace (ResNet34)"
22756
- },
22757
- {
22758
- id: "inception-resnet-v1",
22759
- label: "Inception ResNet V1"
22760
- }
22761
- ]
22803
+ options: [{
22804
+ id: "auraface-r100",
22805
+ label: "AuraFace R100"
22806
+ }]
22762
22807
  }, {
22763
22808
  stepId: "clip-embedding",
22764
22809
  label: "Semantic search model",
22765
- defaultModelId: "mobileclip-s1",
22810
+ defaultModelId: "siglip2-b16-224",
22766
22811
  indexName: "the object semantic-search index",
22767
- options: [
22768
- {
22769
- id: "mobileclip-s1",
22770
- label: "MobileCLIP S1"
22771
- },
22772
- {
22773
- id: "mobileclip-s2",
22774
- label: "MobileCLIP S2"
22775
- },
22776
- {
22777
- id: "siglip2-b16-224",
22778
- label: "SigLIP2 B/16 (Apache-2.0)"
22779
- }
22780
- ]
22812
+ options: [{
22813
+ id: "siglip2-b16-224",
22814
+ label: "SigLIP2 B/16 (Apache-2.0)"
22815
+ }]
22781
22816
  }];
22782
22817
  /**
22783
22818
  * Store identity of the cluster row inside `pipeline-orchestrator`'s GLOBAL
@@ -37050,7 +37085,7 @@ var LocalInterfaceSchema = zod.z.object({
37050
37085
  name: zod.z.string(),
37051
37086
  family: zod.z.enum(["IPv4", "IPv6"]),
37052
37087
  address: zod.z.string(),
37053
- /** CIDR shorthand (e.g. `192.168.1.10/24`). Empty when OS doesn't expose. */
37088
+ /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
37054
37089
  cidr: zod.z.string(),
37055
37090
  /** OS netmask. Stable across calls so the SDK can hash on it. */
37056
37091
  netmask: zod.z.string(),
@@ -37249,7 +37284,7 @@ var localNetworkCapability = {
37249
37284
  * every client a second authority on a socket only the hub binds. A viewer
37250
37285
  * configured with a port-less public URL (`https://camstack.example.top`)
37251
37286
  * infers 443 from the scheme, asks with 443, and was handed
37252
- * `https://192.168.1.9:443` for a hub listening on 4443. That candidate
37287
+ * `https://192.168.x.x:443` for a hub listening on 4443. That candidate
37253
37288
  * cannot ever answer, and losing its race reads in the log exactly like
37254
37289
  * "the LAN was tried and it was slower" — so an operator sitting on his own
37255
37290
  * WiFi stayed on the public tunnel for weeks, with the LAN candidate born
@@ -37708,7 +37743,7 @@ var MeshPeerSchema = zod.z.object({
37708
37743
  tags: zod.z.array(zod.z.string()).readonly(),
37709
37744
  /** True when the peer advertises itself as an exit-node candidate. */
37710
37745
  exitNodeOption: zod.z.boolean(),
37711
- /** Subnet routes the peer advertises (e.g. `["192.168.1.0/24"]`). */
37746
+ /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
37712
37747
  advertisedRoutes: zod.z.array(zod.z.string()).readonly(),
37713
37748
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
37714
37749
  userLogin: zod.z.string().nullable(),
@@ -39386,7 +39421,13 @@ var OsdOverlaySchema = zod.z.object({
39386
39421
  */
39387
39422
  availablePositions: zod.z.array(OsdPositionEnum).readonly(),
39388
39423
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
39389
- readOnly: zod.z.boolean().optional()
39424
+ readOnly: zod.z.boolean().optional(),
39425
+ /**
39426
+ * Firmware text ceiling for this overlay. Absent = no known limit.
39427
+ * The OSD manager truncates here on every write — never stores its own
39428
+ * copy on the binding.
39429
+ */
39430
+ maxCharacters: zod.z.number().int().positive().optional()
39390
39431
  });
39391
39432
  var OsdStatusSchema = zod.z.object({ overlays: zod.z.array(OsdOverlaySchema).readonly() });
39392
39433
  var OsdOverlayPatchSchema = zod.z.object({
@@ -39504,7 +39545,9 @@ var OsdTemplateBindingSchema = zod.z.object({
39504
39545
  valuePath: zod.z.string().min(1).max(64),
39505
39546
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
39506
39547
  displayUnit: zod.z.string().max(16).optional(),
39507
- maxDecimals: zod.z.number().int().min(0).max(4).default(1)
39548
+ maxDecimals: zod.z.number().int().min(0).max(4).default(1),
39549
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
39550
+ valueMap: zod.z.record(zod.z.string(), zod.z.string()).optional()
39508
39551
  });
39509
39552
  /**
39510
39553
  * A named template: bindings (alias → leaf field) + a parser that
@@ -39554,18 +39597,11 @@ var OsdSlotBindingSchema = zod.z.object({
39554
39597
  source: OsdSourceSchema,
39555
39598
  /** `${value}` and `${unit}` are substituted; every occurrence. */
39556
39599
  template: zod.z.string().max(96).default("${value}"),
39557
- /** Truncate with an ellipsis past this length. Absent = no limit. */
39558
- maxCharacters: zod.z.number().int().min(4).max(64).optional(),
39559
39600
  /**
39560
39601
  * Decimal places for a numeric value. `0` yields an integer — the
39561
39602
  * documented workaround for firmwares that reject `.` in overlay text.
39562
39603
  */
39563
39604
  maxDecimals: zod.z.number().int().min(0).max(4).default(1),
39564
- /**
39565
- * Appended via `${unit}` when no unit conversion produces a label.
39566
- * Prefer `source.displayUnit` for converted device-state values.
39567
- */
39568
- unitLabel: zod.z.string().max(8).optional(),
39569
39605
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
39570
39606
  valueMap: zod.z.record(zod.z.string(), zod.z.string()).optional(),
39571
39607
  /** Time windows in which the slot is shown. Absent = always. */
@@ -39574,9 +39610,7 @@ var OsdSlotBindingSchema = zod.z.object({
39574
39610
  * Display gate, in the notification centre's condition vocabulary.
39575
39611
  * Only the keys reported by `getConditionSupport` are accepted.
39576
39612
  */
39577
- conditions: NcConditionsSchema.optional(),
39578
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
39579
- fallbackText: zod.z.string().max(64).default("")
39613
+ conditions: NcConditionsSchema.optional()
39580
39614
  });
39581
39615
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
39582
39616
  var OsdSlotViewSchema = zod.z.object({
@@ -57700,6 +57734,62 @@ var DEVICE_DO_ACTIONS = [
57700
57734
  method: "stop",
57701
57735
  args: {}
57702
57736
  },
57737
+ {
57738
+ id: "valve.open",
57739
+ label: "Open valve",
57740
+ cap: "valve",
57741
+ method: "open",
57742
+ args: {}
57743
+ },
57744
+ {
57745
+ id: "valve.close",
57746
+ label: "Close valve",
57747
+ cap: "valve",
57748
+ method: "close",
57749
+ args: {}
57750
+ },
57751
+ {
57752
+ id: "valve.stop",
57753
+ label: "Stop valve",
57754
+ cap: "valve",
57755
+ method: "stop",
57756
+ args: {}
57757
+ },
57758
+ {
57759
+ id: "humidifier.on",
57760
+ label: "Humidifier on",
57761
+ cap: "humidifier",
57762
+ method: "setOn",
57763
+ args: { on: true }
57764
+ },
57765
+ {
57766
+ id: "humidifier.off",
57767
+ label: "Humidifier off",
57768
+ cap: "humidifier",
57769
+ method: "setOn",
57770
+ args: { on: false }
57771
+ },
57772
+ {
57773
+ id: "waterHeater.off",
57774
+ label: "Water heater off",
57775
+ cap: "water-heater",
57776
+ method: "setOperationMode",
57777
+ args: { mode: "off" }
57778
+ },
57779
+ {
57780
+ id: "waterHeater.awayOn",
57781
+ label: "Water heater away on",
57782
+ cap: "water-heater",
57783
+ method: "setAway",
57784
+ args: { on: true }
57785
+ },
57786
+ {
57787
+ id: "waterHeater.awayOff",
57788
+ label: "Water heater away off",
57789
+ cap: "water-heater",
57790
+ method: "setAway",
57791
+ args: { on: false }
57792
+ },
57703
57793
  {
57704
57794
  id: "climate.off",
57705
57795
  label: "Climate off",
@@ -57770,6 +57860,115 @@ var DEVICE_DO_ACTIONS = [
57770
57860
  method: "returnToBase",
57771
57861
  args: {}
57772
57862
  },
57863
+ {
57864
+ id: "lawnMower.start",
57865
+ label: "Start mowing",
57866
+ cap: "lawn-mower-control",
57867
+ method: "startMowing",
57868
+ args: {}
57869
+ },
57870
+ {
57871
+ id: "lawnMower.pause",
57872
+ label: "Pause mower",
57873
+ cap: "lawn-mower-control",
57874
+ method: "pause",
57875
+ args: {}
57876
+ },
57877
+ {
57878
+ id: "lawnMower.dock",
57879
+ label: "Dock mower",
57880
+ cap: "lawn-mower-control",
57881
+ method: "dock",
57882
+ args: {}
57883
+ },
57884
+ {
57885
+ id: "media.play",
57886
+ label: "Play",
57887
+ cap: "media-player",
57888
+ method: "play",
57889
+ args: {}
57890
+ },
57891
+ {
57892
+ id: "media.pause",
57893
+ label: "Pause media",
57894
+ cap: "media-player",
57895
+ method: "pause",
57896
+ args: {}
57897
+ },
57898
+ {
57899
+ id: "media.stop",
57900
+ label: "Stop media",
57901
+ cap: "media-player",
57902
+ method: "stop",
57903
+ args: {}
57904
+ },
57905
+ {
57906
+ id: "media.next",
57907
+ label: "Next track",
57908
+ cap: "media-player",
57909
+ method: "next",
57910
+ args: {}
57911
+ },
57912
+ {
57913
+ id: "media.previous",
57914
+ label: "Previous track",
57915
+ cap: "media-player",
57916
+ method: "previous",
57917
+ args: {}
57918
+ },
57919
+ {
57920
+ id: "script.run",
57921
+ label: "Run script",
57922
+ cap: "script-runner",
57923
+ method: "run",
57924
+ args: {}
57925
+ },
57926
+ {
57927
+ id: "script.stop",
57928
+ label: "Stop script",
57929
+ cap: "script-runner",
57930
+ method: "stop",
57931
+ args: {}
57932
+ },
57933
+ {
57934
+ id: "haAutomation.enable",
57935
+ label: "Enable automation",
57936
+ cap: "automation-control",
57937
+ method: "enable",
57938
+ args: {}
57939
+ },
57940
+ {
57941
+ id: "haAutomation.disable",
57942
+ label: "Disable automation",
57943
+ cap: "automation-control",
57944
+ method: "disable",
57945
+ args: {}
57946
+ },
57947
+ {
57948
+ id: "haAutomation.trigger",
57949
+ label: "Trigger automation",
57950
+ cap: "automation-control",
57951
+ method: "trigger",
57952
+ args: {}
57953
+ },
57954
+ {
57955
+ id: "petFeeder.feed",
57956
+ label: "Feed",
57957
+ cap: "pet-feeder",
57958
+ method: "feed",
57959
+ openArgs: [{
57960
+ key: "grams",
57961
+ label: "Grams",
57962
+ kind: "number"
57963
+ }]
57964
+ },
57965
+ {
57966
+ id: "petFeeder.callPet",
57967
+ label: "Call pet",
57968
+ cap: "pet-feeder",
57969
+ method: "callPet",
57970
+ args: {}
57971
+ },
57773
57972
  {
57774
57973
  id: "ptz.goHome",
57775
57974
  label: "PTZ go home",
@@ -57997,6 +58196,94 @@ function bakedArgsEqual(action, args) {
57997
58196
  return argsEqual(action.args, args);
57998
58197
  }
57999
58198
  /**
58199
+ * Catalogue caps a `DeviceType` is expected to offer in the Do picker.
58200
+ *
58201
+ * Exhaustive over {@link DeviceType}: adding a new enum member without an
58202
+ * entry fails the TypeScript build here (same pattern as
58203
+ * {@link DEVICE_TYPE_CONTROL_KIND}). An empty list is a deliberate choice
58204
+ * for read-only / non-actuatable types — never "forgotten".
58205
+ *
58206
+ * Camera accessories (ptz, privacy-mask, …) are listed on Camera even though
58207
+ * a given camera may bind only a subset; {@link actionsForBoundCaps} still
58208
+ * filters to what the device actually binds.
58209
+ */
58210
+ var DEVICE_TYPE_DO_CAPS = {
58211
+ [require_err_msg.DeviceType.Camera]: [
58212
+ "ptz",
58213
+ "ptz-autotrack",
58214
+ "privacy-mask",
58215
+ "day-night",
58216
+ "reboot",
58217
+ "motion-trigger"
58218
+ ],
58219
+ [require_err_msg.DeviceType.Hub]: [],
58220
+ [require_err_msg.DeviceType.Light]: ["switch", "brightness"],
58221
+ [require_err_msg.DeviceType.Siren]: ["switch", "motion-trigger"],
58222
+ [require_err_msg.DeviceType.Switch]: ["switch", "motion-trigger"],
58223
+ [require_err_msg.DeviceType.Sensor]: [],
58224
+ [require_err_msg.DeviceType.Thermostat]: ["climate-control"],
58225
+ [require_err_msg.DeviceType.Climate]: ["climate-control"],
58226
+ [require_err_msg.DeviceType.Button]: ["button"],
58227
+ [require_err_msg.DeviceType.EventEmitter]: [],
58228
+ [require_err_msg.DeviceType.Update]: [],
58229
+ [require_err_msg.DeviceType.Generic]: [],
58230
+ [require_err_msg.DeviceType.Notifier]: [],
58231
+ [require_err_msg.DeviceType.Script]: ["script-runner"],
58232
+ [require_err_msg.DeviceType.Automation]: ["automation-control"],
58233
+ [require_err_msg.DeviceType.Lock]: ["lock-control"],
58234
+ [require_err_msg.DeviceType.Cover]: ["cover"],
58235
+ [require_err_msg.DeviceType.Valve]: ["valve"],
58236
+ [require_err_msg.DeviceType.Humidifier]: ["humidifier"],
58237
+ [require_err_msg.DeviceType.WaterHeater]: ["water-heater"],
58238
+ [require_err_msg.DeviceType.Fan]: ["fan-control", "switch"],
58239
+ [require_err_msg.DeviceType.MediaPlayer]: ["media-player"],
58240
+ [require_err_msg.DeviceType.AlarmPanel]: ["alarm-panel"],
58241
+ [require_err_msg.DeviceType.Control]: [],
58242
+ [require_err_msg.DeviceType.Presence]: [],
58243
+ [require_err_msg.DeviceType.Weather]: [],
58244
+ [require_err_msg.DeviceType.Vacuum]: ["vacuum-control"],
58245
+ [require_err_msg.DeviceType.LawnMower]: ["lawn-mower-control"],
58246
+ [require_err_msg.DeviceType.Container]: [],
58247
+ [require_err_msg.DeviceType.Image]: [],
58248
+ [require_err_msg.DeviceType.PetFeeder]: ["pet-feeder"]
58249
+ };
58250
+ /**
58251
+ * Whether a device type belongs in a Do / automation action device picker.
58252
+ *
58253
+ * Containers stay in {@link DEVICE_TYPE_DO_CAPS} (empty, for exhaustiveness)
58254
+ * but must never appear as selectable targets — actuate the children instead.
58255
+ */
58256
+ function isDoPickerDeviceType(type) {
58257
+ return type !== require_err_msg.DeviceType.Container;
58258
+ }
58259
+ /**
58260
+ * Do-picker family id — devices that share one may be multi-selected for
58261
+ * the same action (several locks, the climate family, cover+valve, …).
58262
+ *
58263
+ * Distinct from {@link DeviceControlKind}: humidifier / water-heater keep
58264
+ * their own control widgets but author with climate siblings.
58265
+ */
58266
+ function deviceDoFamily(type) {
58267
+ switch (type) {
58268
+ case require_err_msg.DeviceType.Climate:
58269
+ case require_err_msg.DeviceType.Thermostat:
58270
+ case require_err_msg.DeviceType.Humidifier:
58271
+ case require_err_msg.DeviceType.WaterHeater: return "climate-family";
58272
+ case require_err_msg.DeviceType.Cover:
58273
+ case require_err_msg.DeviceType.Valve: return "cover-family";
58274
+ case require_err_msg.DeviceType.Switch:
58275
+ case require_err_msg.DeviceType.Siren:
58276
+ case require_err_msg.DeviceType.Light: return "switch-family";
58277
+ case require_err_msg.DeviceType.Vacuum:
58278
+ case require_err_msg.DeviceType.LawnMower: return "robot-family";
58279
+ default: return type;
58280
+ }
58281
+ }
58282
+ /** True when two device types may share one multi-target Do step. */
58283
+ function sameDoFamily(leftType, rightType) {
58284
+ return deviceDoFamily(leftType) === deviceDoFamily(rightType);
58285
+ }
58286
+ /**
58000
58287
  * Actions offered for a device that binds the given caps.
58001
58288
  *
58002
58289
  * Only catalogue entries whose cap is bound AND still actuatable in
@@ -58007,6 +58294,50 @@ function actionsForBoundCaps(boundCaps) {
58007
58294
  const set = new Set(boundCaps);
58008
58295
  return DEVICE_DO_ACTIONS.filter((action) => set.has(action.cap) && isDoActionActuatable(action));
58009
58296
  }
58297
+ /**
58298
+ * Catalogue actions for a wire `DeviceType` string — the fallback when
58299
+ * bindings have not answered yet (or answered empty for a typed actuator).
58300
+ * Unknown type strings → empty.
58301
+ */
58302
+ function actionsForDeviceType(type) {
58303
+ if (!Object.values(require_err_msg.DeviceType).includes(type)) return [];
58304
+ return actionsForBoundCaps(DEVICE_TYPE_DO_CAPS[type]);
58305
+ }
58306
+ /**
58307
+ * Union of bound-cap actions with the type's expected catalogue caps.
58308
+ *
58309
+ * Bindings win for filtering (a lock without `lock-control` bound still
58310
+ * offers nothing from bindings alone); the type map fills gaps when the
58311
+ * binding read is empty so a Lock / Valve / Climate never shows
58312
+ * "No actions for this device" solely because getBindings lagged.
58313
+ */
58314
+ function actionsForDevice(input) {
58315
+ const fromBound = input.boundCaps !== void 0 && input.boundCaps.length > 0 ? actionsForBoundCaps(input.boundCaps) : [];
58316
+ if (fromBound.length > 0) return fromBound;
58317
+ if (input.deviceType !== void 0 && input.deviceType.length > 0) return actionsForDeviceType(input.deviceType);
58318
+ return [];
58319
+ }
58320
+ /**
58321
+ * Intersection of {@link actionsForDevice} across several targets — what a
58322
+ * multi-select same-family Do step may offer.
58323
+ */
58324
+ function actionsForDevices(targets) {
58325
+ if (targets.length === 0) return [];
58326
+ let common = null;
58327
+ for (const target of targets) {
58328
+ const offered = actionsForDevice({
58329
+ boundCaps: target.boundCaps,
58330
+ deviceType: target.deviceType
58331
+ });
58332
+ if (common === null) {
58333
+ common = offered;
58334
+ continue;
58335
+ }
58336
+ const ids = new Set(offered.map((a) => a.id));
58337
+ common = common.filter((a) => ids.has(a.id));
58338
+ }
58339
+ return common ?? [];
58340
+ }
58010
58341
  /** The whole catalogue (still actuatable) — for a `{$var}` automation target. */
58011
58342
  function allDoActions() {
58012
58343
  return DEVICE_DO_ACTIONS.filter(isDoActionActuatable);
@@ -67333,6 +67664,10 @@ function bindingPullsAlarmTrigger(binding, sequenceActionsOf) {
67333
67664
  if (steps === void 0) return false;
67334
67665
  return steps.some((step) => step.kind === "cap" && step.cap === ALARM_PANEL_CAP && step.method === ALARM_PANEL_TRIGGER_METHOD);
67335
67666
  }
67667
+ /** True when the rule's deviceState gate names any `armed_*` word. */
67668
+ function ruleGatedOnArmedState(rule) {
67669
+ return (rule.conditions.deviceState?.states ?? []).some((s) => s.trim().toLowerCase().startsWith(ARMED_WORD_PREFIX));
67670
+ }
67336
67671
  /**
67337
67672
  * A rule belongs to the alarm when its `deviceState` gate names ANY device's
67338
67673
  * `armed_*` word, or an on-match binding pulls the alarm panel's trigger
@@ -67340,10 +67675,19 @@ function bindingPullsAlarmTrigger(binding, sequenceActionsOf) {
67340
67675
  * escalation.
67341
67676
  */
67342
67677
  function ruleBelongsToAlarm(rule) {
67343
- if ((rule.conditions.deviceState?.states ?? []).some((s) => s.trim().toLowerCase().startsWith(ARMED_WORD_PREFIX))) return true;
67678
+ if (ruleGatedOnArmedState(rule)) return true;
67344
67679
  for (const binding of rule.actions?.onTrigger ?? []) if (bindingPullsAlarmTrigger(binding, rule.sequenceActionsOf)) return true;
67345
67680
  return false;
67346
67681
  }
67682
+ /**
67683
+ * A rule gated on `armed_*` auto-triggers the CamStack `alarm-panel` on match
67684
+ * — no `onTrigger` sequence required. Sirens are never part of this path.
67685
+ * An explicit `alarm-panel.trigger` binding without an armed gate stays
67686
+ * explicit actuation only ({@link ruleBelongsToAlarm}).
67687
+ */
67688
+ function ruleAutoTriggersAlarm(rule) {
67689
+ return ruleGatedOnArmedState(rule);
67690
+ }
67347
67691
  function isOpeningKind(kind) {
67348
67692
  const k = kind.trim().toLowerCase();
67349
67693
  return NC_ALARM_OPENING_EVENT_KINDS.some((opening) => opening === k);
@@ -67409,6 +67753,14 @@ var NC_ALARM_DELAY_FIELDS = [
67409
67753
  "entryDelaySec",
67410
67754
  "triggeredDurationSec"
67411
67755
  ];
67756
+ /**
67757
+ * Derive the post-triggered action from a stored blob that may predate the field:
67758
+ * a positive duration meant re-arm; zero/absent meant stay triggered.
67759
+ */
67760
+ function derivePostTriggeredAction(action, triggeredDurationSec) {
67761
+ if (action !== void 0) return action;
67762
+ return triggeredDurationSec > 0 ? "rearmAfter" : "doNothing";
67763
+ }
67412
67764
  /** The mode's value when it overrides the field, else the global one. */
67413
67765
  function pick(override, global) {
67414
67766
  return override === void 0 ? {
@@ -67425,14 +67777,19 @@ function resolveModeDelays(settings, mode) {
67425
67777
  const exit = pick(entry?.exitDelaySec, settings.exitDelaySec);
67426
67778
  const entryDelay = pick(entry?.entryDelaySec, settings.entryDelaySec);
67427
67779
  const triggered = pick(entry?.triggeredDurationSec, settings.triggeredDurationSec);
67780
+ const actionOverride = entry?.postTriggeredAction;
67781
+ const actionSource = actionOverride !== void 0 ? "mode" : "default";
67782
+ const postTriggeredAction = derivePostTriggeredAction(actionOverride ?? settings.postTriggeredAction, triggered.value);
67428
67783
  return {
67429
67784
  exitDelaySec: exit.value,
67430
67785
  entryDelaySec: entryDelay.value,
67431
67786
  triggeredDurationSec: triggered.value,
67787
+ postTriggeredAction,
67432
67788
  source: {
67433
67789
  exitDelaySec: exit.source,
67434
67790
  entryDelaySec: entryDelay.source,
67435
- triggeredDurationSec: triggered.source
67791
+ triggeredDurationSec: triggered.source,
67792
+ postTriggeredAction: actionSource
67436
67793
  }
67437
67794
  };
67438
67795
  }
@@ -67441,6 +67798,29 @@ function edited(current, edit) {
67441
67798
  if (edit === void 0) return current;
67442
67799
  return edit === null ? void 0 : edit;
67443
67800
  }
67801
+ function editedAction(current, edit) {
67802
+ if (edit === void 0) return current;
67803
+ return edit === null ? void 0 : edit;
67804
+ }
67805
+ function editedSchedule(current, edit) {
67806
+ if (edit === void 0) return current;
67807
+ return edit === null ? void 0 : edit;
67808
+ }
67809
+ function sameSchedule(a, b) {
67810
+ if (a === void 0 && b === void 0) return true;
67811
+ if (a === void 0 || b === void 0) return false;
67812
+ if (a.invert !== b.invert || a.timezone !== b.timezone) return false;
67813
+ if (a.windows.length !== b.windows.length) return false;
67814
+ for (let i = 0; i < a.windows.length; i++) {
67815
+ const wa = a.windows[i];
67816
+ const wb = b.windows[i];
67817
+ if (wa === void 0 || wb === void 0) return false;
67818
+ if (wa.startMinute !== wb.startMinute || wa.endMinute !== wb.endMinute) return false;
67819
+ if (wa.days.length !== wb.days.length) return false;
67820
+ for (let d = 0; d < wa.days.length; d++) if (wa.days[d] !== wb.days[d]) return false;
67821
+ }
67822
+ return true;
67823
+ }
67444
67824
  /**
67445
67825
  * Apply per-field edits to the stored overrides. Returns new arrays, never mutates the input;
67446
67826
  * an entry with no field left is dropped (the mode inherits everything again).
@@ -67454,13 +67834,17 @@ function applyModeDelaysEdits(current, edits) {
67454
67834
  const exit = edited(base.exitDelaySec, edit.exitDelaySec);
67455
67835
  const entry = edited(base.entryDelaySec, edit.entryDelaySec);
67456
67836
  const triggered = edited(base.triggeredDurationSec, edit.triggeredDurationSec);
67837
+ const action = editedAction(base.postTriggeredAction, edit.postTriggeredAction);
67838
+ const schedule = editedSchedule(base.schedule, edit.schedule);
67457
67839
  if (exit !== void 0) next.exitDelaySec = exit;
67458
67840
  if (entry !== void 0) next.entryDelaySec = entry;
67459
67841
  if (triggered !== void 0) next.triggeredDurationSec = triggered;
67842
+ if (action !== void 0) next.postTriggeredAction = action;
67843
+ if (schedule !== void 0) next.schedule = schedule;
67460
67844
  if (at >= 0) out[at] = next;
67461
67845
  else out.push(next);
67462
67846
  }
67463
- return out.filter((e) => e.exitDelaySec !== void 0 || e.entryDelaySec !== void 0 || e.triggeredDurationSec !== void 0);
67847
+ return out.filter((e) => e.exitDelaySec !== void 0 || e.entryDelaySec !== void 0 || e.triggeredDurationSec !== void 0 || e.postTriggeredAction !== void 0 || e.schedule !== void 0);
67464
67848
  }
67465
67849
  /**
67466
67850
  * Put ONE device on, or take it off, ONE mode's device-id list. A no-op answers
@@ -67588,6 +67972,7 @@ function alarmPatchLanded(patch, returned) {
67588
67972
  if (patch.exitDelaySec !== void 0 && patch.exitDelaySec !== returned.exitDelaySec) return false;
67589
67973
  if (patch.entryDelaySec !== void 0 && patch.entryDelaySec !== returned.entryDelaySec) return false;
67590
67974
  if (patch.triggeredDurationSec !== void 0 && patch.triggeredDurationSec !== returned.triggeredDurationSec) return false;
67975
+ if (patch.postTriggeredAction !== void 0 && patch.postTriggeredAction !== derivePostTriggeredAction(returned.postTriggeredAction, returned.triggeredDurationSec)) return false;
67591
67976
  if (patch.announceTargets !== void 0 && !sameSet(patch.announceTargets, returned.announceTargets)) return false;
67592
67977
  if (patch.nonBlocking !== void 0 && !sameLists(patch.nonBlocking, returned.nonBlocking ?? [])) return false;
67593
67978
  if (patch.blocking !== void 0 && !sameLists(patch.blocking, returned.blocking ?? [])) return false;
@@ -67600,6 +67985,14 @@ function alarmPatchLanded(patch, returned) {
67600
67985
  const got = fieldOf(entry, field);
67601
67986
  if (want === null ? got !== void 0 : got !== want) return false;
67602
67987
  }
67988
+ if (edit.postTriggeredAction !== void 0) {
67989
+ const got = entry?.postTriggeredAction;
67990
+ if (edit.postTriggeredAction === null ? got !== void 0 : got !== edit.postTriggeredAction) return false;
67991
+ }
67992
+ if (edit.schedule !== void 0) {
67993
+ const got = entry?.schedule;
67994
+ if (edit.schedule === null ? got !== void 0 : !sameSchedule(got, edit.schedule)) return false;
67995
+ }
67603
67996
  }
67604
67997
  if (patch.nonBlockingEdit !== void 0) {
67605
67998
  const e = patch.nonBlockingEdit;
@@ -67620,11 +68013,12 @@ function alarmPatchLanded(patch, returned) {
67620
68013
  /** Stable id of the always-present Default profile (migrated from flat settings). */
67621
68014
  var NC_ALARM_DEFAULT_PROFILE_ID = "default";
67622
68015
  var NC_ALARM_DEFAULT_PROFILE_NAME = "Default";
67623
- /** Stock delays — same numbers the panel shipped with before any editor existed. */
68016
+ /** Stock delays — re-arm 10 s after trigger (inherited by every mode). */
67624
68017
  var NC_ALARM_SYSTEM_DEFAULT_DELAYS = {
67625
68018
  exitDelaySec: 30,
67626
68019
  entryDelaySec: 20,
67627
- triggeredDurationSec: 0
68020
+ triggeredDurationSec: 10,
68021
+ postTriggeredAction: "rearmAfter"
67628
68022
  };
67629
68023
  /** Empty memberships + stock delays + no announce targets. */
67630
68024
  function ncAlarmSystemDefaultSettings() {
@@ -67646,6 +68040,7 @@ function cloneAlarmSettings(settings) {
67646
68040
  exitDelaySec: settings.exitDelaySec,
67647
68041
  entryDelaySec: settings.entryDelaySec,
67648
68042
  triggeredDurationSec: settings.triggeredDurationSec,
68043
+ ...settings.postTriggeredAction !== void 0 ? { postTriggeredAction: settings.postTriggeredAction } : {},
67649
68044
  ...settings.announceArm !== void 0 ? { announceArm: settings.announceArm } : {},
67650
68045
  announceTargets: [...settings.announceTargets],
67651
68046
  nonBlocking: settings.nonBlocking.map((l) => ({
@@ -67660,7 +68055,22 @@ function cloneAlarmSettings(settings) {
67660
68055
  mode: l.mode,
67661
68056
  deviceIds: [...l.deviceIds]
67662
68057
  })),
67663
- modeDelays: settings.modeDelays.map((e) => ({ ...e }))
68058
+ modeDelays: settings.modeDelays.map((e) => ({
68059
+ mode: e.mode,
68060
+ ...e.exitDelaySec !== void 0 ? { exitDelaySec: e.exitDelaySec } : {},
68061
+ ...e.entryDelaySec !== void 0 ? { entryDelaySec: e.entryDelaySec } : {},
68062
+ ...e.triggeredDurationSec !== void 0 ? { triggeredDurationSec: e.triggeredDurationSec } : {},
68063
+ ...e.postTriggeredAction !== void 0 ? { postTriggeredAction: e.postTriggeredAction } : {},
68064
+ ...e.schedule !== void 0 ? { schedule: {
68065
+ windows: e.schedule.windows.map((w) => ({
68066
+ days: [...w.days],
68067
+ startMinute: w.startMinute,
68068
+ endMinute: w.endMinute
68069
+ })),
68070
+ ...e.schedule.timezone !== void 0 ? { timezone: e.schedule.timezone } : {},
68071
+ ...e.schedule.invert === true ? { invert: true } : {}
68072
+ } } : {}
68073
+ }))
67664
68074
  };
67665
68075
  }
67666
68076
  /**
@@ -68411,7 +68821,7 @@ var NC_TEMPLATE_VARS = [
68411
68821
  {
68412
68822
  name: "devices",
68413
68823
  label: "Devices",
68414
- description: "node-inference-unavailable: the affected cameras, comma-joined. Alarm arm / refusal: HOW MANY devices are armed (or open).",
68824
+ description: "node-inference-unavailable: the affected cameras, comma-joined. Alarm arm / arming / refusal: HOW MANY devices are armed (or open).",
68415
68825
  example: "Ingresso, Garage",
68416
68826
  group: "system",
68417
68827
  families: ["rule"],
@@ -68420,6 +68830,7 @@ var NC_TEMPLATE_VARS = [
68420
68830
  systemEventKinds: [
68421
68831
  "node-inference-unavailable",
68422
68832
  "alarm-armed",
68833
+ "alarm-arming",
68423
68834
  "alarm-arm-refused"
68424
68835
  ]
68425
68836
  },
@@ -68640,18 +69051,18 @@ var NC_TEMPLATE_VARS = [
68640
69051
  {
68641
69052
  name: "rules",
68642
69053
  label: "Covering rules",
68643
- description: "How many enabled rules the armed mode gates.",
69054
+ description: "How many enabled rules the armed / arming mode gates.",
68644
69055
  example: "2",
68645
69056
  group: "system",
68646
69057
  families: ["rule"],
68647
69058
  fields: [...RULE_TEXT],
68648
69059
  kinds: ["system"],
68649
- systemEventKinds: ["alarm-armed"]
69060
+ systemEventKinds: ["alarm-armed", "alarm-arming"]
68650
69061
  },
68651
69062
  {
68652
69063
  name: "names",
68653
69064
  label: "Device names",
68654
- description: "Armed: the devices armed. Arming: the devices this mode cannot arm. Refusal: the open sensors.",
69065
+ description: "Armed / arming: the Active devices (or every skipped name when none are Active). Refusal: the open sensors.",
68655
69066
  example: "Ingresso, Garage",
68656
69067
  group: "system",
68657
69068
  families: ["rule"],
@@ -68672,7 +69083,29 @@ var NC_TEMPLATE_VARS = [
68672
69083
  families: ["rule"],
68673
69084
  fields: [...RULE_TEXT],
68674
69085
  kinds: ["system"],
68675
- systemEventKinds: ["alarm-armed"]
69086
+ systemEventKinds: ["alarm-armed", "alarm-arming"]
69087
+ },
69088
+ {
69089
+ name: "active",
69090
+ label: "Active count",
69091
+ description: "How many named devices the armed / arming mode is watching (title: n attivi / n active).",
69092
+ example: "3",
69093
+ group: "system",
69094
+ families: ["rule"],
69095
+ fields: [...RULE_TEXT],
69096
+ kinds: ["system"],
69097
+ systemEventKinds: ["alarm-armed", "alarm-arming"]
69098
+ },
69099
+ {
69100
+ name: "skipped",
69101
+ label: "Skipped count",
69102
+ description: "How many named devices the mode cannot arm — muted, detection off, offline (title: m saltati).",
69103
+ example: "1",
69104
+ group: "system",
69105
+ families: ["rule"],
69106
+ fields: [...RULE_TEXT],
69107
+ kinds: ["system"],
69108
+ systemEventKinds: ["alarm-armed", "alarm-arming"]
68676
69109
  },
68677
69110
  {
68678
69111
  name: "bypassedNames",
@@ -72485,6 +72918,7 @@ exports.DEVICE_SETTINGS_CONTRIBUTION_METHODS = require_sleep.DEVICE_SETTINGS_CON
72485
72918
  exports.DEVICE_STATE_READERS = DEVICE_STATE_READERS;
72486
72919
  exports.DEVICE_STATUS_METHOD = require_sleep.DEVICE_STATUS_METHOD;
72487
72920
  exports.DEVICE_TYPE_CONTROL_KIND = DEVICE_TYPE_CONTROL_KIND;
72921
+ exports.DEVICE_TYPE_DO_CAPS = DEVICE_TYPE_DO_CAPS;
72488
72922
  exports.DEVICE_TYPE_INFO = DEVICE_TYPE_INFO;
72489
72923
  exports.DISPLAY_ICON_GROUPS = DISPLAY_ICON_GROUPS;
72490
72924
  exports.DISPLAY_ICON_KEYS = DISPLAY_ICON_KEYS;
@@ -72989,6 +73423,7 @@ exports.NcAlarmModeDelaysSchema = NcAlarmModeDelaysSchema;
72989
73423
  exports.NcAlarmModeDeviceListSchema = NcAlarmModeDeviceListSchema;
72990
73424
  exports.NcAlarmNonBlockingEditSchema = NcAlarmNonBlockingEditSchema;
72991
73425
  exports.NcAlarmNonBlockingSchema = NcAlarmNonBlockingSchema;
73426
+ exports.NcAlarmPostTriggeredActionSchema = NcAlarmPostTriggeredActionSchema;
72992
73427
  exports.NcAlarmProfileIdInputSchema = NcAlarmProfileIdInputSchema;
72993
73428
  exports.NcAlarmProfileMetaSchema = NcAlarmProfileMetaSchema;
72994
73429
  exports.NcAlarmProfilesViewSchema = NcAlarmProfilesViewSchema;
@@ -73573,6 +74008,9 @@ exports.__resetLogChannelRegistryForTests = __resetLogChannelRegistryForTests;
73573
74008
  exports.accessoriesCapability = accessoriesCapability;
73574
74009
  exports.accessoryStableId = accessoryStableId;
73575
74010
  exports.actionsForBoundCaps = actionsForBoundCaps;
74011
+ exports.actionsForDevice = actionsForDevice;
74012
+ exports.actionsForDeviceType = actionsForDeviceType;
74013
+ exports.actionsForDevices = actionsForDevices;
73576
74014
  exports.activateAlarmProfile = activateAlarmProfile;
73577
74015
  exports.addonPagesCapability = addonPagesCapability;
73578
74016
  exports.addonPagesSourceCapability = addonPagesSourceCapability;
@@ -73738,6 +74176,7 @@ exports.deleteAlarmProfile = deleteAlarmProfile;
73738
74176
  exports.deriveBatteryPresence = deriveBatteryPresence;
73739
74177
  exports.deriveCameraSwitches = deriveCameraSwitches;
73740
74178
  exports.deriveDetailCropRect = deriveDetailCropRect;
74179
+ exports.derivePostTriggeredAction = derivePostTriggeredAction;
73741
74180
  exports.deriveRecordingMode = deriveRecordingMode;
73742
74181
  exports.describeComposableCaps = describeComposableCaps;
73743
74182
  exports.describeCustomActions = require_sleep.describeCustomActions;
@@ -73755,6 +74194,7 @@ exports.deviceAdoptionCapability = deviceAdoptionCapability;
73755
74194
  exports.deviceBackendToFormat = deviceBackendToFormat;
73756
74195
  exports.deviceCustomAction = require_sleep.deviceCustomAction;
73757
74196
  exports.deviceDiscoveryCapability = deviceDiscoveryCapability;
74197
+ exports.deviceDoFamily = deviceDoFamily;
73758
74198
  exports.deviceExportCapability = deviceExportCapability;
73759
74199
  exports.deviceExtensionCapability = deviceExtensionCapability;
73760
74200
  exports.deviceManagerCapability = deviceManagerCapability;
@@ -73881,6 +74321,7 @@ exports.isDeviceConfigCap = require_sleep.isDeviceConfigCap;
73881
74321
  exports.isDeviceScopedCap = require_sleep.isDeviceScopedCap;
73882
74322
  exports.isDisplayIconKey = isDisplayIconKey;
73883
74323
  exports.isDoActionActuatable = isDoActionActuatable;
74324
+ exports.isDoPickerDeviceType = isDoPickerDeviceType;
73884
74325
  exports.isEmbeddingModelFailed = isEmbeddingModelFailed;
73885
74326
  exports.isEvent = require_sleep.isEvent;
73886
74327
  exports.isEventKindLabelKey = isEventKindLabelKey;
@@ -74098,10 +74539,12 @@ exports.resolveVariantModelId = resolveVariantModelId;
74098
74539
  exports.resolveViewableDeviceIds = resolveViewableDeviceIds;
74099
74540
  exports.roleSpec = roleSpec;
74100
74541
  exports.roomCompositionExample = roomCompositionExample;
74542
+ exports.ruleAutoTriggersAlarm = ruleAutoTriggersAlarm;
74101
74543
  exports.ruleBelongsToAlarm = ruleBelongsToAlarm;
74102
74544
  exports.ruleDeviceCompatCapNames = ruleDeviceCompatCapNames;
74103
74545
  exports.ruleDeviceCompatCapQueries = ruleDeviceCompatCapQueries;
74104
74546
  exports.ruleEditorSectionsForKind = ruleEditorSectionsForKind;
74547
+ exports.ruleGatedOnArmedState = ruleGatedOnArmedState;
74105
74548
  exports.ruleGroupingApplies = ruleGroupingApplies;
74106
74549
  exports.ruleKindOf = ruleKindOf;
74107
74550
  exports.ruleKindSpec = ruleKindSpec;
@@ -74112,6 +74555,7 @@ exports.ruleSeedForSection = ruleSeedForSection;
74112
74555
  exports.runInferenceStep = runInferenceStep;
74113
74556
  exports.runtimeDevices = runtimeDevices;
74114
74557
  exports.runtimeStatePolicyFor = runtimeStatePolicyFor;
74558
+ exports.sameDoFamily = sameDoFamily;
74115
74559
  exports.sceneMonitorCapability = sceneMonitorCapability;
74116
74560
  exports.scheduleForSendTimes = scheduleForSendTimes;
74117
74561
  exports.schemaDeclaresAnyField = schemaDeclaresAnyField;