@camstack/types 1.2.417 → 1.2.418

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 (42) hide show
  1. package/dist/addon.js +1 -1
  2. package/dist/addon.mjs +1 -1
  3. package/dist/capabilities/capability-definition.d.ts +5 -0
  4. package/dist/capabilities/composer.cap.d.ts +198 -0
  5. package/dist/capabilities/core-blocks.cap.d.ts +1420 -0
  6. package/dist/capabilities/group-status.cap.d.ts +46 -0
  7. package/dist/capabilities/index.d.ts +3 -1
  8. package/dist/capabilities/motion.cap.d.ts +12 -4
  9. package/dist/client.js +3 -0
  10. package/dist/client.mjs +3 -0
  11. package/dist/composition/composition-report.d.ts +72 -0
  12. package/dist/composition/composition.d.ts +285 -5
  13. package/dist/composition/helpers/aggregate.d.ts +41 -0
  14. package/dist/composition/helpers/catalog.d.ts +42 -0
  15. package/dist/composition/helpers/compile.d.ts +22 -0
  16. package/dist/composition/helpers/index.d.ts +6 -0
  17. package/dist/composition/helpers/save.d.ts +18 -0
  18. package/dist/composition/helpers/source-pick.d.ts +40 -0
  19. package/dist/composition/helpers/spec.d.ts +38 -0
  20. package/dist/composition/index.d.ts +1 -0
  21. package/dist/composition/source-ref.d.ts +11 -0
  22. package/dist/composition/validate-composition.d.ts +5 -0
  23. package/dist/{composition-kEl9mevu.mjs → composition-B85l9j1M.mjs} +114 -8
  24. package/dist/{composition-DsmkwP9-.js → composition-OJKOJJD-.js} +179 -7
  25. package/dist/device/cap-vocabulary/entries/sensors.d.ts +1 -1
  26. package/dist/generated/addon-api.d.ts +14 -0
  27. package/dist/generated/addon-cap-facts.d.ts +1 -1
  28. package/dist/generated/cap-status-types.d.ts +3 -1
  29. package/dist/generated/capability-router-map.d.ts +5 -2
  30. package/dist/generated/device-local-state.d.ts +3 -0
  31. package/dist/generated/device-proxy.d.ts +3 -0
  32. package/dist/generated/history-catalog.d.ts +1 -1
  33. package/dist/generated/method-access-map.d.ts +1 -1
  34. package/dist/generated/method-device-selectors.d.ts +1 -1
  35. package/dist/generated/runtime-state-durability.d.ts +1 -1
  36. package/dist/index.js +706 -12
  37. package/dist/index.mjs +686 -13
  38. package/dist/node.js +1 -1
  39. package/dist/node.mjs +1 -1
  40. package/dist/{sleep-gtskVoMw.js → sleep-7Gw3GJ4n.js} +18 -0
  41. package/dist/{sleep-CARd6wZF.mjs → sleep-B81gwQuR.mjs} +18 -0
  42. 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");
2
+ const require_sleep = require("./sleep-7Gw3GJ4n.js");
3
3
  const require_event_category = require("./event-category-DXZ3f9Q5.js");
4
- const require_composition = require("./composition-DsmkwP9-.js");
4
+ const require_composition = require("./composition-OJKOJJD-.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,388 @@ 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
+ baseUnit: require_sleep.baseUnitOf(input.quantity),
13288
+ aggregates: require_composition.NUMERIC_AGGREGATES,
13289
+ accept: [{
13290
+ cap: input.outputCap,
13291
+ fieldPath: input.outputField
13292
+ }]
13293
+ };
13294
+ }
13295
+ function binary(input) {
13296
+ return {
13297
+ ...input,
13298
+ family: "binary",
13299
+ deviceType: require_err_msg.DeviceType.Sensor,
13300
+ memberDeviceType: require_err_msg.DeviceType.Sensor,
13301
+ quantity: "none",
13302
+ baseUnit: void 0,
13303
+ aggregates: require_composition.BINARY_AGGREGATES,
13304
+ empty: "offline"
13305
+ };
13306
+ }
13307
+ var GROUP_TEMPLATES = [
13308
+ numeric({
13309
+ id: "temperature",
13310
+ summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
13311
+ role: require_err_msg.DeviceRole.TemperatureSensor,
13312
+ outputCap: "temperature-sensor",
13313
+ outputField: "celsius",
13314
+ quantity: "temperature",
13315
+ defaultAggregate: "mean",
13316
+ empty: "null",
13317
+ companions: [NOW]
13318
+ }),
13319
+ numeric({
13320
+ id: "humidity",
13321
+ summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
13322
+ role: require_err_msg.DeviceRole.HumiditySensor,
13323
+ outputCap: "humidity-sensor",
13324
+ outputField: "percent",
13325
+ quantity: "humidity",
13326
+ defaultAggregate: "mean",
13327
+ empty: "null",
13328
+ companions: [NOW]
13329
+ }),
13330
+ numeric({
13331
+ id: "pressure",
13332
+ summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
13333
+ role: require_err_msg.DeviceRole.PressureSensor,
13334
+ outputCap: "pressure-sensor",
13335
+ outputField: "hpa",
13336
+ quantity: "pressure",
13337
+ defaultAggregate: "mean",
13338
+ empty: "null",
13339
+ companions: [NOW]
13340
+ }),
13341
+ numeric({
13342
+ id: "illuminance",
13343
+ summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
13344
+ role: require_err_msg.DeviceRole.AmbientLightSensor,
13345
+ outputCap: "ambient-light-sensor",
13346
+ outputField: "lux",
13347
+ quantity: "illuminance",
13348
+ defaultAggregate: "mean",
13349
+ empty: "null",
13350
+ companions: [NOW]
13351
+ }),
13352
+ numeric({
13353
+ id: "power",
13354
+ summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
13355
+ role: require_err_msg.DeviceRole.PowerSensor,
13356
+ outputCap: "power-meter",
13357
+ outputField: "watts",
13358
+ quantity: "power",
13359
+ defaultAggregate: "sum",
13360
+ empty: "omit",
13361
+ companions: [NOW]
13362
+ }),
13363
+ numeric({
13364
+ id: "energy",
13365
+ summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
13366
+ role: require_err_msg.DeviceRole.EnergySensor,
13367
+ outputCap: "power-meter",
13368
+ outputField: "kwhTotal",
13369
+ quantity: "energy",
13370
+ defaultAggregate: "sum",
13371
+ empty: "omit",
13372
+ companions: [NOW]
13373
+ }),
13374
+ numeric({
13375
+ id: "battery",
13376
+ summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
13377
+ role: require_err_msg.DeviceRole.BatterySensor,
13378
+ outputCap: "battery",
13379
+ outputField: "percentage",
13380
+ quantity: "percentage",
13381
+ defaultAggregate: "mean",
13382
+ empty: "null",
13383
+ companions: [
13384
+ {
13385
+ fieldPath: "charging",
13386
+ expr: "\"unknown\""
13387
+ },
13388
+ {
13389
+ fieldPath: "sleeping",
13390
+ expr: "false"
13391
+ },
13392
+ {
13393
+ fieldPath: "lastUpdated",
13394
+ expr: "now"
13395
+ }
13396
+ ]
13397
+ }),
13398
+ numeric({
13399
+ id: "numeric",
13400
+ summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
13401
+ role: require_err_msg.DeviceRole.NumericSensor,
13402
+ outputCap: "numeric-sensor",
13403
+ outputField: "value",
13404
+ quantity: "device",
13405
+ defaultAggregate: "mean",
13406
+ empty: "null",
13407
+ companions: [NOW]
13408
+ }),
13409
+ binary({
13410
+ id: "motion",
13411
+ summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
13412
+ role: require_err_msg.DeviceRole.MotionSensor,
13413
+ outputCap: "motion",
13414
+ outputField: "detected",
13415
+ defaultAggregate: "any",
13416
+ accept: [{
13417
+ cap: "motion",
13418
+ fieldPath: "detected"
13419
+ }],
13420
+ companions: [{
13421
+ fieldPath: "lastDetectedAt",
13422
+ expr: "null"
13423
+ }, {
13424
+ fieldPath: "autoClearAfterMs",
13425
+ expr: "null"
13426
+ }]
13427
+ }),
13428
+ binary({
13429
+ id: "contact",
13430
+ summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
13431
+ role: require_err_msg.DeviceRole.ContactSensor,
13432
+ outputCap: "contact",
13433
+ outputField: "entryOpen",
13434
+ defaultAggregate: "any",
13435
+ accept: [{
13436
+ cap: "contact",
13437
+ fieldPath: "entryOpen"
13438
+ }],
13439
+ companions: [CHANGED]
13440
+ }),
13441
+ binary({
13442
+ id: "leak",
13443
+ summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
13444
+ role: require_err_msg.DeviceRole.LeakSensor,
13445
+ outputCap: "flood",
13446
+ outputField: "flooded",
13447
+ defaultAggregate: "any",
13448
+ accept: [{
13449
+ cap: "flood",
13450
+ fieldPath: "flooded"
13451
+ }],
13452
+ companions: [CHANGED]
13453
+ }),
13454
+ binary({
13455
+ id: "smoke",
13456
+ summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
13457
+ role: require_err_msg.DeviceRole.SmokeSensor,
13458
+ outputCap: "smoke",
13459
+ outputField: "detected",
13460
+ defaultAggregate: "any",
13461
+ accept: [{
13462
+ cap: "smoke",
13463
+ fieldPath: "detected"
13464
+ }],
13465
+ companions: [CHANGED]
13466
+ }),
13467
+ binary({
13468
+ id: "occupancy",
13469
+ summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
13470
+ role: require_err_msg.DeviceRole.BinarySensor,
13471
+ outputCap: "binary",
13472
+ outputField: "on",
13473
+ defaultAggregate: "any",
13474
+ accept: [{
13475
+ cap: "motion",
13476
+ fieldPath: "detected"
13477
+ }, {
13478
+ cap: "binary",
13479
+ fieldPath: "on"
13480
+ }],
13481
+ companions: [CHANGED]
13482
+ }),
13483
+ binary({
13484
+ id: "binary",
13485
+ summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
13486
+ role: require_err_msg.DeviceRole.BinarySensor,
13487
+ outputCap: "binary",
13488
+ outputField: "on",
13489
+ defaultAggregate: "any",
13490
+ accept: [{
13491
+ cap: "binary",
13492
+ fieldPath: "on"
13493
+ }],
13494
+ companions: [CHANGED]
13495
+ })
13496
+ ];
13497
+ var BY_ID = new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
13498
+ function groupTemplate(id) {
13499
+ return BY_ID.get(id) ?? null;
13500
+ }
13501
+ //#endregion
13502
+ //#region src/composition/helpers/compile.ts
13503
+ function sameSource(a, b) {
13504
+ return a.addonId === b.addonId && a.stableId === b.stableId;
13505
+ }
13506
+ function sameMember(a, b) {
13507
+ return sameSource(a.source, b.source) && a.cap === b.cap && a.fieldPath === b.fieldPath;
13508
+ }
13509
+ function accepted(template, member) {
13510
+ return template.accept.some((field) => field.cap === member.cap && field.fieldPath === member.fieldPath);
13511
+ }
13512
+ function memberProblems(template, spec) {
13513
+ return spec.members.flatMap((member, index) => {
13514
+ const at = `helper.members[${index}]`;
13515
+ const problems = [];
13516
+ if (!accepted(template, member)) {
13517
+ const allowed = template.accept.map((field) => `${field.cap}.${field.fieldPath}`).join(" or ");
13518
+ problems.push(problem("member-constraint", at, `a ${template.id} group reads ${allowed}; this member is ${member.cap}.${member.fieldPath}`));
13519
+ }
13520
+ if (spec.members.slice(0, index).some((other) => sameMember(other, member))) problems.push(problem("member-constraint", at, "this member is already in the group"));
13521
+ return problems;
13522
+ });
13523
+ }
13524
+ function aggregateSource(template, spec, reads, publish) {
13525
+ return {
13526
+ kind: "aggregate",
13527
+ reducer: spec.aggregate,
13528
+ reads: [...reads],
13529
+ publish,
13530
+ empty: template.empty
13531
+ };
13532
+ }
13533
+ function expressionSource(expr) {
13534
+ return {
13535
+ kind: "expression",
13536
+ expr,
13537
+ bindings: {}
13538
+ };
13539
+ }
13540
+ function draftOf$1(template, spec) {
13541
+ const reads = spec.members.map((member) => ({
13542
+ source: member.source,
13543
+ cap: member.cap,
13544
+ fieldPath: member.fieldPath
13545
+ }));
13546
+ const companions = Object.fromEntries(template.companions.map((companion) => [companion.fieldPath, expressionSource(companion.expr)]));
13547
+ return {
13548
+ target: {
13549
+ kind: "new",
13550
+ type: template.deviceType,
13551
+ role: template.role
13552
+ },
13553
+ helper: spec,
13554
+ features: [{
13555
+ kind: "fields",
13556
+ cap: template.outputCap,
13557
+ fields: {
13558
+ [template.outputField]: aggregateSource(template, spec, reads, "value"),
13559
+ ...companions
13560
+ }
13561
+ }, {
13562
+ kind: "fields",
13563
+ cap: "group-status",
13564
+ fields: {
13565
+ included: aggregateSource(template, spec, reads, "included"),
13566
+ excluded: aggregateSource(template, spec, reads, "excluded"),
13567
+ total: aggregateSource(template, spec, reads, "total")
13568
+ }
13569
+ }]
13570
+ };
13571
+ }
13572
+ function parseDraft(draft) {
13573
+ const parsed = require_composition.CompositionSchema.safeParse(draft);
13574
+ if (parsed.success) return {
13575
+ ok: true,
13576
+ composition: parsed.data
13577
+ };
13578
+ return {
13579
+ ok: false,
13580
+ problems: [problem("helper-mismatch", "helper", `the template did not compile: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`)]
13581
+ };
13582
+ }
13583
+ /** Compile a group template to a new-device composition. Refusals are named. */
13584
+ function compileHelper(spec) {
13585
+ const template = groupTemplate(spec.templateId);
13586
+ if (template === null) return {
13587
+ ok: false,
13588
+ problems: [problem("member-constraint", "helper.templateId", `unknown template \`${spec.templateId}\``)]
13589
+ };
13590
+ if (!template.aggregates.includes(spec.aggregate)) {
13591
+ const allowed = template.aggregates.join(", ");
13592
+ return {
13593
+ ok: false,
13594
+ problems: [problem("kind-mismatch", "helper.aggregate", `a ${template.id} group aggregates by ${allowed}, not \`${spec.aggregate}\``)]
13595
+ };
13596
+ }
13597
+ const members = memberProblems(template, spec);
13598
+ if (members.length > 0) return {
13599
+ ok: false,
13600
+ problems: members
13601
+ };
13602
+ return parseDraft(draftOf$1(template, spec));
13603
+ }
13604
+ /** The built body, ignoring `helper`, so a save can demand one writer. */
13605
+ function sameHelperBody(stored, compiled) {
13606
+ return JSON.stringify(stored.target) === JSON.stringify(compiled.target) && JSON.stringify(stored.features) === JSON.stringify(compiled.features);
13607
+ }
13608
+ function templateDeviceType(spec) {
13609
+ return groupTemplate(spec.templateId)?.memberDeviceType ?? null;
13610
+ }
13611
+ //#endregion
13612
+ //#region src/composition/helpers/save.ts
13613
+ function quantityProblems(spec, facts) {
13614
+ const template = groupTemplate(spec.templateId);
13615
+ if (template === null || template.family !== "numeric") return [];
13616
+ const known = spec.members.flatMap((member, index) => {
13617
+ const quantity = facts.get(require_composition.compositionSourceKey(member.source))?.quantity;
13618
+ return quantity === void 0 ? [] : [{
13619
+ index,
13620
+ quantity
13621
+ }];
13622
+ });
13623
+ 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}`)]);
13624
+ const distinct = [...new Set(known.map((member) => member.quantity))];
13625
+ if (distinct.length <= 1) return [];
13626
+ return [problem("mixed-quantity", "helper.members", `a numeric group requires one quantity; members report ${distinct.join(" and ")}`)];
13627
+ }
13628
+ function deviceTypeProblems(spec, facts) {
13629
+ const template = groupTemplate(spec.templateId);
13630
+ if (template === null) return [];
13631
+ return spec.members.flatMap((member, index) => {
13632
+ const deviceType = facts.get(require_composition.compositionSourceKey(member.source))?.deviceType;
13633
+ if (deviceType === void 0 || deviceType === template.memberDeviceType) return [];
13634
+ return [problem("member-constraint", `helper.members[${index}]`, `a ${template.id} group takes ${template.memberDeviceType} devices; this member is a ${deviceType}`)];
13635
+ });
13636
+ }
13637
+ /**
13638
+ * Problems that refuse a save. No `helper` key means a free composition: this
13639
+ * returns nothing, and expression semantics stay as they are.
13640
+ */
13641
+ function helperSaveProblems(composition, facts) {
13642
+ const spec = composition.helper;
13643
+ if (spec === void 0) return [];
13644
+ const compiled = compileHelper(spec);
13645
+ if (!compiled.ok) return compiled.problems;
13646
+ if (!sameHelperBody(composition, compiled.composition)) return [problem("helper-mismatch", "helper", "the stored features are not this template — the helper spec is the only writer")];
13647
+ return [...quantityProblems(spec, facts), ...deviceTypeProblems(spec, facts)];
13648
+ }
13649
+ //#endregion
13245
13650
  //#region src/composition/composition-graph.ts
13246
13651
  /**
13247
13652
  * The field graph across every composition, and the cycles in it (D659).
@@ -13472,6 +13877,7 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
13472
13877
  const role = roleOf(source);
13473
13878
  const unavailable = unavailableFor(tf, role, mode, def.name, fieldAt);
13474
13879
  if (!unavailable.ok) return refused(unavailable.problem);
13880
+ const omitEmpty = source.kind === "aggregate" && source.publish === "value" && source.empty === "omit";
13475
13881
  const plan = {
13476
13882
  cap: def.name,
13477
13883
  path,
@@ -13479,7 +13885,7 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
13479
13885
  kind: tf.kind,
13480
13886
  nullable: tf.nullable,
13481
13887
  required: tf.required,
13482
- unavailable: unavailable.unavailable,
13888
+ unavailable: omitEmpty ? "omit" : unavailable.unavailable,
13483
13889
  role,
13484
13890
  source,
13485
13891
  reads: [...require_composition.fieldReads(source)]
@@ -13744,10 +14150,15 @@ function validateComposition(composition, ctx) {
13744
14150
  if (refusedFeatures.some((at) => item.path === at || item.path.startsWith(`${at}.`))) return false;
13745
14151
  return refusedFeatures.length === 0 || item.path !== "features";
13746
14152
  });
14153
+ const facts = new Map([...ctx.sources].flatMap(([key, source]) => source.kind === "found" ? [[key, {
14154
+ deviceType: source.deviceType,
14155
+ quantity: source.quantity
14156
+ }]] : []));
13747
14157
  const problems = [
13748
14158
  ...plan.problems,
13749
14159
  ...sourceProblems(plan.fields, ctx, self),
13750
- ...cycles
14160
+ ...cycles,
14161
+ ...helperSaveProblems(composition, facts)
13751
14162
  ];
13752
14163
  return {
13753
14164
  ok: problems.length === 0,
@@ -64307,6 +64718,53 @@ var gasCapability = {
64307
64718
  volatileStateFields: ["lastChangedAt"]
64308
64719
  };
64309
64720
  //#endregion
64721
+ //#region src/capabilities/group-status.cap.ts
64722
+ /**
64723
+ * How many members of a helper group answered (D944). Counts are integers,
64724
+ * not measurements: zero included is a real count, never a stand-in reading.
64725
+ * The reading itself stays on the output capability. History is none — the
64726
+ * series that later statistics read is the output cap's own history block.
64727
+ */
64728
+ var GroupStatusSchema = zod.z.object({
64729
+ /** Members whose current value entered the aggregate. */
64730
+ included: zod.z.number().int().nonnegative().meta(require_sleep.readingMeta("count", {
64731
+ precision: 0,
64732
+ label: "Reporting"
64733
+ })),
64734
+ /** Members left out: offline, unknown, or not a finite reading (D393). */
64735
+ excluded: zod.z.number().int().nonnegative().meta(require_sleep.readingMeta("count", {
64736
+ precision: 0,
64737
+ label: "Excluded"
64738
+ })),
64739
+ /** `included` + `excluded`. */
64740
+ total: zod.z.number().int().nonnegative().meta(require_sleep.readingMeta("count", {
64741
+ precision: 0,
64742
+ label: "Members"
64743
+ }))
64744
+ });
64745
+ var groupStatusCapability = {
64746
+ name: "group-status",
64747
+ scope: "device",
64748
+ deviceNative: true,
64749
+ mode: "singleton",
64750
+ deviceTypes: [require_err_msg.DeviceType.Sensor],
64751
+ methods: {},
64752
+ status: {
64753
+ schema: GroupStatusSchema,
64754
+ kind: "push"
64755
+ },
64756
+ runtimeState: GroupStatusSchema,
64757
+ /**
64758
+ * Runtime-state durability: **session** — recomputed from members on the
64759
+ * next source event; a restored count would outlive the readings it named.
64760
+ *
64761
+ * See `RuntimeStateDurability`. Enforced by
64762
+ * `scripts/check-runtime-state-durability.ts`.
64763
+ */
64764
+ durability: "session",
64765
+ history: "none"
64766
+ };
64767
+ //#endregion
64310
64768
  //#region src/capabilities/heating-valve.cap.ts
64311
64769
  var HeatingValveStatusSchema = zod.z.object({
64312
64770
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
@@ -66402,12 +66860,18 @@ var motionCapability = {
66402
66860
  methods: {
66403
66861
  /**
66404
66862
  * 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.
66863
+ * for consumers that don't need the full status object. A composed
66864
+ * group answers from its slice (D944): unknown throws, it is not off.
66409
66865
  */
66410
66866
  isDetected: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.boolean()) },
66867
+ /**
66868
+ * A composed motion group serves `isDetected` from `detected` (D944).
66869
+ * Without this the cap stays uncomposable (`has-commands`).
66870
+ */
66871
+ composedMethods: { isDetected: {
66872
+ kind: "slice",
66873
+ field: "detected"
66874
+ } },
66411
66875
  events: {
66412
66876
  /**
66413
66877
  * Fires every time the runner transitions a camera between
@@ -77154,6 +77618,127 @@ function createDeviceExtensionProvider(options) {
77154
77618
  };
77155
77619
  }
77156
77620
  //#endregion
77621
+ //#region src/composition/helpers/aggregate.ts
77622
+ function isBinaryReducer(reducer) {
77623
+ return reducer === "any" || reducer === "all";
77624
+ }
77625
+ function includedValue(reducer, member) {
77626
+ if (member.state !== "fresh") return null;
77627
+ if (isBinaryReducer(reducer)) return typeof member.value === "boolean" ? member.value : null;
77628
+ return typeof member.value === "number" && Number.isFinite(member.value) ? member.value : null;
77629
+ }
77630
+ function median$1(values) {
77631
+ const sorted = [...values].toSorted((a, b) => a - b);
77632
+ const mid = Math.floor(sorted.length / 2);
77633
+ const right = sorted[mid];
77634
+ const left = sorted[mid - 1];
77635
+ if (right === void 0) throw new Error("median requires at least one finite number");
77636
+ if (sorted.length % 2 === 1) return right;
77637
+ if (left === void 0) throw new Error("median requires at least one finite number");
77638
+ return (left + right) / 2;
77639
+ }
77640
+ function reduceNumbers(reducer, values) {
77641
+ if (reducer === "min") return Math.min(...values);
77642
+ if (reducer === "max") return Math.max(...values);
77643
+ if (reducer === "sum") return values.reduce((sum, value) => sum + value, 0);
77644
+ if (reducer === "median") return median$1(values);
77645
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
77646
+ }
77647
+ function reduceBooleans(reducer, values) {
77648
+ return reducer === "all" ? values.every((value) => value) : values.some((value) => value);
77649
+ }
77650
+ function countsOf(included, total) {
77651
+ return {
77652
+ included,
77653
+ excluded: total - included,
77654
+ total
77655
+ };
77656
+ }
77657
+ function fatalReason(members) {
77658
+ const reasons = members.flatMap((member) => member.state === "unavailable" && member.fatal === true ? [member.reason ?? "source gone"] : []);
77659
+ return reasons.length === 0 ? null : reasons.join("; ");
77660
+ }
77661
+ function emptyOutcome(empty, counts) {
77662
+ if (empty === "null") return {
77663
+ kind: "value",
77664
+ value: null,
77665
+ counts
77666
+ };
77667
+ return {
77668
+ kind: "unavailable",
77669
+ fatal: false,
77670
+ reason: "no member included — unknown is not 0 or off",
77671
+ counts
77672
+ };
77673
+ }
77674
+ /** Pure. `members` is not mutated. An empty included set is null or unavailable, never 0 or false. */
77675
+ function evaluateAggregate(input) {
77676
+ const included = input.members.flatMap((member) => {
77677
+ const value = includedValue(input.reducer, member);
77678
+ return value === null ? [] : [value];
77679
+ });
77680
+ const counts = countsOf(included.length, input.members.length);
77681
+ const gone = fatalReason(input.members);
77682
+ if (gone !== null) return {
77683
+ kind: "unavailable",
77684
+ fatal: true,
77685
+ reason: gone,
77686
+ counts
77687
+ };
77688
+ if (input.publish === "included") return {
77689
+ kind: "value",
77690
+ value: counts.included,
77691
+ counts
77692
+ };
77693
+ if (input.publish === "excluded") return {
77694
+ kind: "value",
77695
+ value: counts.excluded,
77696
+ counts
77697
+ };
77698
+ if (input.publish === "total") return {
77699
+ kind: "value",
77700
+ value: counts.total,
77701
+ counts
77702
+ };
77703
+ if (included.length === 0) return emptyOutcome(input.empty, counts);
77704
+ if (isBinaryReducer(input.reducer)) {
77705
+ const flags = included.filter((value) => typeof value === "boolean");
77706
+ return {
77707
+ kind: "value",
77708
+ value: reduceBooleans(input.reducer, flags),
77709
+ counts
77710
+ };
77711
+ }
77712
+ const numbers = included.filter((value) => typeof value === "number");
77713
+ return {
77714
+ kind: "value",
77715
+ value: reduceNumbers(input.reducer, numbers),
77716
+ counts
77717
+ };
77718
+ }
77719
+ //#endregion
77720
+ //#region src/composition/helpers/source-pick.ts
77721
+ /** What the member step asks the selector for this template. */
77722
+ function sourcePickForTemplate(template) {
77723
+ const valueKind = template.family === "numeric" ? "number" : "boolean";
77724
+ return {
77725
+ purpose: "member",
77726
+ multiple: true,
77727
+ max: 64,
77728
+ deviceTypes: [template.memberDeviceType],
77729
+ accept: template.accept.map((field) => ({
77730
+ ...field,
77731
+ valueKind
77732
+ })),
77733
+ history: {
77734
+ required: false,
77735
+ minRetentionMs: null
77736
+ },
77737
+ mustBindCaps: [],
77738
+ exclude: []
77739
+ };
77740
+ }
77741
+ //#endregion
77157
77742
  //#region src/units/unit-table.ts
77158
77743
  /**
77159
77744
  * Frozen unit → spec table. `•` in the doc marks each dimension's canonical
@@ -77740,11 +78325,45 @@ function expressionOutcome(source, read, now, stateful) {
77740
78325
  deadline: deadlines.length > 0 ? Math.min(...deadlines) : null
77741
78326
  };
77742
78327
  }
78328
+ function aggregateRead(reading) {
78329
+ if (reading.state === "unavailable") return {
78330
+ state: "unavailable",
78331
+ fatal: reading.fatal,
78332
+ reason: reading.reason
78333
+ };
78334
+ return {
78335
+ state: reading.state,
78336
+ value: reading.value,
78337
+ ...reading.state === "stale" ? { reason: reading.reason } : {}
78338
+ };
78339
+ }
78340
+ function aggregateField(source, read) {
78341
+ const outcome = evaluateAggregate({
78342
+ reducer: source.reducer,
78343
+ members: source.reads.map((item) => aggregateRead(read(item))),
78344
+ publish: source.publish,
78345
+ empty: source.empty
78346
+ });
78347
+ if (outcome.kind === "value") return {
78348
+ state: "fresh",
78349
+ value: outcome.value,
78350
+ reason: null,
78351
+ deadline: null
78352
+ };
78353
+ return {
78354
+ state: "unavailable",
78355
+ value: null,
78356
+ reason: outcome.reason,
78357
+ fatal: outcome.fatal,
78358
+ confirmed: true
78359
+ };
78360
+ }
77743
78361
  function evaluateCompositionField(input) {
77744
78362
  const { source } = input;
77745
78363
  switch (source.kind) {
77746
78364
  case "from": return fromReading(input.read(source), source);
77747
78365
  case "expression": return expressionOutcome(source, input.read, input.now, input.stateful);
78366
+ case "aggregate": return aggregateField(source, input.read);
77748
78367
  case "code": return {
77749
78368
  state: "unavailable",
77750
78369
  value: null,
@@ -80600,6 +81219,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
80600
81219
  featureProbe: featureProbeCapability,
80601
81220
  flood: floodCapability,
80602
81221
  gas: gasCapability,
81222
+ groupStatus: groupStatusCapability,
80603
81223
  heatingValve: heatingValveCapability,
80604
81224
  humidifier: humidifierCapability,
80605
81225
  humiditySensor: humiditySensorCapability,
@@ -85925,6 +86545,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
85925
86545
  access: "view",
85926
86546
  role: "viewer"
85927
86547
  },
86548
+ "groupStatus.getStatus": {
86549
+ capName: "group-status",
86550
+ capScope: "device",
86551
+ addonId: null,
86552
+ access: "view",
86553
+ role: "viewer"
86554
+ },
85928
86555
  "heatingValve.getStatus": {
85929
86556
  capName: "heating-valve",
85930
86557
  capScope: "device",
@@ -92463,6 +93090,7 @@ var KNOWN_CAP_NAMES = [
92463
93090
  "filesystem-browse",
92464
93091
  "flood",
92465
93092
  "gas",
93093
+ "group-status",
92466
93094
  "heating-valve",
92467
93095
  "humidifier",
92468
93096
  "humidity-sensor",
@@ -92611,6 +93239,7 @@ var DEVICE_CAP_NAMES = [
92611
93239
  "feature-probe",
92612
93240
  "flood",
92613
93241
  "gas",
93242
+ "group-status",
92614
93243
  "heating-valve",
92615
93244
  "humidifier",
92616
93245
  "humidity-sensor",
@@ -96128,6 +96757,33 @@ var SENSOR_CAP_VOCABULARY = {
96128
96757
  icon: "flame"
96129
96758
  }]
96130
96759
  },
96760
+ "group-status": {
96761
+ scope: "device",
96762
+ noun: t("Group", "Gruppo"),
96763
+ state: [
96764
+ {
96765
+ kind: "numeric",
96766
+ field: "included",
96767
+ quantity: t("the members reporting", "i membri che rispondono"),
96768
+ label: t("Reporting", "Rispondono"),
96769
+ icon: "users"
96770
+ },
96771
+ {
96772
+ kind: "numeric",
96773
+ field: "excluded",
96774
+ quantity: t("the members left out", "i membri esclusi"),
96775
+ label: t("Excluded", "Esclusi"),
96776
+ icon: "users"
96777
+ },
96778
+ {
96779
+ kind: "numeric",
96780
+ field: "total",
96781
+ quantity: t("the member count", "il numero di membri"),
96782
+ label: t("Members", "Membri"),
96783
+ icon: "sigma"
96784
+ }
96785
+ ]
96786
+ },
96131
96787
  "humidity-sensor": {
96132
96788
  scope: "device",
96133
96789
  noun: t("Humidity", "Umidità"),
@@ -98265,6 +98921,7 @@ var CAP_NAMES_WITH_STATUS = [
98265
98921
  "feature-probe",
98266
98922
  "flood",
98267
98923
  "gas",
98924
+ "group-status",
98268
98925
  "heating-valve",
98269
98926
  "humidifier",
98270
98927
  "humidity-sensor",
@@ -98387,6 +99044,7 @@ var CAPABILITY_NAMES = {
98387
99044
  filesystemBrowse: "filesystem-browse",
98388
99045
  flood: "flood",
98389
99046
  gas: "gas",
99047
+ groupStatus: "group-status",
98390
99048
  heatingValve: "heating-valve",
98391
99049
  humidifier: "humidifier",
98392
99050
  humiditySensor: "humidity-sensor",
@@ -98793,6 +99451,10 @@ var CAPABILITY_ROUTER_KEYS = [
98793
99451
  key: "gas",
98794
99452
  name: "gas"
98795
99453
  },
99454
+ {
99455
+ key: "groupStatus",
99456
+ name: "group-status"
99457
+ },
98796
99458
  {
98797
99459
  key: "heatingValve",
98798
99460
  name: "heating-valve"
@@ -99306,6 +99968,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
99306
99968
  filesystemBrowseCapability,
99307
99969
  floodCapability,
99308
99970
  gasCapability,
99971
+ groupStatusCapability,
99309
99972
  heatingValveCapability,
99310
99973
  humidifierCapability,
99311
99974
  humiditySensorCapability,
@@ -100382,6 +101045,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
100382
101045
  form: "single",
100383
101046
  optional: false
100384
101047
  }],
101048
+ "groupStatus.getStatus": [{
101049
+ name: "deviceId",
101050
+ form: "single",
101051
+ optional: false
101052
+ }],
100385
101053
  "heatingValve.getStatus": [{
100386
101054
  name: "deviceId",
100387
101055
  form: "single",
@@ -102393,7 +103061,7 @@ function getCapsByProviderKind(kind) {
102393
103061
  //#region src/generated/runtime-state-durability.ts
102394
103062
  /**
102395
103063
  * Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
102396
- * `runtimeState`. 72 caps: 38 `restored`, 34 `session`.
103064
+ * `runtimeState`. 73 caps: 38 `restored`, 35 `session`.
102397
103065
  *
102398
103066
  * A cap absent from this map has no runtime-state slice at all. A cap PRESENT
102399
103067
  * with `durability: 'session'` has one and has decided not to keep it.
@@ -102511,6 +103179,10 @@ var RUNTIME_STATE_POLICY = {
102511
103179
  durability: "restored",
102512
103180
  volatileFields: ["lastChangedAt"]
102513
103181
  },
103182
+ "group-status": {
103183
+ durability: "session",
103184
+ volatileFields: []
103185
+ },
102514
103186
  "heating-valve": {
102515
103187
  durability: "session",
102516
103188
  volatileFields: ["lastFetchedAt"]
@@ -102853,7 +103525,7 @@ var BucketAccumulator = class {
102853
103525
  //#region src/generated/history-catalog.ts
102854
103526
  /**
102855
103527
  * Cap history catalog, projected from every `*.cap.ts` `history` block.
102856
- * 41 caps with series (75 series), 30 caps answered `'none'`.
103528
+ * 41 caps with series (75 series), 31 caps answered `'none'`.
102857
103529
  * Field keys are `runtimeState` paths (`a.b` into fixed objects only).
102858
103530
  */
102859
103531
  var HISTORY_CATALOG = {
@@ -103254,6 +103926,7 @@ var HISTORY_NONE_CAPS = [
103254
103926
  "doorbell",
103255
103927
  "event-emitter",
103256
103928
  "feature-probe",
103929
+ "group-status",
103257
103930
  "image",
103258
103931
  "image-settings",
103259
103932
  "intercom",
@@ -114509,6 +115182,7 @@ exports.ADMIN_SCOPE = ADMIN_SCOPE;
114509
115182
  exports.AGENT_MDNS_QUERY_NAME = AGENT_MDNS_QUERY_NAME;
114510
115183
  exports.AGENT_MDNS_SERVICE_TYPE = AGENT_MDNS_SERVICE_TYPE;
114511
115184
  exports.AGENT_MDNS_TXT_KEYS = AGENT_MDNS_TXT_KEYS;
115185
+ exports.AGGREGATE_REDUCERS = require_composition.AGGREGATE_REDUCERS;
114512
115186
  exports.AGGREGATE_THROUGHPUT_BY_KIND = AGGREGATE_THROUGHPUT_BY_KIND;
114513
115187
  exports.ALEXA_EGRESS_PROFILE = ALEXA_EGRESS_PROFILE;
114514
115188
  exports.ALL_CAPABILITY_DEFINITIONS = ALL_CAPABILITY_DEFINITIONS;
@@ -114563,6 +115237,7 @@ exports.AdoptionOutcomeSchema = AdoptionOutcomeSchema;
114563
115237
  exports.AdoptionReleaseInputSchema = ReleaseInputSchema;
114564
115238
  exports.AdoptionStatusSchema = AdoptionStatusSchema;
114565
115239
  exports.AgentLoadSummarySchema = AgentLoadSummarySchema;
115240
+ exports.AggregateReducerSchema = require_composition.AggregateReducerSchema;
114566
115241
  exports.AirQualitySensorStatusSchema = AirQualitySensorStatusSchema;
114567
115242
  exports.AlarmArmModeSchema = AlarmArmModeSchema;
114568
115243
  exports.AlarmPanelStatusSchema = AlarmPanelStatusSchema;
@@ -114629,6 +115304,7 @@ exports.BASE_LIVE_EGRESS_PROFILE = BASE_LIVE_EGRESS_PROFILE;
114629
115304
  exports.BATTERY_DEVICE_PROFILE = BATTERY_DEVICE_PROFILE;
114630
115305
  exports.BATTERY_UNREACHABLE_AFTER_MS = BATTERY_UNREACHABLE_AFTER_MS;
114631
115306
  exports.BENCH_ROOT_STEP_ID = BENCH_ROOT_STEP_ID;
115307
+ exports.BINARY_AGGREGATES = require_composition.BINARY_AGGREGATES;
114632
115308
  exports.BIRTH_DECISION_DEFAULT_LIMIT = BIRTH_DECISION_DEFAULT_LIMIT;
114633
115309
  exports.BOOT_RECOVERY_BACKOFF_MS = require_sleep.BOOT_RECOVERY_BACKOFF_MS;
114634
115310
  exports.BUILTIN_RESULT_KINDS = BUILTIN_RESULT_KINDS;
@@ -114839,6 +115515,7 @@ exports.ComposerApplyResultSchema = ComposerApplyResultSchema;
114839
115515
  exports.ComposerBlockSchema = ComposerBlockSchema;
114840
115516
  exports.ComposerBlockVerdictSchema = ComposerBlockVerdictSchema;
114841
115517
  exports.ComposerUnreadableBlockSchema = ComposerUnreadableBlockSchema;
115518
+ exports.CompositionAggregateSourceSchema = require_composition.CompositionAggregateSourceSchema;
114842
115519
  exports.CompositionBindingSchema = require_composition.CompositionBindingSchema;
114843
115520
  exports.CompositionBlockInputSchema = CompositionBlockInputSchema;
114844
115521
  exports.CompositionBlockStateSchema = CompositionBlockStateSchema;
@@ -115215,12 +115892,17 @@ exports.FrameInputSchema = FrameInputSchema;
115215
115892
  exports.FrameLazyCountersSchema = FrameLazyCountersSchema;
115216
115893
  exports.FrameLazyMetricsSchema = FrameLazyMetricsSchema;
115217
115894
  exports.G711_SCALE_CORRECTION_DB = G711_SCALE_CORRECTION_DB;
115895
+ exports.GROUP_TEMPLATES = GROUP_TEMPLATES;
115896
+ exports.GROUP_TEMPLATE_IDS = require_composition.GROUP_TEMPLATE_IDS;
115218
115897
  exports.GasStatusSchema = GasStatusSchema;
115219
115898
  exports.GetLoggingSettingsInputSchema = GetLoggingSettingsInputSchema;
115220
115899
  exports.GetStreamWithCodecInputSchema = GetStreamWithCodecInputSchema;
115221
115900
  exports.GlobalMetricsSchema = GlobalMetricsSchema;
115222
115901
  exports.GridLayoutPatchSchema = GridLayoutPatchSchema;
115223
115902
  exports.GridLayoutViewSchema = GridLayoutViewSchema;
115903
+ exports.GroupHelperSpecSchema = require_composition.GroupHelperSpecSchema;
115904
+ exports.GroupStatusSchema = GroupStatusSchema;
115905
+ exports.GroupTemplateIdSchema = require_composition.GroupTemplateIdSchema;
115224
115906
  exports.HAP_AUDIO_BASE = HAP_AUDIO_BASE;
115225
115907
  exports.HAP_AUDIO_BITRATE_KBPS = HAP_AUDIO_BITRATE_KBPS;
115226
115908
  exports.HAP_AUDIO_VBV_KBITS = HAP_AUDIO_VBV_KBITS;
@@ -115244,6 +115926,8 @@ exports.HWACCEL_OPTIONS = HWACCEL_OPTIONS;
115244
115926
  exports.HardwareClassIdSchema = HardwareClassIdSchema;
115245
115927
  exports.HealthStatusSchema = HealthStatusSchema;
115246
115928
  exports.HeatingValveStatusSchema = HeatingValveStatusSchema;
115929
+ exports.HelperMemberSchema = require_composition.HelperMemberSchema;
115930
+ exports.HelperSpecSchema = require_composition.HelperSpecSchema;
115247
115931
  exports.HfModelResolutionSchema = HfModelResolutionSchema;
115248
115932
  exports.HistoryPointSchema = HistoryPointSchema;
115249
115933
  exports.HistoryResolutionEnum = HistoryResolutionEnum;
@@ -115418,6 +116102,7 @@ exports.MAX_EXPRESSION_BINDINGS = require_composition.MAX_EXPRESSION_BINDINGS;
115418
116102
  exports.MAX_EXPRESSION_CALL_ARGS = require_composition.MAX_EXPRESSION_CALL_ARGS;
115419
116103
  exports.MAX_EXPRESSION_EVAL_STEPS = require_composition.MAX_EXPRESSION_EVAL_STEPS;
115420
116104
  exports.MAX_EXPRESSION_SOURCE_LENGTH = require_composition.MAX_EXPRESSION_SOURCE_LENGTH;
116105
+ exports.MAX_HELPER_MEMBERS = require_composition.MAX_HELPER_MEMBERS;
115421
116106
  exports.MAX_KEYS = MAX_KEYS;
115422
116107
  exports.MAX_REASONS_PER_KEY = MAX_REASONS_PER_KEY;
115423
116108
  exports.MAX_REQUEUED_BUCKETS_PER_SERIES = MAX_REQUEUED_BUCKETS_PER_SERIES;
@@ -115609,6 +116294,7 @@ exports.NETWORK_LINK_UNKNOWN = NETWORK_LINK_UNKNOWN;
115609
116294
  exports.NODE_BENCHMARK_DEFAULTS = NODE_BENCHMARK_DEFAULTS;
115610
116295
  exports.NODE_COLOR_IDS = require_node_color.NODE_COLOR_IDS;
115611
116296
  exports.NO_MEASURED_CAPACITY = NO_MEASURED_CAPACITY;
116297
+ exports.NUMERIC_AGGREGATES = require_composition.NUMERIC_AGGREGATES;
115612
116298
  exports.NativeCropBboxSchema = NativeCropBboxSchema;
115613
116299
  exports.NativeCropRefSchema = NativeCropRefSchema;
115614
116300
  exports.NativeCropResultSchema = NativeCropResultSchema;
@@ -116663,6 +117349,7 @@ exports.commitWatchdogRestart = commitWatchdogRestart;
116663
117349
  exports.compareToTarget = compareToTarget;
116664
117350
  exports.compileExpression = require_composition.compileExpression;
116665
117351
  exports.compileExpressionSafe = require_composition.compileExpressionSafe;
117352
+ exports.compileHelper = compileHelper;
116666
117353
  exports.compileKeyedArrayOverride = compileKeyedArrayOverride;
116667
117354
  exports.compilePulseOverride = compilePulseOverride;
116668
117355
  exports.compileScalarOverride = compileScalarOverride;
@@ -116825,6 +117512,7 @@ exports.enumerateItemArrayFields = enumerateItemArrayFields;
116825
117512
  exports.enumerateSchemaFields = enumerateSchemaFields;
116826
117513
  exports.errMsg = require_err_msg.errMsg;
116827
117514
  exports.estimateNodeBenchmarkDurationMs = estimateNodeBenchmarkDurationMs;
117515
+ exports.evaluateAggregate = evaluateAggregate;
116828
117516
  exports.evaluateAst = require_composition.evaluateAst;
116829
117517
  exports.evaluateCompositionField = evaluateCompositionField;
116830
117518
  exports.evaluateCount = require_composition.evaluateCount;
@@ -116898,10 +117586,13 @@ exports.gifFilterComplex = gifFilterComplex;
116898
117586
  exports.gifFromMp4Args = gifFromMp4Args;
116899
117587
  exports.globalSecretScope = require_sleep.globalSecretScope;
116900
117588
  exports.grantRowsOf = grantRowsOf;
117589
+ exports.groupStatusCapability = groupStatusCapability;
117590
+ exports.groupTemplate = groupTemplate;
116901
117591
  exports.hasModelBoundOverrides = hasModelBoundOverrides;
116902
117592
  exports.hasMotionTrigger = hasMotionTrigger;
116903
117593
  exports.hasUrlScheme = hasUrlScheme;
116904
117594
  exports.heatingValveCapability = heatingValveCapability;
117595
+ exports.helperSaveProblems = helperSaveProblems;
116905
117596
  exports.hfModelUrl = require_sleep.hfModelUrl;
116906
117597
  exports.historyFieldsFor = historyFieldsFor;
116907
117598
  exports.historyItemFieldPath = require_sleep.historyItemFieldPath;
@@ -117329,6 +118020,7 @@ exports.runtimeDevices = runtimeDevices;
117329
118020
  exports.runtimeFieldUnit = runtimeFieldUnit;
117330
118021
  exports.runtimeStatePolicyFor = runtimeStatePolicyFor;
117331
118022
  exports.sameDoFamily = sameDoFamily;
118023
+ exports.sameHelperBody = sameHelperBody;
117332
118024
  exports.sameRead = sameRead;
117333
118025
  exports.sceneMonitorCapability = sceneMonitorCapability;
117334
118026
  exports.scheduleForSendTimes = scheduleForSendTimes;
@@ -117378,6 +118070,7 @@ exports.sliceChangedAt = require_composition.sliceChangedAt;
117378
118070
  exports.smokeCapability = smokeCapability;
117379
118071
  exports.smtpProviderCapability = smtpProviderCapability;
117380
118072
  exports.snapshotCapability = snapshotCapability;
118073
+ exports.sourcePickForTemplate = sourcePickForTemplate;
117381
118074
  exports.splitTranslationRef = splitTranslationRef;
117382
118075
  exports.squareAround = squareAround;
117383
118076
  exports.ssoBridgeCapability = ssoBridgeCapability;
@@ -117440,6 +118133,7 @@ exports.taskPhaseSchema = taskPhaseSchema;
117440
118133
  exports.taskTargetSchema = taskTargetSchema;
117441
118134
  exports.temperatureSensorCapability = temperatureSensorCapability;
117442
118135
  exports.templateCarriesSummary = templateCarriesSummary;
118136
+ exports.templateDeviceType = templateDeviceType;
117443
118137
  exports.templateVarDeliveryApplies = templateVarDeliveryApplies;
117444
118138
  exports.templateVarKindApplies = templateVarKindApplies;
117445
118139
  exports.templateVarSystemEventApplies = templateVarSystemEventApplies;