@camstack/types 1.2.417 → 1.2.419

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 (56) hide show
  1. package/dist/addon.js +2 -2
  2. package/dist/addon.mjs +2 -2
  3. package/dist/capabilities/addons.cap.d.ts +67 -1
  4. package/dist/capabilities/capability-definition.d.ts +5 -0
  5. package/dist/capabilities/color.cap.d.ts +1 -0
  6. package/dist/capabilities/composer.cap.d.ts +201 -0
  7. package/dist/capabilities/core-blocks.cap.d.ts +1441 -0
  8. package/dist/capabilities/group-commands.cap.d.ts +49 -0
  9. package/dist/capabilities/group-status.cap.d.ts +46 -0
  10. package/dist/capabilities/index.d.ts +6 -2
  11. package/dist/capabilities/motion.cap.d.ts +12 -4
  12. package/dist/capabilities/notification-rules.cap.d.ts +46 -0
  13. package/dist/capabilities/osd-manager.cap.d.ts +12 -0
  14. package/dist/client.js +37 -5
  15. package/dist/client.mjs +37 -5
  16. package/dist/composition/composition-report.d.ts +72 -0
  17. package/dist/composition/composition.d.ts +286 -5
  18. package/dist/composition/helpers/actuator.d.ts +58 -0
  19. package/dist/composition/helpers/aggregate.d.ts +41 -0
  20. package/dist/composition/helpers/catalog.d.ts +47 -0
  21. package/dist/composition/helpers/compile.d.ts +22 -0
  22. package/dist/composition/helpers/index.d.ts +7 -0
  23. package/dist/composition/helpers/save.d.ts +18 -0
  24. package/dist/composition/helpers/source-pick.d.ts +40 -0
  25. package/dist/composition/helpers/spec.d.ts +43 -0
  26. package/dist/composition/index.d.ts +1 -0
  27. package/dist/composition/source-ref.d.ts +11 -0
  28. package/dist/composition/validate-composition.d.ts +5 -0
  29. package/dist/{composition-kEl9mevu.mjs → composition-OhpuespA.mjs} +121 -8
  30. package/dist/{composition-DsmkwP9-.js → composition-re1aezX9.js} +198 -7
  31. package/dist/device/cap-vocabulary/entries/sensors.d.ts +1 -1
  32. package/dist/enums/event-category.d.ts +8 -0
  33. package/dist/enums.js +1 -1
  34. package/dist/enums.mjs +1 -1
  35. package/dist/{event-category-DXZ3f9Q5.js → event-category-Ave2VSxY.js} +8 -0
  36. package/dist/{event-category-DHXxB8t9.mjs → event-category-CT-hz5Rb.mjs} +8 -0
  37. package/dist/generated/addon-api.d.ts +35 -0
  38. package/dist/generated/addon-cap-facts.d.ts +1 -1
  39. package/dist/generated/cap-status-types.d.ts +5 -1
  40. package/dist/generated/capability-router-map.d.ts +8 -2
  41. package/dist/generated/device-local-state.d.ts +6 -0
  42. package/dist/generated/device-proxy.d.ts +6 -0
  43. package/dist/generated/device-scoped-caps.d.ts +1 -1
  44. package/dist/generated/history-catalog.d.ts +1 -1
  45. package/dist/generated/method-access-map.d.ts +1 -1
  46. package/dist/generated/method-device-selectors.d.ts +1 -1
  47. package/dist/generated/runtime-state-durability.d.ts +1 -1
  48. package/dist/generated/system-proxy.d.ts +1 -1
  49. package/dist/index.js +1040 -24
  50. package/dist/index.mjs +1006 -25
  51. package/dist/interfaces/event-bus.d.ts +15 -0
  52. package/dist/node.js +1 -1
  53. package/dist/node.mjs +1 -1
  54. package/dist/{sleep-gtskVoMw.js → sleep-YJ6FVsUu.js} +26 -2
  55. package/dist/{sleep-CARd6wZF.mjs → sleep-bykKrTgu.mjs} +26 -2
  56. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-gtskVoMw.js");
3
- const require_event_category = require("./event-category-DXZ3f9Q5.js");
4
- const require_composition = require("./composition-DsmkwP9-.js");
2
+ const require_sleep = require("./sleep-YJ6FVsUu.js");
3
+ const require_event_category = require("./event-category-Ave2VSxY.js");
4
+ const require_composition = require("./composition-re1aezX9.js");
5
5
  const require_node_color = require("./node-color.js");
6
6
  const require_err_msg = require("./err-msg-BhVbr0NX.js");
7
7
  const require_enums = require("./enums.js");
@@ -12624,7 +12624,10 @@ var CompositionProblemCodeSchema = zod.z.enum([
12624
12624
  "target-missing",
12625
12625
  "target-unreadable",
12626
12626
  "not-replaceable",
12627
- "native-capability-replace"
12627
+ "native-capability-replace",
12628
+ "mixed-quantity",
12629
+ "helper-mismatch",
12630
+ "member-constraint"
12628
12631
  ]);
12629
12632
  /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
12630
12633
  var CompositionProblemSchema = zod.z.object({
@@ -12648,7 +12651,8 @@ var CompositionUnavailableModeSchema = zod.z.enum([
12648
12651
  "null",
12649
12652
  "offline",
12650
12653
  "unknown",
12651
- "release"
12654
+ "release",
12655
+ "omit"
12652
12656
  ]);
12653
12657
  /**
12654
12658
  * `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
@@ -13019,6 +13023,24 @@ function inferExpressionKinds(input) {
13019
13023
  * planner (`composition-items.ts`). Internal to the composition module — NOT
13020
13024
  * in the barrel: these are planner internals, not a published contract.
13021
13025
  */
13026
+ function aggregateKinds(source) {
13027
+ if (source.publish !== "value") return {
13028
+ ok: true,
13029
+ kinds: new Set(["number"])
13030
+ };
13031
+ if (source.reducer === "any" || source.reducer === "all") return {
13032
+ ok: true,
13033
+ kinds: new Set(["boolean"])
13034
+ };
13035
+ if (source.empty === "null") return {
13036
+ ok: true,
13037
+ kinds: new Set(["number", "null"])
13038
+ };
13039
+ return {
13040
+ ok: true,
13041
+ kinds: new Set(["number"])
13042
+ };
13043
+ }
13022
13044
  function readKinds(read, lookupCap) {
13023
13045
  const def = lookupCap(read.cap);
13024
13046
  const schema = def?.runtimeState ?? def?.status?.schema;
@@ -13046,6 +13068,7 @@ function sourceKinds(source, lookupCap) {
13046
13068
  code: "reserved-variant",
13047
13069
  message: "code fields arrive in slice 4"
13048
13070
  };
13071
+ if (source.kind === "aggregate") return aggregateKinds(source);
13049
13072
  const bindingKinds = /* @__PURE__ */ new Map();
13050
13073
  for (const [name, binding] of Object.entries(source.bindings)) {
13051
13074
  if (binding.kind === "literal") {
@@ -13242,6 +13265,531 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
13242
13265
  };
13243
13266
  }
13244
13267
  //#endregion
13268
+ //#region src/composition/helpers/catalog.ts
13269
+ /**
13270
+ * One catalog row per base reading a group helper can build (D944 §3).
13271
+ * Data, not a form default written into the block.
13272
+ */
13273
+ var NOW = {
13274
+ fieldPath: "lastFetchedAt",
13275
+ expr: "now"
13276
+ };
13277
+ var CHANGED = {
13278
+ fieldPath: "lastChangedAt",
13279
+ expr: "now"
13280
+ };
13281
+ function numeric(input) {
13282
+ return {
13283
+ ...input,
13284
+ family: "numeric",
13285
+ deviceType: require_err_msg.DeviceType.Sensor,
13286
+ memberDeviceType: require_err_msg.DeviceType.Sensor,
13287
+ commandCaps: [],
13288
+ baseUnit: require_sleep.baseUnitOf(input.quantity),
13289
+ aggregates: require_composition.NUMERIC_AGGREGATES,
13290
+ accept: [{
13291
+ cap: input.outputCap,
13292
+ fieldPath: input.outputField
13293
+ }]
13294
+ };
13295
+ }
13296
+ function binary(input) {
13297
+ return {
13298
+ ...input,
13299
+ family: "binary",
13300
+ deviceType: require_err_msg.DeviceType.Sensor,
13301
+ memberDeviceType: require_err_msg.DeviceType.Sensor,
13302
+ commandCaps: [],
13303
+ quantity: "none",
13304
+ baseUnit: void 0,
13305
+ aggregates: require_composition.BINARY_AGGREGATES,
13306
+ empty: "offline"
13307
+ };
13308
+ }
13309
+ var GROUP_TEMPLATES = [
13310
+ numeric({
13311
+ id: "temperature",
13312
+ summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
13313
+ role: require_err_msg.DeviceRole.TemperatureSensor,
13314
+ outputCap: "temperature-sensor",
13315
+ outputField: "celsius",
13316
+ quantity: "temperature",
13317
+ defaultAggregate: "mean",
13318
+ empty: "null",
13319
+ companions: [NOW]
13320
+ }),
13321
+ numeric({
13322
+ id: "humidity",
13323
+ summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
13324
+ role: require_err_msg.DeviceRole.HumiditySensor,
13325
+ outputCap: "humidity-sensor",
13326
+ outputField: "percent",
13327
+ quantity: "humidity",
13328
+ defaultAggregate: "mean",
13329
+ empty: "null",
13330
+ companions: [NOW]
13331
+ }),
13332
+ numeric({
13333
+ id: "pressure",
13334
+ summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
13335
+ role: require_err_msg.DeviceRole.PressureSensor,
13336
+ outputCap: "pressure-sensor",
13337
+ outputField: "hpa",
13338
+ quantity: "pressure",
13339
+ defaultAggregate: "mean",
13340
+ empty: "null",
13341
+ companions: [NOW]
13342
+ }),
13343
+ numeric({
13344
+ id: "illuminance",
13345
+ summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
13346
+ role: require_err_msg.DeviceRole.AmbientLightSensor,
13347
+ outputCap: "ambient-light-sensor",
13348
+ outputField: "lux",
13349
+ quantity: "illuminance",
13350
+ defaultAggregate: "mean",
13351
+ empty: "null",
13352
+ companions: [NOW]
13353
+ }),
13354
+ numeric({
13355
+ id: "power",
13356
+ summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
13357
+ role: require_err_msg.DeviceRole.PowerSensor,
13358
+ outputCap: "power-meter",
13359
+ outputField: "watts",
13360
+ quantity: "power",
13361
+ defaultAggregate: "sum",
13362
+ empty: "omit",
13363
+ companions: [NOW]
13364
+ }),
13365
+ numeric({
13366
+ id: "energy",
13367
+ summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
13368
+ role: require_err_msg.DeviceRole.EnergySensor,
13369
+ outputCap: "power-meter",
13370
+ outputField: "kwhTotal",
13371
+ quantity: "energy",
13372
+ defaultAggregate: "sum",
13373
+ empty: "omit",
13374
+ companions: [NOW]
13375
+ }),
13376
+ numeric({
13377
+ id: "battery",
13378
+ summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
13379
+ role: require_err_msg.DeviceRole.BatterySensor,
13380
+ outputCap: "battery",
13381
+ outputField: "percentage",
13382
+ quantity: "percentage",
13383
+ defaultAggregate: "mean",
13384
+ empty: "null",
13385
+ companions: [
13386
+ {
13387
+ fieldPath: "charging",
13388
+ expr: "\"unknown\""
13389
+ },
13390
+ {
13391
+ fieldPath: "sleeping",
13392
+ expr: "false"
13393
+ },
13394
+ {
13395
+ fieldPath: "lastUpdated",
13396
+ expr: "now"
13397
+ }
13398
+ ]
13399
+ }),
13400
+ numeric({
13401
+ id: "numeric",
13402
+ summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
13403
+ role: require_err_msg.DeviceRole.NumericSensor,
13404
+ outputCap: "numeric-sensor",
13405
+ outputField: "value",
13406
+ quantity: "device",
13407
+ defaultAggregate: "mean",
13408
+ empty: "null",
13409
+ companions: [NOW]
13410
+ }),
13411
+ binary({
13412
+ id: "motion",
13413
+ summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
13414
+ role: require_err_msg.DeviceRole.MotionSensor,
13415
+ outputCap: "motion",
13416
+ outputField: "detected",
13417
+ defaultAggregate: "any",
13418
+ accept: [{
13419
+ cap: "motion",
13420
+ fieldPath: "detected"
13421
+ }],
13422
+ companions: [{
13423
+ fieldPath: "lastDetectedAt",
13424
+ expr: "null"
13425
+ }, {
13426
+ fieldPath: "autoClearAfterMs",
13427
+ expr: "null"
13428
+ }]
13429
+ }),
13430
+ binary({
13431
+ id: "contact",
13432
+ summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
13433
+ role: require_err_msg.DeviceRole.ContactSensor,
13434
+ outputCap: "contact",
13435
+ outputField: "entryOpen",
13436
+ defaultAggregate: "any",
13437
+ accept: [{
13438
+ cap: "contact",
13439
+ fieldPath: "entryOpen"
13440
+ }],
13441
+ companions: [CHANGED]
13442
+ }),
13443
+ binary({
13444
+ id: "leak",
13445
+ summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
13446
+ role: require_err_msg.DeviceRole.LeakSensor,
13447
+ outputCap: "flood",
13448
+ outputField: "flooded",
13449
+ defaultAggregate: "any",
13450
+ accept: [{
13451
+ cap: "flood",
13452
+ fieldPath: "flooded"
13453
+ }],
13454
+ companions: [CHANGED]
13455
+ }),
13456
+ binary({
13457
+ id: "smoke",
13458
+ summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
13459
+ role: require_err_msg.DeviceRole.SmokeSensor,
13460
+ outputCap: "smoke",
13461
+ outputField: "detected",
13462
+ defaultAggregate: "any",
13463
+ accept: [{
13464
+ cap: "smoke",
13465
+ fieldPath: "detected"
13466
+ }],
13467
+ companions: [CHANGED]
13468
+ }),
13469
+ binary({
13470
+ id: "occupancy",
13471
+ summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
13472
+ role: require_err_msg.DeviceRole.BinarySensor,
13473
+ outputCap: "binary",
13474
+ outputField: "on",
13475
+ defaultAggregate: "any",
13476
+ accept: [{
13477
+ cap: "motion",
13478
+ fieldPath: "detected"
13479
+ }, {
13480
+ cap: "binary",
13481
+ fieldPath: "on"
13482
+ }],
13483
+ companions: [CHANGED]
13484
+ }),
13485
+ binary({
13486
+ id: "binary",
13487
+ summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
13488
+ role: require_err_msg.DeviceRole.BinarySensor,
13489
+ outputCap: "binary",
13490
+ outputField: "on",
13491
+ defaultAggregate: "any",
13492
+ accept: [{
13493
+ cap: "binary",
13494
+ fieldPath: "on"
13495
+ }],
13496
+ companions: [CHANGED]
13497
+ }),
13498
+ actuator({
13499
+ id: "switch",
13500
+ summary: "On when at least one switch is on, or when all of them are. Offline and unknown members are left out of that decision, never read as off, and still receive the command.",
13501
+ deviceType: require_err_msg.DeviceType.Switch,
13502
+ outputCap: "switch",
13503
+ commandCaps: ["switch"]
13504
+ }),
13505
+ actuator({
13506
+ id: "light",
13507
+ summary: "On when at least one light is on, or when all of them are. Brightness and colour are offered only when every member has them. A command is not sent to a member that lacks it.",
13508
+ deviceType: require_err_msg.DeviceType.Light,
13509
+ outputCap: "switch",
13510
+ commandCaps: [
13511
+ "switch",
13512
+ "brightness",
13513
+ "color"
13514
+ ]
13515
+ })
13516
+ ];
13517
+ function actuator(input) {
13518
+ return {
13519
+ ...input,
13520
+ family: "actuator",
13521
+ role: void 0,
13522
+ memberDeviceType: input.deviceType,
13523
+ outputField: "on",
13524
+ quantity: "none",
13525
+ baseUnit: void 0,
13526
+ aggregates: require_composition.BINARY_AGGREGATES,
13527
+ defaultAggregate: "any",
13528
+ empty: "offline",
13529
+ accept: [{
13530
+ cap: "switch",
13531
+ fieldPath: "on"
13532
+ }],
13533
+ companions: [CHANGED]
13534
+ };
13535
+ }
13536
+ var BY_ID = new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
13537
+ function groupTemplate(id) {
13538
+ return BY_ID.get(id) ?? null;
13539
+ }
13540
+ //#endregion
13541
+ //#region src/composition/helpers/actuator.ts
13542
+ /**
13543
+ * Actuator groups (D944 phase 1b). The active boolean is the binary reducer
13544
+ * with unknown members left out. A command is one call per member that binds
13545
+ * the cap, including members that are offline. One failure does not cancel
13546
+ * the others.
13547
+ */
13548
+ /** Caps a light group may expose, in display order. Switch is the active state. */
13549
+ var LIGHT_SHARED_CAPS = [
13550
+ "switch",
13551
+ "brightness",
13552
+ "color"
13553
+ ];
13554
+ var COLOR_MODE_FEATURES = [
13555
+ require_err_msg.DeviceFeature.LightColorRgb,
13556
+ require_err_msg.DeviceFeature.LightColorHsv,
13557
+ require_err_msg.DeviceFeature.LightColorMired
13558
+ ];
13559
+ /** How many member calls run at once. The rest wait; none are dropped. */
13560
+ var FAN_OUT_CONCURRENCY = 4;
13561
+ /** `at-least-one` is any included member on; `all` is every included member on. */
13562
+ function reducerForActive(active) {
13563
+ return active === "all" ? "all" : "any";
13564
+ }
13565
+ function activeForReducer(reducer) {
13566
+ return reducer === "all" ? "all" : "at-least-one";
13567
+ }
13568
+ /**
13569
+ * Caps every member binds, from {@link LIGHT_SHARED_CAPS}. An empty member
13570
+ * list shares nothing. A member that lacks colour drops colour from the group.
13571
+ */
13572
+ function sharedLightCaps(memberCaps) {
13573
+ if (memberCaps.length === 0) return [];
13574
+ return LIGHT_SHARED_CAPS.filter((cap) => memberCaps.every((bound) => bound.includes(cap)));
13575
+ }
13576
+ /**
13577
+ * Colour modes every member advertises. Offline does not remove a mode:
13578
+ * the caller passes device features, not liveness. No members → no mode.
13579
+ */
13580
+ function sharedColorModes(memberFeatures) {
13581
+ if (memberFeatures.length === 0) return [];
13582
+ return COLOR_MODE_FEATURES.filter((mode) => memberFeatures.every((features) => features.includes(mode)));
13583
+ }
13584
+ /**
13585
+ * One call per member that binds `cap`. Offline members stay in the list.
13586
+ * A member without the cap is not called — the command cannot reach it.
13587
+ */
13588
+ function fanOutTargets(members, cap, method, args) {
13589
+ return members.flatMap((member) => member.caps.includes(cap) ? [{
13590
+ deviceId: member.deviceId,
13591
+ cap,
13592
+ method,
13593
+ args: { ...args }
13594
+ }] : []);
13595
+ }
13596
+ /**
13597
+ * Run every call. A throw is that member's result; the other calls still run.
13598
+ * At most {@link FAN_OUT_CONCURRENCY} are in flight.
13599
+ */
13600
+ async function runFanOut(calls, invoke) {
13601
+ const results = [];
13602
+ let next = 0;
13603
+ const worker = async () => {
13604
+ for (;;) {
13605
+ const index = next;
13606
+ next += 1;
13607
+ const call = calls[index];
13608
+ if (call === void 0) return;
13609
+ try {
13610
+ await invoke(call);
13611
+ results[index] = {
13612
+ deviceId: call.deviceId,
13613
+ ok: true
13614
+ };
13615
+ } catch (err) {
13616
+ const error = err instanceof Error ? err.message : String(err);
13617
+ results[index] = {
13618
+ deviceId: call.deviceId,
13619
+ ok: false,
13620
+ error
13621
+ };
13622
+ }
13623
+ }
13624
+ };
13625
+ const width = Math.min(4, calls.length);
13626
+ await Promise.all(Array.from({ length: width }, () => worker()));
13627
+ return results;
13628
+ }
13629
+ //#endregion
13630
+ //#region src/composition/helpers/compile.ts
13631
+ function sameSource(a, b) {
13632
+ return a.addonId === b.addonId && a.stableId === b.stableId;
13633
+ }
13634
+ function sameMember(a, b) {
13635
+ return sameSource(a.source, b.source) && a.cap === b.cap && a.fieldPath === b.fieldPath;
13636
+ }
13637
+ function accepted(template, member) {
13638
+ return template.accept.some((field) => field.cap === member.cap && field.fieldPath === member.fieldPath);
13639
+ }
13640
+ function memberProblems(template, spec) {
13641
+ return spec.members.flatMap((member, index) => {
13642
+ const at = `helper.members[${index}]`;
13643
+ const problems = [];
13644
+ if (!accepted(template, member)) {
13645
+ const allowed = template.accept.map((field) => `${field.cap}.${field.fieldPath}`).join(" or ");
13646
+ problems.push(problem("member-constraint", at, `a ${template.id} group reads ${allowed}; this member is ${member.cap}.${member.fieldPath}`));
13647
+ }
13648
+ if (spec.members.slice(0, index).some((other) => sameMember(other, member))) problems.push(problem("member-constraint", at, "this member is already in the group"));
13649
+ return problems;
13650
+ });
13651
+ }
13652
+ function aggregateSource(template, spec, reads, publish) {
13653
+ return {
13654
+ kind: "aggregate",
13655
+ reducer: spec.aggregate,
13656
+ reads: [...reads],
13657
+ publish,
13658
+ empty: template.empty
13659
+ };
13660
+ }
13661
+ function expressionSource(expr) {
13662
+ return {
13663
+ kind: "expression",
13664
+ expr,
13665
+ bindings: {}
13666
+ };
13667
+ }
13668
+ function draftOf$1(template, spec) {
13669
+ const reads = spec.members.map((member) => ({
13670
+ source: member.source,
13671
+ cap: member.cap,
13672
+ fieldPath: member.fieldPath
13673
+ }));
13674
+ const companions = Object.fromEntries(template.companions.map((companion) => [companion.fieldPath, expressionSource(companion.expr)]));
13675
+ return {
13676
+ target: {
13677
+ kind: "new",
13678
+ type: template.deviceType,
13679
+ ...template.role === void 0 ? {} : { role: template.role }
13680
+ },
13681
+ helper: spec,
13682
+ features: [{
13683
+ kind: "fields",
13684
+ cap: template.outputCap,
13685
+ fields: {
13686
+ [template.outputField]: aggregateSource(template, spec, reads, "value"),
13687
+ ...companions
13688
+ }
13689
+ }, {
13690
+ kind: "fields",
13691
+ cap: "group-status",
13692
+ fields: {
13693
+ included: aggregateSource(template, spec, reads, "included"),
13694
+ excluded: aggregateSource(template, spec, reads, "excluded"),
13695
+ total: aggregateSource(template, spec, reads, "total")
13696
+ }
13697
+ }]
13698
+ };
13699
+ }
13700
+ function criterionProblems(template, spec) {
13701
+ if (template.family === "actuator") {
13702
+ if (spec.active === void 0) return [problem("kind-mismatch", "helper.active", `a ${template.id} group needs an active criterion (at-least-one or all)`)];
13703
+ const reducer = reducerForActive(spec.active);
13704
+ if (spec.aggregate !== reducer) return [problem("kind-mismatch", "helper.aggregate", `active \`${spec.active}\` aggregates by \`${reducer}\`, not \`${spec.aggregate}\``)];
13705
+ return [];
13706
+ }
13707
+ if (spec.active !== void 0) return [problem("kind-mismatch", "helper.active", `a ${template.id} group has no active criterion — that belongs to an actuator group`)];
13708
+ return [];
13709
+ }
13710
+ function parseDraft(draft) {
13711
+ const parsed = require_composition.CompositionSchema.safeParse(draft);
13712
+ if (parsed.success) return {
13713
+ ok: true,
13714
+ composition: parsed.data
13715
+ };
13716
+ return {
13717
+ ok: false,
13718
+ problems: [problem("helper-mismatch", "helper", `the template did not compile: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`)]
13719
+ };
13720
+ }
13721
+ /** Compile a group template to a new-device composition. Refusals are named. */
13722
+ function compileHelper(spec) {
13723
+ const template = groupTemplate(spec.templateId);
13724
+ if (template === null) return {
13725
+ ok: false,
13726
+ problems: [problem("member-constraint", "helper.templateId", `unknown template \`${spec.templateId}\``)]
13727
+ };
13728
+ const criterion = criterionProblems(template, spec);
13729
+ if (criterion.length > 0) return {
13730
+ ok: false,
13731
+ problems: criterion
13732
+ };
13733
+ if (!template.aggregates.includes(spec.aggregate)) {
13734
+ const allowed = template.aggregates.join(", ");
13735
+ return {
13736
+ ok: false,
13737
+ problems: [problem("kind-mismatch", "helper.aggregate", `a ${template.id} group aggregates by ${allowed}, not \`${spec.aggregate}\``)]
13738
+ };
13739
+ }
13740
+ const members = memberProblems(template, spec);
13741
+ if (members.length > 0) return {
13742
+ ok: false,
13743
+ problems: members
13744
+ };
13745
+ return parseDraft(draftOf$1(template, spec));
13746
+ }
13747
+ /** The built body, ignoring `helper`, so a save can demand one writer. */
13748
+ function sameHelperBody(stored, compiled) {
13749
+ return JSON.stringify(stored.target) === JSON.stringify(compiled.target) && JSON.stringify(stored.features) === JSON.stringify(compiled.features);
13750
+ }
13751
+ function templateDeviceType(spec) {
13752
+ return groupTemplate(spec.templateId)?.memberDeviceType ?? null;
13753
+ }
13754
+ //#endregion
13755
+ //#region src/composition/helpers/save.ts
13756
+ function quantityProblems(spec, facts) {
13757
+ const template = groupTemplate(spec.templateId);
13758
+ if (template === null || template.family !== "numeric") return [];
13759
+ const known = spec.members.flatMap((member, index) => {
13760
+ const quantity = facts.get(require_composition.compositionSourceKey(member.source))?.quantity;
13761
+ return quantity === void 0 ? [] : [{
13762
+ index,
13763
+ quantity
13764
+ }];
13765
+ });
13766
+ if (template.quantity !== "device") return known.flatMap((member) => member.quantity === template.quantity ? [] : [problem("mixed-quantity", `helper.members[${member.index}]`, `a ${template.id} group is ${template.quantity}${template.baseUnit === void 0 ? "" : ` (${template.baseUnit})`}; this member is ${member.quantity}`)]);
13767
+ const distinct = [...new Set(known.map((member) => member.quantity))];
13768
+ if (distinct.length <= 1) return [];
13769
+ return [problem("mixed-quantity", "helper.members", `a numeric group requires one quantity; members report ${distinct.join(" and ")}`)];
13770
+ }
13771
+ function deviceTypeProblems(spec, facts) {
13772
+ const template = groupTemplate(spec.templateId);
13773
+ if (template === null) return [];
13774
+ return spec.members.flatMap((member, index) => {
13775
+ const deviceType = facts.get(require_composition.compositionSourceKey(member.source))?.deviceType;
13776
+ if (deviceType === void 0 || deviceType === template.memberDeviceType) return [];
13777
+ return [problem("member-constraint", `helper.members[${index}]`, `a ${template.id} group takes ${template.memberDeviceType} devices; this member is a ${deviceType}`)];
13778
+ });
13779
+ }
13780
+ /**
13781
+ * Problems that refuse a save. No `helper` key means a free composition: this
13782
+ * returns nothing, and expression semantics stay as they are.
13783
+ */
13784
+ function helperSaveProblems(composition, facts) {
13785
+ const spec = composition.helper;
13786
+ if (spec === void 0) return [];
13787
+ const compiled = compileHelper(spec);
13788
+ if (!compiled.ok) return compiled.problems;
13789
+ if (!sameHelperBody(composition, compiled.composition)) return [problem("helper-mismatch", "helper", "the stored features are not this template — the helper spec is the only writer")];
13790
+ return [...quantityProblems(spec, facts), ...deviceTypeProblems(spec, facts)];
13791
+ }
13792
+ //#endregion
13245
13793
  //#region src/composition/composition-graph.ts
13246
13794
  /**
13247
13795
  * The field graph across every composition, and the cycles in it (D659).
@@ -13448,11 +13996,22 @@ function composableCap(feature, at, lookupCap) {
13448
13996
  * required field. A REPLACE needs none of it: the cap is bound (a fact), the
13449
13997
  * native keeps serving its methods, and only the named fields are owned (D663).
13450
13998
  */
13451
- function builtCapProblems({ def, state, fields: targetFields }, feature, at, deviceType) {
13999
+ /**
14000
+ * Caps an actuator helper is allowed to serve. A free composition, and a
14001
+ * reading group, get an empty set — `has-commands` stays for them.
14002
+ */
14003
+ function actuatorCommandCaps(composition) {
14004
+ const spec = composition.helper;
14005
+ if (spec === void 0) return /* @__PURE__ */ new Set();
14006
+ const template = groupTemplate(spec.templateId);
14007
+ if (template === null || template.family !== "actuator") return /* @__PURE__ */ new Set();
14008
+ return new Set(template.commandCaps);
14009
+ }
14010
+ function builtCapProblems({ def, state, fields: targetFields }, feature, at, deviceType, servedCommands) {
13452
14011
  const problems = [];
13453
14012
  if (def.deviceTypes !== void 0 && !def.deviceTypes.includes(deviceType)) problems.push(problem("wrong-device-type", `${at}.cap`, `\`${def.name}\` is not offered on a \`${deviceType}\` device (it allows ${def.deviceTypes.join(", ")})`));
13454
14013
  const served = Object.entries(def.methods).filter(([name, m]) => m.systemOnly !== true && def.composedMethods?.[name] === void 0).map(([name]) => `\`${name}\``);
13455
- if (served.length > 0) problems.push(problem("has-commands", `${at}.cap`, `\`${def.name}\` has ${served.join(", ")}, which a composed device cannot serve until commands arrive (slice 3)`));
14014
+ if (served.length > 0 && !servedCommands.has(def.name)) problems.push(problem("has-commands", `${at}.cap`, `\`${def.name}\` has ${served.join(", ")}, which a composed device cannot serve until commands arrive (slice 3)`));
13456
14015
  const itemArrayPath = feature.items === void 0 ? null : def.status?.itemArray?.path ?? null;
13457
14016
  for (const key of requiredTopLevelKeys(state)) {
13458
14017
  if (key === itemArrayPath) continue;
@@ -13472,6 +14031,7 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
13472
14031
  const role = roleOf(source);
13473
14032
  const unavailable = unavailableFor(tf, role, mode, def.name, fieldAt);
13474
14033
  if (!unavailable.ok) return refused(unavailable.problem);
14034
+ const omitEmpty = source.kind === "aggregate" && source.publish === "value" && source.empty === "omit";
13475
14035
  const plan = {
13476
14036
  cap: def.name,
13477
14037
  path,
@@ -13479,7 +14039,7 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
13479
14039
  kind: tf.kind,
13480
14040
  nullable: tf.nullable,
13481
14041
  required: tf.required,
13482
- unavailable: unavailable.unavailable,
14042
+ unavailable: omitEmpty ? "omit" : unavailable.unavailable,
13483
14043
  role,
13484
14044
  source,
13485
14045
  reads: [...require_composition.fieldReads(source)]
@@ -13492,11 +14052,11 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
13492
14052
  events: []
13493
14053
  };
13494
14054
  }
13495
- function planFeature(feature, featureIndex, target, lookupCap) {
14055
+ function planFeature(feature, featureIndex, target, lookupCap, servedCommands) {
13496
14056
  const at = `features[${featureIndex}]`;
13497
14057
  const cap = composableCap(feature, at, lookupCap);
13498
14058
  if ("code" in cap) return refused(cap);
13499
- const capProblems = target.mode === "replace" ? [] : [...builtCapProblems(cap, feature, at, target.deviceType)];
14059
+ const capProblems = target.mode === "replace" ? [] : [...builtCapProblems(cap, feature, at, target.deviceType, servedCommands)];
13500
14060
  if (feature.commands !== void 0 && Object.keys(feature.commands).length > 0) capProblems.push(problem("reserved-variant", `${at}.commands`, "commands (`forward`) arrive in slice 3"));
13501
14061
  const perField = Object.entries(feature.fields).map(([path, source]) => planTopLevelField(cap, {
13502
14062
  featureIndex,
@@ -13582,6 +14142,7 @@ function featureTargetOf(target, cap, at) {
13582
14142
  function planComposition(composition, lookupCap, target) {
13583
14143
  const planTarget = planTargetOf(composition, target);
13584
14144
  if ("code" in planTarget) return refused(planTarget);
14145
+ const servedCommands = actuatorCommandCaps(composition);
13585
14146
  const results = composition.features.map((feature, index) => {
13586
14147
  const at = `features[${index}]`;
13587
14148
  if (feature.kind === "passthrough") return refused(problem("reserved-variant", at, `whole-capability passthrough of \`${feature.cap}\` arrives in slice 3`));
@@ -13596,9 +14157,9 @@ function planComposition(composition, lookupCap, target) {
13596
14157
  return nativeReplaceOrBlock(featureTarget, planFeature(feature, index, {
13597
14158
  mode: "add",
13598
14159
  deviceType: planTarget.found.type
13599
- }, lookupCap));
14160
+ }, lookupCap, servedCommands));
13600
14161
  }
13601
- const result = planFeature(feature, index, featureTarget, lookupCap);
14162
+ const result = planFeature(feature, index, featureTarget, lookupCap, servedCommands);
13602
14163
  return require_composition.compositionFeatureEnabled(feature) ? result : {
13603
14164
  problems: result.problems,
13604
14165
  fields: [],
@@ -13744,10 +14305,15 @@ function validateComposition(composition, ctx) {
13744
14305
  if (refusedFeatures.some((at) => item.path === at || item.path.startsWith(`${at}.`))) return false;
13745
14306
  return refusedFeatures.length === 0 || item.path !== "features";
13746
14307
  });
14308
+ const facts = new Map([...ctx.sources].flatMap(([key, source]) => source.kind === "found" ? [[key, {
14309
+ deviceType: source.deviceType,
14310
+ quantity: source.quantity
14311
+ }]] : []));
13747
14312
  const problems = [
13748
14313
  ...plan.problems,
13749
14314
  ...sourceProblems(plan.fields, ctx, self),
13750
- ...cycles
14315
+ ...cycles,
14316
+ ...helperSaveProblems(composition, facts)
13751
14317
  ];
13752
14318
  return {
13753
14319
  ok: problems.length === 0,
@@ -44507,6 +45073,8 @@ var NcSystemEventKindSchema = zod.z.enum([
44507
45073
  "detection-blind",
44508
45074
  "motion-noisy",
44509
45075
  "motion-calm",
45076
+ "package-llm-silent",
45077
+ "package-llm-answered",
44510
45078
  "recording-stalled",
44511
45079
  "recording-healthy",
44512
45080
  "recording-degraded",
@@ -46151,6 +46719,14 @@ var NC_CONDITION_CATALOG = [
46151
46719
  value: "motion-calm",
46152
46720
  label: "Camera motion calm again"
46153
46721
  },
46722
+ {
46723
+ value: "package-llm-silent",
46724
+ label: "Package confirm not answering"
46725
+ },
46726
+ {
46727
+ value: "package-llm-answered",
46728
+ label: "Package confirm answering again"
46729
+ },
46154
46730
  {
46155
46731
  value: "recording-stalled",
46156
46732
  label: "Recording stalled"
@@ -60182,6 +60758,28 @@ var PackageVersionInfoSchema = zod.z.object({
60182
60758
  deprecated: zod.z.string().optional(),
60183
60759
  distTags: zod.z.array(zod.z.string()).readonly()
60184
60760
  });
60761
+ /**
60762
+ * One published document. `ok` is markdown from the registry. `missing` means
60763
+ * the registry answered and the file was not there. `error` is a registry or
60764
+ * tarball failure — never an empty string standing in for either.
60765
+ */
60766
+ var PackageDocBodySchema = zod.z.discriminatedUnion("status", [
60767
+ zod.z.object({
60768
+ status: zod.z.literal("ok"),
60769
+ markdown: zod.z.string()
60770
+ }),
60771
+ zod.z.object({ status: zod.z.literal("missing") }),
60772
+ zod.z.object({
60773
+ status: zod.z.literal("error"),
60774
+ message: zod.z.string()
60775
+ })
60776
+ ]);
60777
+ var PackageDocsSchema = zod.z.object({
60778
+ name: zod.z.string(),
60779
+ version: zod.z.string(),
60780
+ readme: PackageDocBodySchema,
60781
+ changelog: PackageDocBodySchema
60782
+ });
60185
60783
  var SearchResultSchema = zod.z.object({
60186
60784
  name: zod.z.string(),
60187
60785
  version: zod.z.string(),
@@ -60548,6 +61146,15 @@ var addonsCapability = {
60548
61146
  auth: "admin"
60549
61147
  }),
60550
61148
  getVersions: require_sleep.method(zod.z.object({ name: zod.z.string() }), zod.z.array(PackageVersionInfoSchema).readonly()),
61149
+ /**
61150
+ * README and CHANGELOG for one registry package, read on the hub and
61151
+ * cached. `version` omitted resolves the `latest` dist-tag. The browser
61152
+ * never talks to the registry.
61153
+ */
61154
+ getPackageDocs: require_sleep.method(zod.z.object({
61155
+ name: zod.z.string().min(1),
61156
+ version: zod.z.string().min(1).optional()
61157
+ }), PackageDocsSchema, { auth: "admin" }),
60551
61158
  restartAddon: require_sleep.method(zod.z.object({ addonId: zod.z.string() }), RestartAddonResultSchema, {
60552
61159
  kind: "mutation",
60553
61160
  auth: "admin"
@@ -62109,6 +62716,10 @@ var ColorStatusSchema = zod.z.object({
62109
62716
  /** Ms epoch of the last operator-driven change. */
62110
62717
  lastChangedAt: zod.z.number()
62111
62718
  });
62719
+ function parseColorInput(value) {
62720
+ const parsed = ColorInputSchema.safeParse(value);
62721
+ return parsed.success ? parsed.data : null;
62722
+ }
62112
62723
  var colorCapability = {
62113
62724
  name: "color",
62114
62725
  scope: "device",
@@ -64307,6 +64918,99 @@ var gasCapability = {
64307
64918
  volatileStateFields: ["lastChangedAt"]
64308
64919
  };
64309
64920
  //#endregion
64921
+ //#region src/capabilities/group-commands.cap.ts
64922
+ /**
64923
+ * The last command a helper actuator group sent to each member (D944).
64924
+ * The composer writes this slice; the aggregate pass does not, so a later
64925
+ * reading does not wipe it. History is none — the outcome is the latest
64926
+ * attempt, not a series.
64927
+ */
64928
+ var GroupCommandResultSchema = zod.z.object({
64929
+ deviceId: zod.z.number().int().nonnegative(),
64930
+ cap: zod.z.string().min(1),
64931
+ method: zod.z.string().min(1),
64932
+ ok: zod.z.boolean(),
64933
+ error: zod.z.string().optional(),
64934
+ /** Ms epoch of the attempt. */
64935
+ at: zod.z.number()
64936
+ });
64937
+ var GroupCommandsSchema = zod.z.object({
64938
+ /** One row per member that has been commanded. A later command replaces that member's row. */
64939
+ results: zod.z.array(GroupCommandResultSchema) });
64940
+ var groupCommandsCapability = {
64941
+ name: "group-commands",
64942
+ scope: "device",
64943
+ deviceNative: true,
64944
+ mode: "singleton",
64945
+ deviceTypes: [require_err_msg.DeviceType.Switch, require_err_msg.DeviceType.Light],
64946
+ methods: {},
64947
+ status: {
64948
+ schema: GroupCommandsSchema,
64949
+ kind: "push"
64950
+ },
64951
+ runtimeState: GroupCommandsSchema,
64952
+ /**
64953
+ * Runtime-state durability: **session** — the last attempt. A restored
64954
+ * failure would outlive the command that caused it.
64955
+ *
64956
+ * See `RuntimeStateDurability`. Enforced by
64957
+ * `scripts/check-runtime-state-durability.ts`.
64958
+ */
64959
+ durability: "session",
64960
+ history: "none"
64961
+ };
64962
+ //#endregion
64963
+ //#region src/capabilities/group-status.cap.ts
64964
+ /**
64965
+ * How many members of a helper group answered (D944). Counts are integers,
64966
+ * not measurements: zero included is a real count, never a stand-in reading.
64967
+ * The reading itself stays on the output capability. History is none — the
64968
+ * series that later statistics read is the output cap's own history block.
64969
+ */
64970
+ var GroupStatusSchema = zod.z.object({
64971
+ /** Members whose current value entered the aggregate. */
64972
+ included: zod.z.number().int().nonnegative().meta(require_sleep.readingMeta("count", {
64973
+ precision: 0,
64974
+ label: "Reporting"
64975
+ })),
64976
+ /** Members left out: offline, unknown, or not a finite reading (D393). */
64977
+ excluded: zod.z.number().int().nonnegative().meta(require_sleep.readingMeta("count", {
64978
+ precision: 0,
64979
+ label: "Excluded"
64980
+ })),
64981
+ /** `included` + `excluded`. */
64982
+ total: zod.z.number().int().nonnegative().meta(require_sleep.readingMeta("count", {
64983
+ precision: 0,
64984
+ label: "Members"
64985
+ }))
64986
+ });
64987
+ var groupStatusCapability = {
64988
+ name: "group-status",
64989
+ scope: "device",
64990
+ deviceNative: true,
64991
+ mode: "singleton",
64992
+ deviceTypes: [
64993
+ require_err_msg.DeviceType.Sensor,
64994
+ require_err_msg.DeviceType.Switch,
64995
+ require_err_msg.DeviceType.Light
64996
+ ],
64997
+ methods: {},
64998
+ status: {
64999
+ schema: GroupStatusSchema,
65000
+ kind: "push"
65001
+ },
65002
+ runtimeState: GroupStatusSchema,
65003
+ /**
65004
+ * Runtime-state durability: **session** — recomputed from members on the
65005
+ * next source event; a restored count would outlive the readings it named.
65006
+ *
65007
+ * See `RuntimeStateDurability`. Enforced by
65008
+ * `scripts/check-runtime-state-durability.ts`.
65009
+ */
65010
+ durability: "session",
65011
+ history: "none"
65012
+ };
65013
+ //#endregion
64310
65014
  //#region src/capabilities/heating-valve.cap.ts
64311
65015
  var HeatingValveStatusSchema = zod.z.object({
64312
65016
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
@@ -66402,12 +67106,18 @@ var motionCapability = {
66402
67106
  methods: {
66403
67107
  /**
66404
67108
  * Pull the current motion state synchronously. Convenience shortcut
66405
- * for consumers that don't need the full status object; equivalent
66406
- * to `getStatus()?.detected ?? false`. Will likely be folded into
66407
- * `getStatus` once the auto-injected status surface lands in every
66408
- * consumer.
67109
+ * for consumers that don't need the full status object. A composed
67110
+ * group answers from its slice (D944): unknown throws, it is not off.
66409
67111
  */
66410
67112
  isDetected: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.boolean()) },
67113
+ /**
67114
+ * A composed motion group serves `isDetected` from `detected` (D944).
67115
+ * Without this the cap stays uncomposable (`has-commands`).
67116
+ */
67117
+ composedMethods: { isDetected: {
67118
+ kind: "slice",
67119
+ field: "detected"
67120
+ } },
66411
67121
  events: {
66412
67122
  /**
66413
67123
  * Fires every time the runner transitions a camera between
@@ -77154,6 +77864,127 @@ function createDeviceExtensionProvider(options) {
77154
77864
  };
77155
77865
  }
77156
77866
  //#endregion
77867
+ //#region src/composition/helpers/aggregate.ts
77868
+ function isBinaryReducer(reducer) {
77869
+ return reducer === "any" || reducer === "all";
77870
+ }
77871
+ function includedValue(reducer, member) {
77872
+ if (member.state !== "fresh") return null;
77873
+ if (isBinaryReducer(reducer)) return typeof member.value === "boolean" ? member.value : null;
77874
+ return typeof member.value === "number" && Number.isFinite(member.value) ? member.value : null;
77875
+ }
77876
+ function median$1(values) {
77877
+ const sorted = [...values].toSorted((a, b) => a - b);
77878
+ const mid = Math.floor(sorted.length / 2);
77879
+ const right = sorted[mid];
77880
+ const left = sorted[mid - 1];
77881
+ if (right === void 0) throw new Error("median requires at least one finite number");
77882
+ if (sorted.length % 2 === 1) return right;
77883
+ if (left === void 0) throw new Error("median requires at least one finite number");
77884
+ return (left + right) / 2;
77885
+ }
77886
+ function reduceNumbers(reducer, values) {
77887
+ if (reducer === "min") return Math.min(...values);
77888
+ if (reducer === "max") return Math.max(...values);
77889
+ if (reducer === "sum") return values.reduce((sum, value) => sum + value, 0);
77890
+ if (reducer === "median") return median$1(values);
77891
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
77892
+ }
77893
+ function reduceBooleans(reducer, values) {
77894
+ return reducer === "all" ? values.every((value) => value) : values.some((value) => value);
77895
+ }
77896
+ function countsOf(included, total) {
77897
+ return {
77898
+ included,
77899
+ excluded: total - included,
77900
+ total
77901
+ };
77902
+ }
77903
+ function fatalReason(members) {
77904
+ const reasons = members.flatMap((member) => member.state === "unavailable" && member.fatal === true ? [member.reason ?? "source gone"] : []);
77905
+ return reasons.length === 0 ? null : reasons.join("; ");
77906
+ }
77907
+ function emptyOutcome(empty, counts) {
77908
+ if (empty === "null") return {
77909
+ kind: "value",
77910
+ value: null,
77911
+ counts
77912
+ };
77913
+ return {
77914
+ kind: "unavailable",
77915
+ fatal: false,
77916
+ reason: "no member included — unknown is not 0 or off",
77917
+ counts
77918
+ };
77919
+ }
77920
+ /** Pure. `members` is not mutated. An empty included set is null or unavailable, never 0 or false. */
77921
+ function evaluateAggregate(input) {
77922
+ const included = input.members.flatMap((member) => {
77923
+ const value = includedValue(input.reducer, member);
77924
+ return value === null ? [] : [value];
77925
+ });
77926
+ const counts = countsOf(included.length, input.members.length);
77927
+ const gone = fatalReason(input.members);
77928
+ if (gone !== null) return {
77929
+ kind: "unavailable",
77930
+ fatal: true,
77931
+ reason: gone,
77932
+ counts
77933
+ };
77934
+ if (input.publish === "included") return {
77935
+ kind: "value",
77936
+ value: counts.included,
77937
+ counts
77938
+ };
77939
+ if (input.publish === "excluded") return {
77940
+ kind: "value",
77941
+ value: counts.excluded,
77942
+ counts
77943
+ };
77944
+ if (input.publish === "total") return {
77945
+ kind: "value",
77946
+ value: counts.total,
77947
+ counts
77948
+ };
77949
+ if (included.length === 0) return emptyOutcome(input.empty, counts);
77950
+ if (isBinaryReducer(input.reducer)) {
77951
+ const flags = included.filter((value) => typeof value === "boolean");
77952
+ return {
77953
+ kind: "value",
77954
+ value: reduceBooleans(input.reducer, flags),
77955
+ counts
77956
+ };
77957
+ }
77958
+ const numbers = included.filter((value) => typeof value === "number");
77959
+ return {
77960
+ kind: "value",
77961
+ value: reduceNumbers(input.reducer, numbers),
77962
+ counts
77963
+ };
77964
+ }
77965
+ //#endregion
77966
+ //#region src/composition/helpers/source-pick.ts
77967
+ /** What the member step asks the selector for this template. */
77968
+ function sourcePickForTemplate(template) {
77969
+ const valueKind = template.family === "numeric" ? "number" : "boolean";
77970
+ return {
77971
+ purpose: "member",
77972
+ multiple: true,
77973
+ max: 64,
77974
+ deviceTypes: [template.memberDeviceType],
77975
+ accept: template.accept.map((field) => ({
77976
+ ...field,
77977
+ valueKind
77978
+ })),
77979
+ history: {
77980
+ required: false,
77981
+ minRetentionMs: null
77982
+ },
77983
+ mustBindCaps: template.family === "actuator" ? [template.outputCap] : [],
77984
+ exclude: []
77985
+ };
77986
+ }
77987
+ //#endregion
77157
77988
  //#region src/units/unit-table.ts
77158
77989
  /**
77159
77990
  * Frozen unit → spec table. `•` in the doc marks each dimension's canonical
@@ -77740,11 +78571,45 @@ function expressionOutcome(source, read, now, stateful) {
77740
78571
  deadline: deadlines.length > 0 ? Math.min(...deadlines) : null
77741
78572
  };
77742
78573
  }
78574
+ function aggregateRead(reading) {
78575
+ if (reading.state === "unavailable") return {
78576
+ state: "unavailable",
78577
+ fatal: reading.fatal,
78578
+ reason: reading.reason
78579
+ };
78580
+ return {
78581
+ state: reading.state,
78582
+ value: reading.value,
78583
+ ...reading.state === "stale" ? { reason: reading.reason } : {}
78584
+ };
78585
+ }
78586
+ function aggregateField(source, read) {
78587
+ const outcome = evaluateAggregate({
78588
+ reducer: source.reducer,
78589
+ members: source.reads.map((item) => aggregateRead(read(item))),
78590
+ publish: source.publish,
78591
+ empty: source.empty
78592
+ });
78593
+ if (outcome.kind === "value") return {
78594
+ state: "fresh",
78595
+ value: outcome.value,
78596
+ reason: null,
78597
+ deadline: null
78598
+ };
78599
+ return {
78600
+ state: "unavailable",
78601
+ value: null,
78602
+ reason: outcome.reason,
78603
+ fatal: outcome.fatal,
78604
+ confirmed: true
78605
+ };
78606
+ }
77743
78607
  function evaluateCompositionField(input) {
77744
78608
  const { source } = input;
77745
78609
  switch (source.kind) {
77746
78610
  case "from": return fromReading(input.read(source), source);
77747
78611
  case "expression": return expressionOutcome(source, input.read, input.now, input.stateful);
78612
+ case "aggregate": return aggregateField(source, input.read);
77748
78613
  case "code": return {
77749
78614
  state: "unavailable",
77750
78615
  value: null,
@@ -80600,6 +81465,8 @@ var DEVICE_LOCAL_STATE_CAPS = {
80600
81465
  featureProbe: featureProbeCapability,
80601
81466
  flood: floodCapability,
80602
81467
  gas: gasCapability,
81468
+ groupCommands: groupCommandsCapability,
81469
+ groupStatus: groupStatusCapability,
80603
81470
  heatingValve: heatingValveCapability,
80604
81471
  humidifier: humidifierCapability,
80605
81472
  humiditySensor: humiditySensorCapability,
@@ -82817,6 +83684,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
82817
83684
  access: "view",
82818
83685
  role: "admin"
82819
83686
  },
83687
+ "addons.getPackageDocs": {
83688
+ capName: "addons",
83689
+ capScope: "system",
83690
+ addonId: null,
83691
+ access: "view",
83692
+ role: "admin"
83693
+ },
82820
83694
  "addons.getVersions": {
82821
83695
  capName: "addons",
82822
83696
  capScope: "system",
@@ -85925,6 +86799,20 @@ var METHOD_ACCESS_MAP = Object.freeze({
85925
86799
  access: "view",
85926
86800
  role: "viewer"
85927
86801
  },
86802
+ "groupCommands.getStatus": {
86803
+ capName: "group-commands",
86804
+ capScope: "device",
86805
+ addonId: null,
86806
+ access: "view",
86807
+ role: "viewer"
86808
+ },
86809
+ "groupStatus.getStatus": {
86810
+ capName: "group-status",
86811
+ capScope: "device",
86812
+ addonId: null,
86813
+ access: "view",
86814
+ role: "viewer"
86815
+ },
85928
86816
  "heatingValve.getStatus": {
85929
86817
  capName: "heating-valve",
85930
86818
  capScope: "device",
@@ -92463,6 +93351,8 @@ var KNOWN_CAP_NAMES = [
92463
93351
  "filesystem-browse",
92464
93352
  "flood",
92465
93353
  "gas",
93354
+ "group-commands",
93355
+ "group-status",
92466
93356
  "heating-valve",
92467
93357
  "humidifier",
92468
93358
  "humidity-sensor",
@@ -92611,6 +93501,8 @@ var DEVICE_CAP_NAMES = [
92611
93501
  "feature-probe",
92612
93502
  "flood",
92613
93503
  "gas",
93504
+ "group-commands",
93505
+ "group-status",
92614
93506
  "heating-valve",
92615
93507
  "humidifier",
92616
93508
  "humidity-sensor",
@@ -96128,6 +97020,37 @@ var SENSOR_CAP_VOCABULARY = {
96128
97020
  icon: "flame"
96129
97021
  }]
96130
97022
  },
97023
+ "group-commands": {
97024
+ scope: "device",
97025
+ noun: t("Group command", "Comando di gruppo")
97026
+ },
97027
+ "group-status": {
97028
+ scope: "device",
97029
+ noun: t("Group", "Gruppo"),
97030
+ state: [
97031
+ {
97032
+ kind: "numeric",
97033
+ field: "included",
97034
+ quantity: t("the members reporting", "i membri che rispondono"),
97035
+ label: t("Reporting", "Rispondono"),
97036
+ icon: "users"
97037
+ },
97038
+ {
97039
+ kind: "numeric",
97040
+ field: "excluded",
97041
+ quantity: t("the members left out", "i membri esclusi"),
97042
+ label: t("Excluded", "Esclusi"),
97043
+ icon: "users"
97044
+ },
97045
+ {
97046
+ kind: "numeric",
97047
+ field: "total",
97048
+ quantity: t("the member count", "il numero di membri"),
97049
+ label: t("Members", "Membri"),
97050
+ icon: "sigma"
97051
+ }
97052
+ ]
97053
+ },
96131
97054
  "humidity-sensor": {
96132
97055
  scope: "device",
96133
97056
  noun: t("Humidity", "Umidità"),
@@ -98265,6 +99188,8 @@ var CAP_NAMES_WITH_STATUS = [
98265
99188
  "feature-probe",
98266
99189
  "flood",
98267
99190
  "gas",
99191
+ "group-commands",
99192
+ "group-status",
98268
99193
  "heating-valve",
98269
99194
  "humidifier",
98270
99195
  "humidity-sensor",
@@ -98387,6 +99312,8 @@ var CAPABILITY_NAMES = {
98387
99312
  filesystemBrowse: "filesystem-browse",
98388
99313
  flood: "flood",
98389
99314
  gas: "gas",
99315
+ groupCommands: "group-commands",
99316
+ groupStatus: "group-status",
98390
99317
  heatingValve: "heating-valve",
98391
99318
  humidifier: "humidifier",
98392
99319
  humiditySensor: "humidity-sensor",
@@ -98793,6 +99720,14 @@ var CAPABILITY_ROUTER_KEYS = [
98793
99720
  key: "gas",
98794
99721
  name: "gas"
98795
99722
  },
99723
+ {
99724
+ key: "groupCommands",
99725
+ name: "group-commands"
99726
+ },
99727
+ {
99728
+ key: "groupStatus",
99729
+ name: "group-status"
99730
+ },
98796
99731
  {
98797
99732
  key: "heatingValve",
98798
99733
  name: "heating-valve"
@@ -99306,6 +100241,8 @@ var ALL_CAPABILITY_DEFINITIONS = [
99306
100241
  filesystemBrowseCapability,
99307
100242
  floodCapability,
99308
100243
  gasCapability,
100244
+ groupCommandsCapability,
100245
+ groupStatusCapability,
99309
100246
  heatingValveCapability,
99310
100247
  humidifierCapability,
99311
100248
  humiditySensorCapability,
@@ -100382,6 +101319,16 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
100382
101319
  form: "single",
100383
101320
  optional: false
100384
101321
  }],
101322
+ "groupCommands.getStatus": [{
101323
+ name: "deviceId",
101324
+ form: "single",
101325
+ optional: false
101326
+ }],
101327
+ "groupStatus.getStatus": [{
101328
+ name: "deviceId",
101329
+ form: "single",
101330
+ optional: false
101331
+ }],
100385
101332
  "heatingValve.getStatus": [{
100386
101333
  name: "deviceId",
100387
101334
  form: "single",
@@ -102393,7 +103340,7 @@ function getCapsByProviderKind(kind) {
102393
103340
  //#region src/generated/runtime-state-durability.ts
102394
103341
  /**
102395
103342
  * Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
102396
- * `runtimeState`. 72 caps: 38 `restored`, 34 `session`.
103343
+ * `runtimeState`. 74 caps: 38 `restored`, 36 `session`.
102397
103344
  *
102398
103345
  * A cap absent from this map has no runtime-state slice at all. A cap PRESENT
102399
103346
  * with `durability: 'session'` has one and has decided not to keep it.
@@ -102511,6 +103458,14 @@ var RUNTIME_STATE_POLICY = {
102511
103458
  durability: "restored",
102512
103459
  volatileFields: ["lastChangedAt"]
102513
103460
  },
103461
+ "group-commands": {
103462
+ durability: "session",
103463
+ volatileFields: []
103464
+ },
103465
+ "group-status": {
103466
+ durability: "session",
103467
+ volatileFields: []
103468
+ },
102514
103469
  "heating-valve": {
102515
103470
  durability: "session",
102516
103471
  volatileFields: ["lastFetchedAt"]
@@ -102853,7 +103808,7 @@ var BucketAccumulator = class {
102853
103808
  //#region src/generated/history-catalog.ts
102854
103809
  /**
102855
103810
  * Cap history catalog, projected from every `*.cap.ts` `history` block.
102856
- * 41 caps with series (75 series), 30 caps answered `'none'`.
103811
+ * 41 caps with series (75 series), 32 caps answered `'none'`.
102857
103812
  * Field keys are `runtimeState` paths (`a.b` into fixed objects only).
102858
103813
  */
102859
103814
  var HISTORY_CATALOG = {
@@ -103254,6 +104209,8 @@ var HISTORY_NONE_CAPS = [
103254
104209
  "doorbell",
103255
104210
  "event-emitter",
103256
104211
  "feature-probe",
104212
+ "group-commands",
104213
+ "group-status",
103257
104214
  "image",
103258
104215
  "image-settings",
103259
104216
  "intercom",
@@ -103832,6 +104789,7 @@ function createSystemProxy(api) {
103832
104789
  listCapabilityProviders: (input) => dispatch("addons", "listCapabilityProviders", "query", input),
103833
104790
  setCapabilityProviderEnabled: (input) => dispatch("addons", "setCapabilityProviderEnabled", "mutation", input),
103834
104791
  getVersions: (input) => dispatch("addons", "getVersions", "query", input),
104792
+ getPackageDocs: (input) => dispatch("addons", "getPackageDocs", "query", input),
103835
104793
  restartAddon: (input) => dispatch("addons", "restartAddon", "mutation", input),
103836
104794
  retryLoad: (input) => dispatch("addons", "retryLoad", "mutation", input),
103837
104795
  getAutoUpdateSettings: (input) => dispatch("addons", "getAutoUpdateSettings", "query", input),
@@ -105414,8 +106372,8 @@ var NC_SYSTEM_EVENT_FILTER_KEYS = [
105414
106372
  function systemEventFilterApplies(kind, filter) {
105415
106373
  if (LEGACY_KINDS_WITHOUT_FILTERS.has(kind)) return false;
105416
106374
  switch (filter) {
105417
- case "deviceIds": return kind.startsWith("device-") || kind.startsWith("stream-") || kind === "detection-blind" || kind.startsWith("motion-") || kind.startsWith("recording-") || kind === "alarm-triggered";
105418
- case "deviceTypes": return kind.startsWith("device-") || kind === "detection-blind" || kind.startsWith("motion-");
106375
+ case "deviceIds": return kind.startsWith("device-") || kind.startsWith("stream-") || kind === "detection-blind" || kind.startsWith("motion-") || kind.startsWith("package-llm-") || kind.startsWith("recording-") || kind === "alarm-triggered";
106376
+ case "deviceTypes": return kind.startsWith("device-") || kind === "detection-blind" || kind.startsWith("motion-") || kind.startsWith("package-llm-");
105419
106377
  case "nodeIds": return kind.startsWith("node-") || kind === "addon-crash-loop" || kind === "addon-update-available" || kind === "addon-updated" || kind === "server-update-available" || kind === "wrapper-update-available" || kind === "server-updated" || kind.startsWith("storage-location-") || kind.startsWith("alert-");
105420
106378
  case "packageNames": return kind.endsWith("update-available") || kind === "addon-updated" || kind === "node-updating" || kind === "server-updated";
105421
106379
  case "consumableLowPercent": return NC_CONSUMABLE_SYSTEM_EVENT_KINDS.includes(kind);
@@ -105472,6 +106430,8 @@ var NC_SYSTEM_EVENT_FAMILY = {
105472
106430
  "detection-blind": "device-events",
105473
106431
  "motion-noisy": "device-events",
105474
106432
  "motion-calm": "device-events",
106433
+ "package-llm-silent": "device-events",
106434
+ "package-llm-answered": "device-events",
105475
106435
  "recording-stalled": "device-events",
105476
106436
  "recording-healthy": "device-events",
105477
106437
  "recording-degraded": "device-events",
@@ -105573,6 +106533,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
105573
106533
  label: "Motion without a subject",
105574
106534
  kinds: ["motion-noisy", "motion-calm"]
105575
106535
  },
106536
+ {
106537
+ id: "package-llm",
106538
+ family: "device-events",
106539
+ label: "Package confirm",
106540
+ kinds: ["package-llm-silent", "package-llm-answered"]
106541
+ },
105576
106542
  {
105577
106543
  id: "recording",
105578
106544
  family: "device-events",
@@ -107493,6 +108459,8 @@ var DEVICE_EVENTS = [
107493
108459
  "detection-blind",
107494
108460
  "motion-noisy",
107495
108461
  "motion-calm",
108462
+ "package-llm-silent",
108463
+ "package-llm-answered",
107496
108464
  "recording-stalled",
107497
108465
  "recording-healthy",
107498
108466
  "recording-degraded",
@@ -108096,7 +109064,8 @@ var NC_TEMPLATE_VARS = [
108096
109064
  systemEventKinds: [
108097
109065
  "recording-degraded",
108098
109066
  ...DEVICE_ATTENTION,
108099
- ...ALERT_EPISODE
109067
+ ...ALERT_EPISODE,
109068
+ "package-llm-silent"
108100
109069
  ]
108101
109070
  },
108102
109071
  {
@@ -108189,7 +109158,8 @@ var NC_TEMPLATE_VARS = [
108189
109158
  systemEventKinds: [
108190
109159
  "storage-location-low",
108191
109160
  "storage-location-critical",
108192
- "storage-location-ok"
109161
+ "storage-location-ok",
109162
+ "package-llm-silent"
108193
109163
  ]
108194
109164
  },
108195
109165
  {
@@ -108600,7 +109570,9 @@ var NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS = [
108600
109570
  "device-attention-required",
108601
109571
  "device-attention-resolved",
108602
109572
  "rule-broken",
108603
- "rule-repaired"
109573
+ "rule-repaired",
109574
+ "package-llm-silent",
109575
+ "package-llm-answered"
108604
109576
  ];
108605
109577
  /**
108606
109578
  * The catalog as `getTemplateCatalog` SERVES it: every descriptor, with the
@@ -108762,6 +109734,15 @@ var NC_SYSTEM_EVENT_CLASS_SPECS = [
108762
109734
  snapshotLabel: "Cameras with constant motion now",
108763
109735
  snapshotSection: null
108764
109736
  },
109737
+ {
109738
+ id: "package-llm-confirm",
109739
+ family: "device-events",
109740
+ label: "Package confirm (not answering / answering again)",
109741
+ bad: ["package-llm-silent"],
109742
+ recovery: ["package-llm-answered"],
109743
+ snapshotLabel: "Cameras whose package confirm is not answering",
109744
+ snapshotSection: null
109745
+ },
108765
109746
  {
108766
109747
  id: "recording-health",
108767
109748
  family: "device-events",
@@ -114505,10 +115486,12 @@ function armRemovalReconcile(opts) {
114505
115486
  //#endregion
114506
115487
  exports.ACCESSORY_LABEL = ACCESSORY_LABEL;
114507
115488
  exports.ACCESS_ROLES = ACCESS_ROLES;
115489
+ exports.ACTIVE_CRITERIA = require_composition.ACTIVE_CRITERIA;
114508
115490
  exports.ADMIN_SCOPE = ADMIN_SCOPE;
114509
115491
  exports.AGENT_MDNS_QUERY_NAME = AGENT_MDNS_QUERY_NAME;
114510
115492
  exports.AGENT_MDNS_SERVICE_TYPE = AGENT_MDNS_SERVICE_TYPE;
114511
115493
  exports.AGENT_MDNS_TXT_KEYS = AGENT_MDNS_TXT_KEYS;
115494
+ exports.AGGREGATE_REDUCERS = require_composition.AGGREGATE_REDUCERS;
114512
115495
  exports.AGGREGATE_THROUGHPUT_BY_KIND = AGGREGATE_THROUGHPUT_BY_KIND;
114513
115496
  exports.ALEXA_EGRESS_PROFILE = ALEXA_EGRESS_PROFILE;
114514
115497
  exports.ALL_CAPABILITY_DEFINITIONS = ALL_CAPABILITY_DEFINITIONS;
@@ -114542,6 +115525,7 @@ exports.AcceleratorComputeSchema = AcceleratorComputeSchema;
114542
115525
  exports.AcceleratorKindSchema = AcceleratorKindSchema;
114543
115526
  exports.AccessoriesStatusSchema = AccessoriesStatusSchema;
114544
115527
  exports.AccessoryKind = AccessoryKind;
115528
+ exports.ActiveCriterionSchema = require_composition.ActiveCriterionSchema;
114545
115529
  exports.AddBrokerInputSchema = AddBrokerInputSchema;
114546
115530
  exports.AddRetrainFrameFromRecordingResultSchema = AddRetrainFrameFromRecordingResultSchema;
114547
115531
  exports.AddonAutoUpdateSchema = AddonAutoUpdateSchema;
@@ -114563,6 +115547,7 @@ exports.AdoptionOutcomeSchema = AdoptionOutcomeSchema;
114563
115547
  exports.AdoptionReleaseInputSchema = ReleaseInputSchema;
114564
115548
  exports.AdoptionStatusSchema = AdoptionStatusSchema;
114565
115549
  exports.AgentLoadSummarySchema = AgentLoadSummarySchema;
115550
+ exports.AggregateReducerSchema = require_composition.AggregateReducerSchema;
114566
115551
  exports.AirQualitySensorStatusSchema = AirQualitySensorStatusSchema;
114567
115552
  exports.AlarmArmModeSchema = AlarmArmModeSchema;
114568
115553
  exports.AlarmPanelStatusSchema = AlarmPanelStatusSchema;
@@ -114629,6 +115614,7 @@ exports.BASE_LIVE_EGRESS_PROFILE = BASE_LIVE_EGRESS_PROFILE;
114629
115614
  exports.BATTERY_DEVICE_PROFILE = BATTERY_DEVICE_PROFILE;
114630
115615
  exports.BATTERY_UNREACHABLE_AFTER_MS = BATTERY_UNREACHABLE_AFTER_MS;
114631
115616
  exports.BENCH_ROOT_STEP_ID = BENCH_ROOT_STEP_ID;
115617
+ exports.BINARY_AGGREGATES = require_composition.BINARY_AGGREGATES;
114632
115618
  exports.BIRTH_DECISION_DEFAULT_LIMIT = BIRTH_DECISION_DEFAULT_LIMIT;
114633
115619
  exports.BOOT_RECOVERY_BACKOFF_MS = require_sleep.BOOT_RECOVERY_BACKOFF_MS;
114634
115620
  exports.BUILTIN_RESULT_KINDS = BUILTIN_RESULT_KINDS;
@@ -114839,6 +115825,7 @@ exports.ComposerApplyResultSchema = ComposerApplyResultSchema;
114839
115825
  exports.ComposerBlockSchema = ComposerBlockSchema;
114840
115826
  exports.ComposerBlockVerdictSchema = ComposerBlockVerdictSchema;
114841
115827
  exports.ComposerUnreadableBlockSchema = ComposerUnreadableBlockSchema;
115828
+ exports.CompositionAggregateSourceSchema = require_composition.CompositionAggregateSourceSchema;
114842
115829
  exports.CompositionBindingSchema = require_composition.CompositionBindingSchema;
114843
115830
  exports.CompositionBlockInputSchema = CompositionBlockInputSchema;
114844
115831
  exports.CompositionBlockStateSchema = CompositionBlockStateSchema;
@@ -115192,6 +116179,7 @@ exports.FACE_RESCORE_INTERVAL_FIELD = FACE_RESCORE_INTERVAL_FIELD;
115192
116179
  exports.FACE_RESCORE_INTERVAL_KEY = FACE_RESCORE_INTERVAL_KEY;
115193
116180
  exports.FACE_RESCORE_INTERVAL_MIN_RUNNING = FACE_RESCORE_INTERVAL_MIN_RUNNING;
115194
116181
  exports.FACE_RESCORE_SECTION_ID = FACE_RESCORE_SECTION_ID;
116182
+ exports.FAN_OUT_CONCURRENCY = FAN_OUT_CONCURRENCY;
115195
116183
  exports.FEEDER_EXAMPLE_ADDON_ID = FEEDER_EXAMPLE_ADDON_ID;
115196
116184
  exports.FEEDER_EXAMPLE_HA_DEVICE_ID = FEEDER_EXAMPLE_HA_DEVICE_ID;
115197
116185
  exports.FFMPEG_PATH_ENV = require_composition.FFMPEG_PATH_ENV;
@@ -115215,12 +116203,19 @@ exports.FrameInputSchema = FrameInputSchema;
115215
116203
  exports.FrameLazyCountersSchema = FrameLazyCountersSchema;
115216
116204
  exports.FrameLazyMetricsSchema = FrameLazyMetricsSchema;
115217
116205
  exports.G711_SCALE_CORRECTION_DB = G711_SCALE_CORRECTION_DB;
116206
+ exports.GROUP_TEMPLATES = GROUP_TEMPLATES;
116207
+ exports.GROUP_TEMPLATE_IDS = require_composition.GROUP_TEMPLATE_IDS;
115218
116208
  exports.GasStatusSchema = GasStatusSchema;
115219
116209
  exports.GetLoggingSettingsInputSchema = GetLoggingSettingsInputSchema;
115220
116210
  exports.GetStreamWithCodecInputSchema = GetStreamWithCodecInputSchema;
115221
116211
  exports.GlobalMetricsSchema = GlobalMetricsSchema;
115222
116212
  exports.GridLayoutPatchSchema = GridLayoutPatchSchema;
115223
116213
  exports.GridLayoutViewSchema = GridLayoutViewSchema;
116214
+ exports.GroupCommandResultSchema = GroupCommandResultSchema;
116215
+ exports.GroupCommandsSchema = GroupCommandsSchema;
116216
+ exports.GroupHelperSpecSchema = require_composition.GroupHelperSpecSchema;
116217
+ exports.GroupStatusSchema = GroupStatusSchema;
116218
+ exports.GroupTemplateIdSchema = require_composition.GroupTemplateIdSchema;
115224
116219
  exports.HAP_AUDIO_BASE = HAP_AUDIO_BASE;
115225
116220
  exports.HAP_AUDIO_BITRATE_KBPS = HAP_AUDIO_BITRATE_KBPS;
115226
116221
  exports.HAP_AUDIO_VBV_KBITS = HAP_AUDIO_VBV_KBITS;
@@ -115244,6 +116239,8 @@ exports.HWACCEL_OPTIONS = HWACCEL_OPTIONS;
115244
116239
  exports.HardwareClassIdSchema = HardwareClassIdSchema;
115245
116240
  exports.HealthStatusSchema = HealthStatusSchema;
115246
116241
  exports.HeatingValveStatusSchema = HeatingValveStatusSchema;
116242
+ exports.HelperMemberSchema = require_composition.HelperMemberSchema;
116243
+ exports.HelperSpecSchema = require_composition.HelperSpecSchema;
115247
116244
  exports.HfModelResolutionSchema = HfModelResolutionSchema;
115248
116245
  exports.HistoryPointSchema = HistoryPointSchema;
115249
116246
  exports.HistoryResolutionEnum = HistoryResolutionEnum;
@@ -115303,6 +116300,7 @@ exports.LABEL_SUPPLY_MACRO = LABEL_SUPPLY_MACRO;
115303
116300
  exports.LABEL_SUPPLY_STEP_IDS = LABEL_SUPPLY_STEP_IDS;
115304
116301
  exports.LABEL_SUPPLY_VOCABULARIES = LABEL_SUPPLY_VOCABULARIES;
115305
116302
  exports.LEGACY_READ_ONLY_CONFIG_KEY = LEGACY_READ_ONLY_CONFIG_KEY;
116303
+ exports.LIGHT_SHARED_CAPS = LIGHT_SHARED_CAPS;
115306
116304
  exports.LINKED_DEVICES_SLOT = LINKED_DEVICES_SLOT;
115307
116305
  exports.LINKED_LABEL_STEP_PREFIX = LINKED_LABEL_STEP_PREFIX;
115308
116306
  exports.LLM_PROFILE_KIND_PATTERN = LLM_PROFILE_KIND_PATTERN;
@@ -115418,6 +116416,7 @@ exports.MAX_EXPRESSION_BINDINGS = require_composition.MAX_EXPRESSION_BINDINGS;
115418
116416
  exports.MAX_EXPRESSION_CALL_ARGS = require_composition.MAX_EXPRESSION_CALL_ARGS;
115419
116417
  exports.MAX_EXPRESSION_EVAL_STEPS = require_composition.MAX_EXPRESSION_EVAL_STEPS;
115420
116418
  exports.MAX_EXPRESSION_SOURCE_LENGTH = require_composition.MAX_EXPRESSION_SOURCE_LENGTH;
116419
+ exports.MAX_HELPER_MEMBERS = require_composition.MAX_HELPER_MEMBERS;
115421
116420
  exports.MAX_KEYS = MAX_KEYS;
115422
116421
  exports.MAX_REASONS_PER_KEY = MAX_REASONS_PER_KEY;
115423
116422
  exports.MAX_REQUEUED_BUCKETS_PER_SERIES = MAX_REQUEUED_BUCKETS_PER_SERIES;
@@ -115609,6 +116608,7 @@ exports.NETWORK_LINK_UNKNOWN = NETWORK_LINK_UNKNOWN;
115609
116608
  exports.NODE_BENCHMARK_DEFAULTS = NODE_BENCHMARK_DEFAULTS;
115610
116609
  exports.NODE_COLOR_IDS = require_node_color.NODE_COLOR_IDS;
115611
116610
  exports.NO_MEASURED_CAPACITY = NO_MEASURED_CAPACITY;
116611
+ exports.NUMERIC_AGGREGATES = require_composition.NUMERIC_AGGREGATES;
115612
116612
  exports.NativeCropBboxSchema = NativeCropBboxSchema;
115613
116613
  exports.NativeCropRefSchema = NativeCropRefSchema;
115614
116614
  exports.NativeCropResultSchema = NativeCropResultSchema;
@@ -116510,6 +117510,7 @@ exports.actionsForDevice = actionsForDevice;
116510
117510
  exports.actionsForDeviceType = actionsForDeviceType;
116511
117511
  exports.actionsForDevices = actionsForDevices;
116512
117512
  exports.activateAlarmProfile = activateAlarmProfile;
117513
+ exports.activeForReducer = activeForReducer;
116513
117514
  exports.addonCatalogHref = addonCatalogHref;
116514
117515
  exports.addonPagesCapability = addonPagesCapability;
116515
117516
  exports.addonPagesSourceCapability = addonPagesSourceCapability;
@@ -116663,6 +117664,7 @@ exports.commitWatchdogRestart = commitWatchdogRestart;
116663
117664
  exports.compareToTarget = compareToTarget;
116664
117665
  exports.compileExpression = require_composition.compileExpression;
116665
117666
  exports.compileExpressionSafe = require_composition.compileExpressionSafe;
117667
+ exports.compileHelper = compileHelper;
116666
117668
  exports.compileKeyedArrayOverride = compileKeyedArrayOverride;
116667
117669
  exports.compilePulseOverride = compilePulseOverride;
116668
117670
  exports.compileScalarOverride = compileScalarOverride;
@@ -116825,6 +117827,7 @@ exports.enumerateItemArrayFields = enumerateItemArrayFields;
116825
117827
  exports.enumerateSchemaFields = enumerateSchemaFields;
116826
117828
  exports.errMsg = require_err_msg.errMsg;
116827
117829
  exports.estimateNodeBenchmarkDurationMs = estimateNodeBenchmarkDurationMs;
117830
+ exports.evaluateAggregate = evaluateAggregate;
116828
117831
  exports.evaluateAst = require_composition.evaluateAst;
116829
117832
  exports.evaluateCompositionField = evaluateCompositionField;
116830
117833
  exports.evaluateCount = require_composition.evaluateCount;
@@ -116855,6 +117858,7 @@ exports.faceGalleryCapability = faceGalleryCapability;
116855
117858
  exports.failureContributionCapability = failureContributionCapability;
116856
117859
  exports.failureRate = failureRate;
116857
117860
  exports.fanControlCapability = fanControlCapability;
117861
+ exports.fanOutTargets = fanOutTargets;
116858
117862
  exports.featureFieldEntries = require_composition.featureFieldEntries;
116859
117863
  exports.featureOfRole = featureOfRole;
116860
117864
  exports.featureProbeCapability = featureProbeCapability;
@@ -116898,10 +117902,14 @@ exports.gifFilterComplex = gifFilterComplex;
116898
117902
  exports.gifFromMp4Args = gifFromMp4Args;
116899
117903
  exports.globalSecretScope = require_sleep.globalSecretScope;
116900
117904
  exports.grantRowsOf = grantRowsOf;
117905
+ exports.groupCommandsCapability = groupCommandsCapability;
117906
+ exports.groupStatusCapability = groupStatusCapability;
117907
+ exports.groupTemplate = groupTemplate;
116901
117908
  exports.hasModelBoundOverrides = hasModelBoundOverrides;
116902
117909
  exports.hasMotionTrigger = hasMotionTrigger;
116903
117910
  exports.hasUrlScheme = hasUrlScheme;
116904
117911
  exports.heatingValveCapability = heatingValveCapability;
117912
+ exports.helperSaveProblems = helperSaveProblems;
116905
117913
  exports.hfModelUrl = require_sleep.hfModelUrl;
116906
117914
  exports.historyFieldsFor = historyFieldsFor;
116907
117915
  exports.historyItemFieldPath = require_sleep.historyItemFieldPath;
@@ -117134,6 +118142,7 @@ exports.parseAppAuthCallback = parseAppAuthCallback;
117134
118142
  exports.parseAppFlowRequest = parseAppFlowRequest;
117135
118143
  exports.parseAppPageLang = parseAppPageLang;
117136
118144
  exports.parseCameraStreamConfig = parseCameraStreamConfig;
118145
+ exports.parseColorInput = parseColorInput;
117137
118146
  exports.parseCredentialScopes = parseCredentialScopes;
117138
118147
  exports.parseDeviceEnrollmentLink = parseDeviceEnrollmentLink;
117139
118148
  exports.parseExpression = require_composition.parseExpression;
@@ -117243,6 +118252,7 @@ exports.recordsCapability = recordsCapability;
117243
118252
  exports.recordsErrorFromMessage = require_sleep.recordsErrorFromMessage;
117244
118253
  exports.rectsToCells = rectsToCells;
117245
118254
  exports.reducePoints = reducePoints;
118255
+ exports.reducerForActive = reducerForActive;
117246
118256
  exports.registerKnownSecret = require_sleep.registerKnownSecret;
117247
118257
  exports.remapCropDetections = remapCropDetections;
117248
118258
  exports.renameAlarmProfile = renameAlarmProfile;
@@ -117319,6 +118329,7 @@ exports.ruleSection = ruleSection;
117319
118329
  exports.ruleSectionOf = ruleSectionOf;
117320
118330
  exports.ruleSeedForSection = ruleSeedForSection;
117321
118331
  exports.ruleTriggerZoneIds = ruleTriggerZoneIds;
118332
+ exports.runFanOut = runFanOut;
117322
118333
  exports.runInferenceStep = runInferenceStep;
117323
118334
  exports.runningFromDishwasherOperation = runningFromDishwasherOperation;
117324
118335
  exports.runningFromLawnMower = runningFromLawnMower;
@@ -117329,6 +118340,7 @@ exports.runtimeDevices = runtimeDevices;
117329
118340
  exports.runtimeFieldUnit = runtimeFieldUnit;
117330
118341
  exports.runtimeStatePolicyFor = runtimeStatePolicyFor;
117331
118342
  exports.sameDoFamily = sameDoFamily;
118343
+ exports.sameHelperBody = sameHelperBody;
117332
118344
  exports.sameRead = sameRead;
117333
118345
  exports.sceneMonitorCapability = sceneMonitorCapability;
117334
118346
  exports.scheduleForSendTimes = scheduleForSendTimes;
@@ -117366,6 +118378,8 @@ exports.settingValuesEqual = settingValuesEqual;
117366
118378
  exports.settingsBelow = settingsBelow;
117367
118379
  exports.settingsStoreCapability = settingsStoreCapability;
117368
118380
  exports.shareViewGrantOf = shareViewGrantOf;
118381
+ exports.sharedColorModes = sharedColorModes;
118382
+ exports.sharedLightCaps = sharedLightCaps;
117369
118383
  exports.shortHostname = shortHostname;
117370
118384
  exports.shortSecretRefHash = require_sleep.shortSecretRefHash;
117371
118385
  exports.signalPercentFromBars = signalPercentFromBars;
@@ -117378,6 +118392,7 @@ exports.sliceChangedAt = require_composition.sliceChangedAt;
117378
118392
  exports.smokeCapability = smokeCapability;
117379
118393
  exports.smtpProviderCapability = smtpProviderCapability;
117380
118394
  exports.snapshotCapability = snapshotCapability;
118395
+ exports.sourcePickForTemplate = sourcePickForTemplate;
117381
118396
  exports.splitTranslationRef = splitTranslationRef;
117382
118397
  exports.squareAround = squareAround;
117383
118398
  exports.ssoBridgeCapability = ssoBridgeCapability;
@@ -117440,6 +118455,7 @@ exports.taskPhaseSchema = taskPhaseSchema;
117440
118455
  exports.taskTargetSchema = taskTargetSchema;
117441
118456
  exports.temperatureSensorCapability = temperatureSensorCapability;
117442
118457
  exports.templateCarriesSummary = templateCarriesSummary;
118458
+ exports.templateDeviceType = templateDeviceType;
117443
118459
  exports.templateVarDeliveryApplies = templateVarDeliveryApplies;
117444
118460
  exports.templateVarKindApplies = templateVarKindApplies;
117445
118461
  exports.templateVarSystemEventApplies = templateVarSystemEventApplies;