@camstack/system 1.2.485 → 1.2.487

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 (88) hide show
  1. package/dist/{agent-https-DBP7P-ee.js → agent-https-0EEnqeUL.js} +1 -1
  2. package/dist/{agent-https-_EXvi6F8.mjs → agent-https-C24nO-la.mjs} +1 -1
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/autotrack/index.js +1 -1
  10. package/dist/builtins/autotrack/index.mjs +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
  13. package/dist/builtins/calendars/calendars.addon.js +1 -1
  14. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  15. package/dist/builtins/camera-grid/index.js +1 -1
  16. package/dist/builtins/camera-grid/index.mjs +1 -1
  17. package/dist/builtins/composer/actuator-dispatch.d.ts +13 -0
  18. package/dist/builtins/composer/actuator-groups.d.ts +54 -0
  19. package/dist/builtins/composer/actuator-invoke.d.ts +11 -0
  20. package/dist/builtins/composer/composed-device.d.ts +13 -24
  21. package/dist/builtins/composer/composer.addon.js +464 -18
  22. package/dist/builtins/composer/composer.addon.mjs +464 -18
  23. package/dist/builtins/composer/composer.d.ts +11 -1
  24. package/dist/builtins/composer/composition-runtime.d.ts +2 -0
  25. package/dist/builtins/console-logging/index.js +1 -1
  26. package/dist/builtins/console-logging/index.mjs +1 -1
  27. package/dist/builtins/core-blocks/composition-sources.d.ts +3 -1
  28. package/dist/builtins/core-blocks/core-blocks.addon.js +53 -28
  29. package/dist/builtins/core-blocks/core-blocks.addon.mjs +53 -28
  30. package/dist/builtins/device-history/device-history.addon.js +2 -2
  31. package/dist/builtins/device-history/device-history.addon.mjs +2 -2
  32. package/dist/builtins/device-manager/device-manager.addon.js +1 -1
  33. package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
  34. package/dist/builtins/hub-forwarder/index.js +1 -1
  35. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  36. package/dist/builtins/keychain/index.js +3 -3
  37. package/dist/builtins/keychain/index.mjs +3 -3
  38. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  39. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  40. package/dist/builtins/local-auth/local-auth.addon.js +2 -2
  41. package/dist/builtins/local-auth/local-auth.addon.mjs +2 -2
  42. package/dist/builtins/local-network/local-network.addon.js +2 -2
  43. package/dist/builtins/local-network/local-network.addon.mjs +2 -2
  44. package/dist/builtins/loki-logging/index.js +1 -1
  45. package/dist/builtins/loki-logging/index.mjs +1 -1
  46. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  47. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  48. package/dist/builtins/platform-probe/index.js +1 -1
  49. package/dist/builtins/platform-probe/index.mjs +1 -1
  50. package/dist/builtins/record-entries/index.js +1 -1
  51. package/dist/builtins/record-entries/index.mjs +1 -1
  52. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  53. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  54. package/dist/builtins/snapshot/index.js +1 -1
  55. package/dist/builtins/snapshot/index.mjs +1 -1
  56. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  57. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  58. package/dist/builtins/sqlite-storage/index.js +1 -1
  59. package/dist/builtins/sqlite-storage/index.mjs +1 -1
  60. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +2 -2
  61. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +2 -2
  62. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  63. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  64. package/dist/builtins/system-config/system-config.addon.js +3 -3
  65. package/dist/builtins/system-config/system-config.addon.mjs +284 -284
  66. package/dist/builtins/winston-logging/index.js +1 -1
  67. package/dist/builtins/winston-logging/index.mjs +1 -1
  68. package/dist/{composition-sources-BnZpIA8u.mjs → composition-sources-BA2e5vh_.mjs} +4 -2
  69. package/dist/{composition-sources-BSQneZV9.js → composition-sources-BulDAgW2.js} +4 -2
  70. package/dist/{constants-CQfTeCnB.js → constants-BntdWx4k.js} +1 -1
  71. package/dist/{constants-7D7xjw0h.mjs → constants-DZKo4kM2.mjs} +1 -1
  72. package/dist/{device-ca-D_4dI5gv.js → device-ca-BuRg4V4x.js} +1 -1
  73. package/dist/{device-ca-Bzd6UO_c.mjs → device-ca-DXm8IH3p.mjs} +1 -1
  74. package/dist/{dist-xCNJAQMh.js → dist-CrsVjBbk.js} +1127 -26
  75. package/dist/{dist-Df6c0RX_.mjs → dist-Dfwxsc_Y.mjs} +1062 -27
  76. package/dist/file-host-worker.js +1 -1
  77. package/dist/file-host-worker.mjs +1 -1
  78. package/dist/{hub-mdns-ciao-D7GMnEz0.mjs → hub-mdns-ciao-BbI8MNtQ.mjs} +2 -2
  79. package/dist/{hub-mdns-ciao-DRfmLR_Z.js → hub-mdns-ciao-CLroVKhP.js} +2 -2
  80. package/dist/index.js +7 -7
  81. package/dist/index.mjs +7 -7
  82. package/dist/{restore-archive-Co70oRya.mjs → restore-archive-BB5QxUIe.mjs} +82 -82
  83. package/dist/{restore-archive-DA7N6ZZA.js → restore-archive-CPoja7N3.js} +1 -1
  84. package/dist/{retention-DNDOPW7Z.js → retention-DgA4qLBj.js} +1 -1
  85. package/dist/{retention-DfCW-dZS.mjs → retention-Dz5t6cWO.mjs} +1 -1
  86. package/dist/{wal-maintenance-71-j48Ci.mjs → wal-maintenance-BJi3_DBN.mjs} +0 -0
  87. package/dist/{wal-maintenance-CA0L6WZ9.js → wal-maintenance-CL9hrbnn.js} +0 -0
  88. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import "node:crypto";
3
- //#region ../types/dist/event-category-DHXxB8t9.mjs
3
+ //#region ../types/dist/event-category-CT-hz5Rb.mjs
4
4
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
5
5
  EventCategory["SystemBoot"] = "system.boot";
6
6
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -326,6 +326,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
326
326
  /** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
327
327
  EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
328
328
  /**
329
+ * A camera's package LLM confirm has failed closed three times in a row
330
+ * (D931, 2026-10-26). One edge per camera until
331
+ * {@link PipelinePackageLlmAnswered}.
332
+ */
333
+ EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
334
+ /** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
335
+ EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
336
+ /**
329
337
  * Per-camera pipeline config was mutated by the orchestrator
330
338
  * (a settings change via `setAgentInferenceDevices` /
331
339
  * `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
@@ -765,7 +773,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
765
773
  return EventCategory;
766
774
  }({});
767
775
  //#endregion
768
- //#region ../types/dist/sleep-CARd6wZF.mjs
776
+ //#region ../types/dist/sleep-bykKrTgu.mjs
769
777
  /**
770
778
  * The audio chunk plane's byte format, and the ONE expansion from a coded
771
779
  * window to float samples (D455).
@@ -5183,6 +5191,8 @@ var CAP_NAMES = Object.freeze([
5183
5191
  "filesystem-browse",
5184
5192
  "flood",
5185
5193
  "gas",
5194
+ "group-commands",
5195
+ "group-status",
5186
5196
  "heating-valve",
5187
5197
  "humidifier",
5188
5198
  "humidity-sensor",
@@ -6001,6 +6011,20 @@ Object.freeze({
6001
6011
  "path": "detected",
6002
6012
  "valueType": "boolean"
6003
6013
  }],
6014
+ "group-status": [
6015
+ {
6016
+ "path": "included",
6017
+ "valueType": "number"
6018
+ },
6019
+ {
6020
+ "path": "excluded",
6021
+ "valueType": "number"
6022
+ },
6023
+ {
6024
+ "path": "total",
6025
+ "valueType": "number"
6026
+ }
6027
+ ],
6004
6028
  "heating-valve": [{
6005
6029
  "path": "position",
6006
6030
  "valueType": "number"
@@ -7468,7 +7492,7 @@ function errMsg(err) {
7468
7492
  return String(err);
7469
7493
  }
7470
7494
  //#endregion
7471
- //#region ../types/dist/composition-kEl9mevu.mjs
7495
+ //#region ../types/dist/composition-OhpuespA.mjs
7472
7496
  var AUDIO_ENCODER_BY_CODEC = {
7473
7497
  opus: "libopus",
7474
7498
  aac: "aac",
@@ -8986,6 +9010,75 @@ function evaluateExpressionSource(expr, bindingValues, now, opts) {
8986
9010
  }
8987
9011
  }
8988
9012
  /**
9013
+ * A composition source identity: `(addonId, stableId)`, never a numeric device
9014
+ * id. Split out so helper schemas can name it without a cycle through
9015
+ * `composition.ts` (D659).
9016
+ */
9017
+ var CompositionSourceRefSchema = z.object({
9018
+ /** The owning addon; `stableId` is unique only within it. */
9019
+ addonId: z.string().min(1),
9020
+ stableId: z.string().min(1)
9021
+ });
9022
+ var GROUP_TEMPLATE_IDS = [
9023
+ "temperature",
9024
+ "humidity",
9025
+ "pressure",
9026
+ "illuminance",
9027
+ "power",
9028
+ "energy",
9029
+ "battery",
9030
+ "numeric",
9031
+ "motion",
9032
+ "contact",
9033
+ "leak",
9034
+ "smoke",
9035
+ "occupancy",
9036
+ "binary",
9037
+ "switch",
9038
+ "light"
9039
+ ];
9040
+ var NUMERIC_AGGREGATES = [
9041
+ "mean",
9042
+ "median",
9043
+ "min",
9044
+ "max",
9045
+ "sum"
9046
+ ];
9047
+ var BINARY_AGGREGATES = ["any", "all"];
9048
+ /** How an actuator group decides it is on. Unknown members never count as off. */
9049
+ var ACTIVE_CRITERIA = ["at-least-one", "all"];
9050
+ var AGGREGATE_REDUCERS = [
9051
+ "mean",
9052
+ "median",
9053
+ "min",
9054
+ "max",
9055
+ "sum",
9056
+ "any",
9057
+ "all"
9058
+ ];
9059
+ var GroupTemplateIdSchema = z.enum(GROUP_TEMPLATE_IDS);
9060
+ var AggregateReducerSchema = z.enum(AGGREGATE_REDUCERS);
9061
+ var ActiveCriterionSchema = z.enum(ACTIVE_CRITERIA);
9062
+ /** One member. The field is stored so occupancy can name motion or binary. */
9063
+ var HelperMemberSchema = z.object({
9064
+ source: CompositionSourceRefSchema,
9065
+ cap: z.string().min(1),
9066
+ fieldPath: z.string().min(1)
9067
+ });
9068
+ /**
9069
+ * Phase 1a is groups only. Math, integral and statistics stay off this union
9070
+ * until the composer can run them — a control must not save a spec it cannot.
9071
+ */
9072
+ var GroupHelperSpecSchema = z.object({
9073
+ kind: z.literal("group"),
9074
+ templateId: GroupTemplateIdSchema,
9075
+ aggregate: AggregateReducerSchema,
9076
+ members: z.array(HelperMemberSchema).min(1).max(64),
9077
+ /** Actuator groups only. Readings leave this unset. */
9078
+ active: ActiveCriterionSchema.optional()
9079
+ });
9080
+ var HelperSpecSchema = z.discriminatedUnion("kind", [GroupHelperSpecSchema]);
9081
+ /**
8989
9082
  * A COMPOSITION: a device assembled from other devices' state (D659).
8990
9083
  *
8991
9084
  * The data half of the composed-devices spec §1. A composition is stored inside
@@ -9010,11 +9103,6 @@ var COMPOSER_ADDON_ID = "composer";
9010
9103
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
9011
9104
  /** Longest snippet a `code` source may carry (slice 4). */
9012
9105
  var MAX_COMPOSITION_CODE_LENGTH = 2e4;
9013
- var CompositionSourceRefSchema = z.object({
9014
- /** The owning addon; `stableId` is unique only within it. */
9015
- addonId: z.string().min(1),
9016
- stableId: z.string().min(1)
9017
- });
9018
9106
  /** One field of one capability of one source device. */
9019
9107
  var CompositionFieldReadSchema = z.object({
9020
9108
  source: CompositionSourceRefSchema,
@@ -9057,10 +9145,42 @@ var CompositionCodeSourceSchema = z.object({
9057
9145
  kind: z.literal("code"),
9058
9146
  code: z.string().min(1).max(MAX_COMPOSITION_CODE_LENGTH)
9059
9147
  });
9148
+ /**
9149
+ * `aggregate`: a group reducer. Offline and unknown reads are excluded, not
9150
+ * folded in as 0 or false (D944). Free expressions stay `expression` so a
9151
+ * stale member is still included there.
9152
+ */
9153
+ var CompositionAggregateSourceSchema = z.object({
9154
+ kind: z.literal("aggregate"),
9155
+ reducer: z.enum([
9156
+ "mean",
9157
+ "median",
9158
+ "min",
9159
+ "max",
9160
+ "sum",
9161
+ "any",
9162
+ "all"
9163
+ ]),
9164
+ reads: z.array(CompositionFieldReadSchema).min(1).max(64),
9165
+ /** `value` is the reading; the others are the member counts. */
9166
+ publish: z.enum([
9167
+ "value",
9168
+ "included",
9169
+ "excluded",
9170
+ "total"
9171
+ ]),
9172
+ /** What a `value` publish does when nobody is included. Counts ignore this. */
9173
+ empty: z.enum([
9174
+ "null",
9175
+ "omit",
9176
+ "offline"
9177
+ ])
9178
+ });
9060
9179
  var CompositionFieldSourceSchema = z.discriminatedUnion("kind", [
9061
9180
  CompositionFromSourceSchema,
9062
9181
  CompositionExpressionSourceSchema,
9063
- CompositionCodeSourceSchema
9182
+ CompositionCodeSourceSchema,
9183
+ CompositionAggregateSourceSchema
9064
9184
  ]);
9065
9185
  /** `forward`: RESERVED for slice 3. Argument mapping arrives there as an additive optional `args`. */
9066
9186
  var CompositionForwardCommandSchema = z.object({
@@ -9125,7 +9245,13 @@ var CompositionExistingTargetSchema = z.object({
9125
9245
  var CompositionTargetSchema = z.discriminatedUnion("kind", [CompositionNewTargetSchema, CompositionExistingTargetSchema]);
9126
9246
  var CompositionSchema = z.object({
9127
9247
  target: CompositionTargetSchema,
9128
- features: z.array(CompositionFeatureSchema).min(1).max(16)
9248
+ features: z.array(CompositionFeatureSchema).min(1).max(16),
9249
+ /**
9250
+ * Present when the block is a helper template. Absent on a free
9251
+ * composition (the room example, device 4603). The editor reads this,
9252
+ * never the compiled features.
9253
+ */
9254
+ helper: HelperSpecSchema.optional()
9129
9255
  }).superRefine((composition, ctx) => {
9130
9256
  const seen = /* @__PURE__ */ new Set();
9131
9257
  composition.features.forEach((feature, index) => {
@@ -9172,6 +9298,7 @@ function fieldReads(source) {
9172
9298
  cap: binding.cap,
9173
9299
  fieldPath: binding.fieldPath
9174
9300
  }] : []);
9301
+ case "aggregate": return source.reads;
9175
9302
  case "code": return [];
9176
9303
  }
9177
9304
  }
@@ -17363,7 +17490,10 @@ var CompositionProblemCodeSchema = z.enum([
17363
17490
  "target-missing",
17364
17491
  "target-unreadable",
17365
17492
  "not-replaceable",
17366
- "native-capability-replace"
17493
+ "native-capability-replace",
17494
+ "mixed-quantity",
17495
+ "helper-mismatch",
17496
+ "member-constraint"
17367
17497
  ]);
17368
17498
  /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
17369
17499
  var CompositionProblemSchema = z.object({
@@ -17387,7 +17517,8 @@ var CompositionUnavailableModeSchema = z.enum([
17387
17517
  "null",
17388
17518
  "offline",
17389
17519
  "unknown",
17390
- "release"
17520
+ "release",
17521
+ "omit"
17391
17522
  ]);
17392
17523
  /**
17393
17524
  * `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
@@ -17749,6 +17880,24 @@ function inferExpressionKinds(input) {
17749
17880
  * planner (`composition-items.ts`). Internal to the composition module — NOT
17750
17881
  * in the barrel: these are planner internals, not a published contract.
17751
17882
  */
17883
+ function aggregateKinds(source) {
17884
+ if (source.publish !== "value") return {
17885
+ ok: true,
17886
+ kinds: new Set(["number"])
17887
+ };
17888
+ if (source.reducer === "any" || source.reducer === "all") return {
17889
+ ok: true,
17890
+ kinds: new Set(["boolean"])
17891
+ };
17892
+ if (source.empty === "null") return {
17893
+ ok: true,
17894
+ kinds: new Set(["number", "null"])
17895
+ };
17896
+ return {
17897
+ ok: true,
17898
+ kinds: new Set(["number"])
17899
+ };
17900
+ }
17752
17901
  function readKinds(read, lookupCap) {
17753
17902
  const def = lookupCap(read.cap);
17754
17903
  const schema = def?.runtimeState ?? def?.status?.schema;
@@ -17776,6 +17925,7 @@ function sourceKinds(source, lookupCap) {
17776
17925
  code: "reserved-variant",
17777
17926
  message: "code fields arrive in slice 4"
17778
17927
  };
17928
+ if (source.kind === "aggregate") return aggregateKinds(source);
17779
17929
  const bindingKinds = /* @__PURE__ */ new Map();
17780
17930
  for (const [name, binding] of Object.entries(source.bindings)) {
17781
17931
  if (binding.kind === "literal") {
@@ -17970,6 +18120,515 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
17970
18120
  };
17971
18121
  }
17972
18122
  /**
18123
+ * One catalog row per base reading a group helper can build (D944 §3).
18124
+ * Data, not a form default written into the block.
18125
+ */
18126
+ var NOW = {
18127
+ fieldPath: "lastFetchedAt",
18128
+ expr: "now"
18129
+ };
18130
+ var CHANGED = {
18131
+ fieldPath: "lastChangedAt",
18132
+ expr: "now"
18133
+ };
18134
+ function numeric(input) {
18135
+ return {
18136
+ ...input,
18137
+ family: "numeric",
18138
+ deviceType: DeviceType.Sensor,
18139
+ memberDeviceType: DeviceType.Sensor,
18140
+ commandCaps: [],
18141
+ baseUnit: baseUnitOf(input.quantity),
18142
+ aggregates: NUMERIC_AGGREGATES,
18143
+ accept: [{
18144
+ cap: input.outputCap,
18145
+ fieldPath: input.outputField
18146
+ }]
18147
+ };
18148
+ }
18149
+ function binary(input) {
18150
+ return {
18151
+ ...input,
18152
+ family: "binary",
18153
+ deviceType: DeviceType.Sensor,
18154
+ memberDeviceType: DeviceType.Sensor,
18155
+ commandCaps: [],
18156
+ quantity: "none",
18157
+ baseUnit: void 0,
18158
+ aggregates: BINARY_AGGREGATES,
18159
+ empty: "offline"
18160
+ };
18161
+ }
18162
+ var GROUP_TEMPLATES = [
18163
+ numeric({
18164
+ id: "temperature",
18165
+ summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
18166
+ role: DeviceRole.TemperatureSensor,
18167
+ outputCap: "temperature-sensor",
18168
+ outputField: "celsius",
18169
+ quantity: "temperature",
18170
+ defaultAggregate: "mean",
18171
+ empty: "null",
18172
+ companions: [NOW]
18173
+ }),
18174
+ numeric({
18175
+ id: "humidity",
18176
+ summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
18177
+ role: DeviceRole.HumiditySensor,
18178
+ outputCap: "humidity-sensor",
18179
+ outputField: "percent",
18180
+ quantity: "humidity",
18181
+ defaultAggregate: "mean",
18182
+ empty: "null",
18183
+ companions: [NOW]
18184
+ }),
18185
+ numeric({
18186
+ id: "pressure",
18187
+ summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
18188
+ role: DeviceRole.PressureSensor,
18189
+ outputCap: "pressure-sensor",
18190
+ outputField: "hpa",
18191
+ quantity: "pressure",
18192
+ defaultAggregate: "mean",
18193
+ empty: "null",
18194
+ companions: [NOW]
18195
+ }),
18196
+ numeric({
18197
+ id: "illuminance",
18198
+ summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
18199
+ role: DeviceRole.AmbientLightSensor,
18200
+ outputCap: "ambient-light-sensor",
18201
+ outputField: "lux",
18202
+ quantity: "illuminance",
18203
+ defaultAggregate: "mean",
18204
+ empty: "null",
18205
+ companions: [NOW]
18206
+ }),
18207
+ numeric({
18208
+ id: "power",
18209
+ summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
18210
+ role: DeviceRole.PowerSensor,
18211
+ outputCap: "power-meter",
18212
+ outputField: "watts",
18213
+ quantity: "power",
18214
+ defaultAggregate: "sum",
18215
+ empty: "omit",
18216
+ companions: [NOW]
18217
+ }),
18218
+ numeric({
18219
+ id: "energy",
18220
+ summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
18221
+ role: DeviceRole.EnergySensor,
18222
+ outputCap: "power-meter",
18223
+ outputField: "kwhTotal",
18224
+ quantity: "energy",
18225
+ defaultAggregate: "sum",
18226
+ empty: "omit",
18227
+ companions: [NOW]
18228
+ }),
18229
+ numeric({
18230
+ id: "battery",
18231
+ summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
18232
+ role: DeviceRole.BatterySensor,
18233
+ outputCap: "battery",
18234
+ outputField: "percentage",
18235
+ quantity: "percentage",
18236
+ defaultAggregate: "mean",
18237
+ empty: "null",
18238
+ companions: [
18239
+ {
18240
+ fieldPath: "charging",
18241
+ expr: "\"unknown\""
18242
+ },
18243
+ {
18244
+ fieldPath: "sleeping",
18245
+ expr: "false"
18246
+ },
18247
+ {
18248
+ fieldPath: "lastUpdated",
18249
+ expr: "now"
18250
+ }
18251
+ ]
18252
+ }),
18253
+ numeric({
18254
+ id: "numeric",
18255
+ summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
18256
+ role: DeviceRole.NumericSensor,
18257
+ outputCap: "numeric-sensor",
18258
+ outputField: "value",
18259
+ quantity: "device",
18260
+ defaultAggregate: "mean",
18261
+ empty: "null",
18262
+ companions: [NOW]
18263
+ }),
18264
+ binary({
18265
+ id: "motion",
18266
+ summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
18267
+ role: DeviceRole.MotionSensor,
18268
+ outputCap: "motion",
18269
+ outputField: "detected",
18270
+ defaultAggregate: "any",
18271
+ accept: [{
18272
+ cap: "motion",
18273
+ fieldPath: "detected"
18274
+ }],
18275
+ companions: [{
18276
+ fieldPath: "lastDetectedAt",
18277
+ expr: "null"
18278
+ }, {
18279
+ fieldPath: "autoClearAfterMs",
18280
+ expr: "null"
18281
+ }]
18282
+ }),
18283
+ binary({
18284
+ id: "contact",
18285
+ summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
18286
+ role: DeviceRole.ContactSensor,
18287
+ outputCap: "contact",
18288
+ outputField: "entryOpen",
18289
+ defaultAggregate: "any",
18290
+ accept: [{
18291
+ cap: "contact",
18292
+ fieldPath: "entryOpen"
18293
+ }],
18294
+ companions: [CHANGED]
18295
+ }),
18296
+ binary({
18297
+ id: "leak",
18298
+ summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
18299
+ role: DeviceRole.LeakSensor,
18300
+ outputCap: "flood",
18301
+ outputField: "flooded",
18302
+ defaultAggregate: "any",
18303
+ accept: [{
18304
+ cap: "flood",
18305
+ fieldPath: "flooded"
18306
+ }],
18307
+ companions: [CHANGED]
18308
+ }),
18309
+ binary({
18310
+ id: "smoke",
18311
+ summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
18312
+ role: DeviceRole.SmokeSensor,
18313
+ outputCap: "smoke",
18314
+ outputField: "detected",
18315
+ defaultAggregate: "any",
18316
+ accept: [{
18317
+ cap: "smoke",
18318
+ fieldPath: "detected"
18319
+ }],
18320
+ companions: [CHANGED]
18321
+ }),
18322
+ binary({
18323
+ id: "occupancy",
18324
+ summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
18325
+ role: DeviceRole.BinarySensor,
18326
+ outputCap: "binary",
18327
+ outputField: "on",
18328
+ defaultAggregate: "any",
18329
+ accept: [{
18330
+ cap: "motion",
18331
+ fieldPath: "detected"
18332
+ }, {
18333
+ cap: "binary",
18334
+ fieldPath: "on"
18335
+ }],
18336
+ companions: [CHANGED]
18337
+ }),
18338
+ binary({
18339
+ id: "binary",
18340
+ summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
18341
+ role: DeviceRole.BinarySensor,
18342
+ outputCap: "binary",
18343
+ outputField: "on",
18344
+ defaultAggregate: "any",
18345
+ accept: [{
18346
+ cap: "binary",
18347
+ fieldPath: "on"
18348
+ }],
18349
+ companions: [CHANGED]
18350
+ }),
18351
+ actuator({
18352
+ id: "switch",
18353
+ 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.",
18354
+ deviceType: DeviceType.Switch,
18355
+ outputCap: "switch",
18356
+ commandCaps: ["switch"]
18357
+ }),
18358
+ actuator({
18359
+ id: "light",
18360
+ 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.",
18361
+ deviceType: DeviceType.Light,
18362
+ outputCap: "switch",
18363
+ commandCaps: [
18364
+ "switch",
18365
+ "brightness",
18366
+ "color"
18367
+ ]
18368
+ })
18369
+ ];
18370
+ function actuator(input) {
18371
+ return {
18372
+ ...input,
18373
+ family: "actuator",
18374
+ role: void 0,
18375
+ memberDeviceType: input.deviceType,
18376
+ outputField: "on",
18377
+ quantity: "none",
18378
+ baseUnit: void 0,
18379
+ aggregates: BINARY_AGGREGATES,
18380
+ defaultAggregate: "any",
18381
+ empty: "offline",
18382
+ accept: [{
18383
+ cap: "switch",
18384
+ fieldPath: "on"
18385
+ }],
18386
+ companions: [CHANGED]
18387
+ };
18388
+ }
18389
+ var BY_ID = new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18390
+ function groupTemplate(id) {
18391
+ return BY_ID.get(id) ?? null;
18392
+ }
18393
+ /**
18394
+ * Actuator groups (D944 phase 1b). The active boolean is the binary reducer
18395
+ * with unknown members left out. A command is one call per member that binds
18396
+ * the cap, including members that are offline. One failure does not cancel
18397
+ * the others.
18398
+ */
18399
+ /** Caps a light group may expose, in display order. Switch is the active state. */
18400
+ var LIGHT_SHARED_CAPS = [
18401
+ "switch",
18402
+ "brightness",
18403
+ "color"
18404
+ ];
18405
+ var COLOR_MODE_FEATURES = [
18406
+ DeviceFeature.LightColorRgb,
18407
+ DeviceFeature.LightColorHsv,
18408
+ DeviceFeature.LightColorMired
18409
+ ];
18410
+ /** `at-least-one` is any included member on; `all` is every included member on. */
18411
+ function reducerForActive(active) {
18412
+ return active === "all" ? "all" : "any";
18413
+ }
18414
+ /**
18415
+ * Caps every member binds, from {@link LIGHT_SHARED_CAPS}. An empty member
18416
+ * list shares nothing. A member that lacks colour drops colour from the group.
18417
+ */
18418
+ function sharedLightCaps(memberCaps) {
18419
+ if (memberCaps.length === 0) return [];
18420
+ return LIGHT_SHARED_CAPS.filter((cap) => memberCaps.every((bound) => bound.includes(cap)));
18421
+ }
18422
+ /**
18423
+ * Colour modes every member advertises. Offline does not remove a mode:
18424
+ * the caller passes device features, not liveness. No members → no mode.
18425
+ */
18426
+ function sharedColorModes(memberFeatures) {
18427
+ if (memberFeatures.length === 0) return [];
18428
+ return COLOR_MODE_FEATURES.filter((mode) => memberFeatures.every((features) => features.includes(mode)));
18429
+ }
18430
+ /**
18431
+ * One call per member that binds `cap`. Offline members stay in the list.
18432
+ * A member without the cap is not called — the command cannot reach it.
18433
+ */
18434
+ function fanOutTargets(members, cap, method, args) {
18435
+ return members.flatMap((member) => member.caps.includes(cap) ? [{
18436
+ deviceId: member.deviceId,
18437
+ cap,
18438
+ method,
18439
+ args: { ...args }
18440
+ }] : []);
18441
+ }
18442
+ /**
18443
+ * Run every call. A throw is that member's result; the other calls still run.
18444
+ * At most {@link FAN_OUT_CONCURRENCY} are in flight.
18445
+ */
18446
+ async function runFanOut(calls, invoke) {
18447
+ const results = [];
18448
+ let next = 0;
18449
+ const worker = async () => {
18450
+ for (;;) {
18451
+ const index = next;
18452
+ next += 1;
18453
+ const call = calls[index];
18454
+ if (call === void 0) return;
18455
+ try {
18456
+ await invoke(call);
18457
+ results[index] = {
18458
+ deviceId: call.deviceId,
18459
+ ok: true
18460
+ };
18461
+ } catch (err) {
18462
+ const error = err instanceof Error ? err.message : String(err);
18463
+ results[index] = {
18464
+ deviceId: call.deviceId,
18465
+ ok: false,
18466
+ error
18467
+ };
18468
+ }
18469
+ }
18470
+ };
18471
+ const width = Math.min(4, calls.length);
18472
+ await Promise.all(Array.from({ length: width }, () => worker()));
18473
+ return results;
18474
+ }
18475
+ function sameSource(a, b) {
18476
+ return a.addonId === b.addonId && a.stableId === b.stableId;
18477
+ }
18478
+ function sameMember(a, b) {
18479
+ return sameSource(a.source, b.source) && a.cap === b.cap && a.fieldPath === b.fieldPath;
18480
+ }
18481
+ function accepted(template, member) {
18482
+ return template.accept.some((field) => field.cap === member.cap && field.fieldPath === member.fieldPath);
18483
+ }
18484
+ function memberProblems(template, spec) {
18485
+ return spec.members.flatMap((member, index) => {
18486
+ const at = `helper.members[${index}]`;
18487
+ const problems = [];
18488
+ if (!accepted(template, member)) {
18489
+ const allowed = template.accept.map((field) => `${field.cap}.${field.fieldPath}`).join(" or ");
18490
+ problems.push(problem("member-constraint", at, `a ${template.id} group reads ${allowed}; this member is ${member.cap}.${member.fieldPath}`));
18491
+ }
18492
+ if (spec.members.slice(0, index).some((other) => sameMember(other, member))) problems.push(problem("member-constraint", at, "this member is already in the group"));
18493
+ return problems;
18494
+ });
18495
+ }
18496
+ function aggregateSource(template, spec, reads, publish) {
18497
+ return {
18498
+ kind: "aggregate",
18499
+ reducer: spec.aggregate,
18500
+ reads: [...reads],
18501
+ publish,
18502
+ empty: template.empty
18503
+ };
18504
+ }
18505
+ function expressionSource(expr) {
18506
+ return {
18507
+ kind: "expression",
18508
+ expr,
18509
+ bindings: {}
18510
+ };
18511
+ }
18512
+ function draftOf$1(template, spec) {
18513
+ const reads = spec.members.map((member) => ({
18514
+ source: member.source,
18515
+ cap: member.cap,
18516
+ fieldPath: member.fieldPath
18517
+ }));
18518
+ const companions = Object.fromEntries(template.companions.map((companion) => [companion.fieldPath, expressionSource(companion.expr)]));
18519
+ return {
18520
+ target: {
18521
+ kind: "new",
18522
+ type: template.deviceType,
18523
+ ...template.role === void 0 ? {} : { role: template.role }
18524
+ },
18525
+ helper: spec,
18526
+ features: [{
18527
+ kind: "fields",
18528
+ cap: template.outputCap,
18529
+ fields: {
18530
+ [template.outputField]: aggregateSource(template, spec, reads, "value"),
18531
+ ...companions
18532
+ }
18533
+ }, {
18534
+ kind: "fields",
18535
+ cap: "group-status",
18536
+ fields: {
18537
+ included: aggregateSource(template, spec, reads, "included"),
18538
+ excluded: aggregateSource(template, spec, reads, "excluded"),
18539
+ total: aggregateSource(template, spec, reads, "total")
18540
+ }
18541
+ }]
18542
+ };
18543
+ }
18544
+ function criterionProblems(template, spec) {
18545
+ if (template.family === "actuator") {
18546
+ if (spec.active === void 0) return [problem("kind-mismatch", "helper.active", `a ${template.id} group needs an active criterion (at-least-one or all)`)];
18547
+ const reducer = reducerForActive(spec.active);
18548
+ if (spec.aggregate !== reducer) return [problem("kind-mismatch", "helper.aggregate", `active \`${spec.active}\` aggregates by \`${reducer}\`, not \`${spec.aggregate}\``)];
18549
+ return [];
18550
+ }
18551
+ 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`)];
18552
+ return [];
18553
+ }
18554
+ function parseDraft(draft) {
18555
+ const parsed = CompositionSchema.safeParse(draft);
18556
+ if (parsed.success) return {
18557
+ ok: true,
18558
+ composition: parsed.data
18559
+ };
18560
+ return {
18561
+ ok: false,
18562
+ problems: [problem("helper-mismatch", "helper", `the template did not compile: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`)]
18563
+ };
18564
+ }
18565
+ /** Compile a group template to a new-device composition. Refusals are named. */
18566
+ function compileHelper(spec) {
18567
+ const template = groupTemplate(spec.templateId);
18568
+ if (template === null) return {
18569
+ ok: false,
18570
+ problems: [problem("member-constraint", "helper.templateId", `unknown template \`${spec.templateId}\``)]
18571
+ };
18572
+ const criterion = criterionProblems(template, spec);
18573
+ if (criterion.length > 0) return {
18574
+ ok: false,
18575
+ problems: criterion
18576
+ };
18577
+ if (!template.aggregates.includes(spec.aggregate)) {
18578
+ const allowed = template.aggregates.join(", ");
18579
+ return {
18580
+ ok: false,
18581
+ problems: [problem("kind-mismatch", "helper.aggregate", `a ${template.id} group aggregates by ${allowed}, not \`${spec.aggregate}\``)]
18582
+ };
18583
+ }
18584
+ const members = memberProblems(template, spec);
18585
+ if (members.length > 0) return {
18586
+ ok: false,
18587
+ problems: members
18588
+ };
18589
+ return parseDraft(draftOf$1(template, spec));
18590
+ }
18591
+ /** The built body, ignoring `helper`, so a save can demand one writer. */
18592
+ function sameHelperBody(stored, compiled) {
18593
+ return JSON.stringify(stored.target) === JSON.stringify(compiled.target) && JSON.stringify(stored.features) === JSON.stringify(compiled.features);
18594
+ }
18595
+ function quantityProblems(spec, facts) {
18596
+ const template = groupTemplate(spec.templateId);
18597
+ if (template === null || template.family !== "numeric") return [];
18598
+ const known = spec.members.flatMap((member, index) => {
18599
+ const quantity = facts.get(compositionSourceKey(member.source))?.quantity;
18600
+ return quantity === void 0 ? [] : [{
18601
+ index,
18602
+ quantity
18603
+ }];
18604
+ });
18605
+ 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}`)]);
18606
+ const distinct = [...new Set(known.map((member) => member.quantity))];
18607
+ if (distinct.length <= 1) return [];
18608
+ return [problem("mixed-quantity", "helper.members", `a numeric group requires one quantity; members report ${distinct.join(" and ")}`)];
18609
+ }
18610
+ function deviceTypeProblems(spec, facts) {
18611
+ const template = groupTemplate(spec.templateId);
18612
+ if (template === null) return [];
18613
+ return spec.members.flatMap((member, index) => {
18614
+ const deviceType = facts.get(compositionSourceKey(member.source))?.deviceType;
18615
+ if (deviceType === void 0 || deviceType === template.memberDeviceType) return [];
18616
+ return [problem("member-constraint", `helper.members[${index}]`, `a ${template.id} group takes ${template.memberDeviceType} devices; this member is a ${deviceType}`)];
18617
+ });
18618
+ }
18619
+ /**
18620
+ * Problems that refuse a save. No `helper` key means a free composition: this
18621
+ * returns nothing, and expression semantics stay as they are.
18622
+ */
18623
+ function helperSaveProblems(composition, facts) {
18624
+ const spec = composition.helper;
18625
+ if (spec === void 0) return [];
18626
+ const compiled = compileHelper(spec);
18627
+ if (!compiled.ok) return compiled.problems;
18628
+ if (!sameHelperBody(composition, compiled.composition)) return [problem("helper-mismatch", "helper", "the stored features are not this template — the helper spec is the only writer")];
18629
+ return [...quantityProblems(spec, facts), ...deviceTypeProblems(spec, facts)];
18630
+ }
18631
+ /**
17973
18632
  * The field graph across every composition, and the cycles in it (D659).
17974
18633
  *
17975
18634
  * A node is ONE field of ONE device (`<addon>/<stableId>#<cap>.<field>`); an
@@ -18150,11 +18809,22 @@ function composableCap(feature, at, lookupCap) {
18150
18809
  * required field. A REPLACE needs none of it: the cap is bound (a fact), the
18151
18810
  * native keeps serving its methods, and only the named fields are owned (D663).
18152
18811
  */
18153
- function builtCapProblems({ def, state, fields: targetFields }, feature, at, deviceType) {
18812
+ /**
18813
+ * Caps an actuator helper is allowed to serve. A free composition, and a
18814
+ * reading group, get an empty set — `has-commands` stays for them.
18815
+ */
18816
+ function actuatorCommandCaps(composition) {
18817
+ const spec = composition.helper;
18818
+ if (spec === void 0) return /* @__PURE__ */ new Set();
18819
+ const template = groupTemplate(spec.templateId);
18820
+ if (template === null || template.family !== "actuator") return /* @__PURE__ */ new Set();
18821
+ return new Set(template.commandCaps);
18822
+ }
18823
+ function builtCapProblems({ def, state, fields: targetFields }, feature, at, deviceType, servedCommands) {
18154
18824
  const problems = [];
18155
18825
  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(", ")})`));
18156
18826
  const served = Object.entries(def.methods).filter(([name, m]) => m.systemOnly !== true && def.composedMethods?.[name] === void 0).map(([name]) => `\`${name}\``);
18157
- 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)`));
18827
+ 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)`));
18158
18828
  const itemArrayPath = feature.items === void 0 ? null : def.status?.itemArray?.path ?? null;
18159
18829
  for (const key of requiredTopLevelKeys(state)) {
18160
18830
  if (key === itemArrayPath) continue;
@@ -18174,6 +18844,7 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
18174
18844
  const role = roleOf(source);
18175
18845
  const unavailable = unavailableFor(tf, role, mode, def.name, fieldAt);
18176
18846
  if (!unavailable.ok) return refused(unavailable.problem);
18847
+ const omitEmpty = source.kind === "aggregate" && source.publish === "value" && source.empty === "omit";
18177
18848
  const plan = {
18178
18849
  cap: def.name,
18179
18850
  path,
@@ -18181,7 +18852,7 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
18181
18852
  kind: tf.kind,
18182
18853
  nullable: tf.nullable,
18183
18854
  required: tf.required,
18184
- unavailable: unavailable.unavailable,
18855
+ unavailable: omitEmpty ? "omit" : unavailable.unavailable,
18185
18856
  role,
18186
18857
  source,
18187
18858
  reads: [...fieldReads(source)]
@@ -18194,11 +18865,11 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
18194
18865
  events: []
18195
18866
  };
18196
18867
  }
18197
- function planFeature(feature, featureIndex, target, lookupCap) {
18868
+ function planFeature(feature, featureIndex, target, lookupCap, servedCommands) {
18198
18869
  const at = `features[${featureIndex}]`;
18199
18870
  const cap = composableCap(feature, at, lookupCap);
18200
18871
  if ("code" in cap) return refused(cap);
18201
- const capProblems = target.mode === "replace" ? [] : [...builtCapProblems(cap, feature, at, target.deviceType)];
18872
+ const capProblems = target.mode === "replace" ? [] : [...builtCapProblems(cap, feature, at, target.deviceType, servedCommands)];
18202
18873
  if (feature.commands !== void 0 && Object.keys(feature.commands).length > 0) capProblems.push(problem("reserved-variant", `${at}.commands`, "commands (`forward`) arrive in slice 3"));
18203
18874
  const perField = Object.entries(feature.fields).map(([path, source]) => planTopLevelField(cap, {
18204
18875
  featureIndex,
@@ -18284,6 +18955,7 @@ function featureTargetOf(target, cap, at) {
18284
18955
  function planComposition(composition, lookupCap, target) {
18285
18956
  const planTarget = planTargetOf(composition, target);
18286
18957
  if ("code" in planTarget) return refused(planTarget);
18958
+ const servedCommands = actuatorCommandCaps(composition);
18287
18959
  const results = composition.features.map((feature, index) => {
18288
18960
  const at = `features[${index}]`;
18289
18961
  if (feature.kind === "passthrough") return refused(problem("reserved-variant", at, `whole-capability passthrough of \`${feature.cap}\` arrives in slice 3`));
@@ -18298,9 +18970,9 @@ function planComposition(composition, lookupCap, target) {
18298
18970
  return nativeReplaceOrBlock(featureTarget, planFeature(feature, index, {
18299
18971
  mode: "add",
18300
18972
  deviceType: planTarget.found.type
18301
- }, lookupCap));
18973
+ }, lookupCap, servedCommands));
18302
18974
  }
18303
- const result = planFeature(feature, index, featureTarget, lookupCap);
18975
+ const result = planFeature(feature, index, featureTarget, lookupCap, servedCommands);
18304
18976
  return compositionFeatureEnabled(feature) ? result : {
18305
18977
  problems: result.problems,
18306
18978
  fields: [],
@@ -18446,10 +19118,15 @@ function validateComposition(composition, ctx) {
18446
19118
  if (refusedFeatures.some((at) => item.path === at || item.path.startsWith(`${at}.`))) return false;
18447
19119
  return refusedFeatures.length === 0 || item.path !== "features";
18448
19120
  });
19121
+ const facts = new Map([...ctx.sources].flatMap(([key, source]) => source.kind === "found" ? [[key, {
19122
+ deviceType: source.deviceType,
19123
+ quantity: source.quantity
19124
+ }]] : []));
18449
19125
  const problems = [
18450
19126
  ...plan.problems,
18451
19127
  ...sourceProblems(plan.fields, ctx, self),
18452
- ...cycles
19128
+ ...cycles,
19129
+ ...helperSaveProblems(composition, facts)
18453
19130
  ];
18454
19131
  return {
18455
19132
  ok: problems.length === 0,
@@ -47747,6 +48424,8 @@ var NcSystemEventKindSchema = z.enum([
47747
48424
  "detection-blind",
47748
48425
  "motion-noisy",
47749
48426
  "motion-calm",
48427
+ "package-llm-silent",
48428
+ "package-llm-answered",
47750
48429
  "recording-stalled",
47751
48430
  "recording-healthy",
47752
48431
  "recording-degraded",
@@ -61712,6 +62391,28 @@ var PackageVersionInfoSchema = z.object({
61712
62391
  deprecated: z.string().optional(),
61713
62392
  distTags: z.array(z.string()).readonly()
61714
62393
  });
62394
+ /**
62395
+ * One published document. `ok` is markdown from the registry. `missing` means
62396
+ * the registry answered and the file was not there. `error` is a registry or
62397
+ * tarball failure — never an empty string standing in for either.
62398
+ */
62399
+ var PackageDocBodySchema = z.discriminatedUnion("status", [
62400
+ z.object({
62401
+ status: z.literal("ok"),
62402
+ markdown: z.string()
62403
+ }),
62404
+ z.object({ status: z.literal("missing") }),
62405
+ z.object({
62406
+ status: z.literal("error"),
62407
+ message: z.string()
62408
+ })
62409
+ ]);
62410
+ var PackageDocsSchema = z.object({
62411
+ name: z.string(),
62412
+ version: z.string(),
62413
+ readme: PackageDocBodySchema,
62414
+ changelog: PackageDocBodySchema
62415
+ });
61715
62416
  var SearchResultSchema = z.object({
61716
62417
  name: z.string(),
61717
62418
  version: z.string(),
@@ -62078,6 +62779,15 @@ var addonsCapability = {
62078
62779
  auth: "admin"
62079
62780
  }),
62080
62781
  getVersions: method(z.object({ name: z.string() }), z.array(PackageVersionInfoSchema).readonly()),
62782
+ /**
62783
+ * README and CHANGELOG for one registry package, read on the hub and
62784
+ * cached. `version` omitted resolves the `latest` dist-tag. The browser
62785
+ * never talks to the registry.
62786
+ */
62787
+ getPackageDocs: method(z.object({
62788
+ name: z.string().min(1),
62789
+ version: z.string().min(1).optional()
62790
+ }), PackageDocsSchema, { auth: "admin" }),
62081
62791
  restartAddon: method(z.object({ addonId: z.string() }), RestartAddonResultSchema, {
62082
62792
  kind: "mutation",
62083
62793
  auth: "admin"
@@ -63575,6 +64285,10 @@ var ColorStatusSchema = z.object({
63575
64285
  /** Ms epoch of the last operator-driven change. */
63576
64286
  lastChangedAt: z.number()
63577
64287
  });
64288
+ function parseColorInput(value) {
64289
+ const parsed = ColorInputSchema.safeParse(value);
64290
+ return parsed.success ? parsed.data : null;
64291
+ }
63578
64292
  var colorCapability = {
63579
64293
  name: "color",
63580
64294
  scope: "device",
@@ -65651,6 +66365,95 @@ var gasCapability = {
65651
66365
  * whether persisting is worth a SQLite commit. */
65652
66366
  volatileStateFields: ["lastChangedAt"]
65653
66367
  };
66368
+ /**
66369
+ * The last command a helper actuator group sent to each member (D944).
66370
+ * The composer writes this slice; the aggregate pass does not, so a later
66371
+ * reading does not wipe it. History is none — the outcome is the latest
66372
+ * attempt, not a series.
66373
+ */
66374
+ var GroupCommandResultSchema = z.object({
66375
+ deviceId: z.number().int().nonnegative(),
66376
+ cap: z.string().min(1),
66377
+ method: z.string().min(1),
66378
+ ok: z.boolean(),
66379
+ error: z.string().optional(),
66380
+ /** Ms epoch of the attempt. */
66381
+ at: z.number()
66382
+ });
66383
+ var GroupCommandsSchema = z.object({
66384
+ /** One row per member that has been commanded. A later command replaces that member's row. */
66385
+ results: z.array(GroupCommandResultSchema) });
66386
+ var groupCommandsCapability = {
66387
+ name: "group-commands",
66388
+ scope: "device",
66389
+ deviceNative: true,
66390
+ mode: "singleton",
66391
+ deviceTypes: [DeviceType.Switch, DeviceType.Light],
66392
+ methods: {},
66393
+ status: {
66394
+ schema: GroupCommandsSchema,
66395
+ kind: "push"
66396
+ },
66397
+ runtimeState: GroupCommandsSchema,
66398
+ /**
66399
+ * Runtime-state durability: **session** — the last attempt. A restored
66400
+ * failure would outlive the command that caused it.
66401
+ *
66402
+ * See `RuntimeStateDurability`. Enforced by
66403
+ * `scripts/check-runtime-state-durability.ts`.
66404
+ */
66405
+ durability: "session",
66406
+ history: "none"
66407
+ };
66408
+ /**
66409
+ * How many members of a helper group answered (D944). Counts are integers,
66410
+ * not measurements: zero included is a real count, never a stand-in reading.
66411
+ * The reading itself stays on the output capability. History is none — the
66412
+ * series that later statistics read is the output cap's own history block.
66413
+ */
66414
+ var GroupStatusSchema = z.object({
66415
+ /** Members whose current value entered the aggregate. */
66416
+ included: z.number().int().nonnegative().meta(readingMeta("count", {
66417
+ precision: 0,
66418
+ label: "Reporting"
66419
+ })),
66420
+ /** Members left out: offline, unknown, or not a finite reading (D393). */
66421
+ excluded: z.number().int().nonnegative().meta(readingMeta("count", {
66422
+ precision: 0,
66423
+ label: "Excluded"
66424
+ })),
66425
+ /** `included` + `excluded`. */
66426
+ total: z.number().int().nonnegative().meta(readingMeta("count", {
66427
+ precision: 0,
66428
+ label: "Members"
66429
+ }))
66430
+ });
66431
+ var groupStatusCapability = {
66432
+ name: "group-status",
66433
+ scope: "device",
66434
+ deviceNative: true,
66435
+ mode: "singleton",
66436
+ deviceTypes: [
66437
+ DeviceType.Sensor,
66438
+ DeviceType.Switch,
66439
+ DeviceType.Light
66440
+ ],
66441
+ methods: {},
66442
+ status: {
66443
+ schema: GroupStatusSchema,
66444
+ kind: "push"
66445
+ },
66446
+ runtimeState: GroupStatusSchema,
66447
+ /**
66448
+ * Runtime-state durability: **session** — recomputed from members on the
66449
+ * next source event; a restored count would outlive the readings it named.
66450
+ *
66451
+ * See `RuntimeStateDurability`. Enforced by
66452
+ * `scripts/check-runtime-state-durability.ts`.
66453
+ */
66454
+ durability: "session",
66455
+ history: "none"
66456
+ };
65654
66457
  var HeatingValveStatusSchema = z.object({
65655
66458
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
65656
66459
  position: z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -67715,12 +68518,18 @@ var motionCapability = {
67715
68518
  methods: {
67716
68519
  /**
67717
68520
  * Pull the current motion state synchronously. Convenience shortcut
67718
- * for consumers that don't need the full status object; equivalent
67719
- * to `getStatus()?.detected ?? false`. Will likely be folded into
67720
- * `getStatus` once the auto-injected status surface lands in every
67721
- * consumer.
68521
+ * for consumers that don't need the full status object. A composed
68522
+ * group answers from its slice (D944): unknown throws, it is not off.
67722
68523
  */
67723
68524
  isDetected: method(z.object({ deviceId: z.number() }), z.boolean()) },
68525
+ /**
68526
+ * A composed motion group serves `isDetected` from `detected` (D944).
68527
+ * Without this the cap stays uncomposable (`has-commands`).
68528
+ */
68529
+ composedMethods: { isDetected: {
68530
+ kind: "slice",
68531
+ field: "detected"
68532
+ } },
67724
68533
  events: {
67725
68534
  /**
67726
68535
  * Fires every time the runner transitions a camera between
@@ -76628,6 +77437,103 @@ function createDeviceExtensionProvider(options) {
76628
77437
  }
76629
77438
  };
76630
77439
  }
77440
+ function isBinaryReducer(reducer) {
77441
+ return reducer === "any" || reducer === "all";
77442
+ }
77443
+ function includedValue(reducer, member) {
77444
+ if (member.state !== "fresh") return null;
77445
+ if (isBinaryReducer(reducer)) return typeof member.value === "boolean" ? member.value : null;
77446
+ return typeof member.value === "number" && Number.isFinite(member.value) ? member.value : null;
77447
+ }
77448
+ function median$1(values) {
77449
+ const sorted = [...values].toSorted((a, b) => a - b);
77450
+ const mid = Math.floor(sorted.length / 2);
77451
+ const right = sorted[mid];
77452
+ const left = sorted[mid - 1];
77453
+ if (right === void 0) throw new Error("median requires at least one finite number");
77454
+ if (sorted.length % 2 === 1) return right;
77455
+ if (left === void 0) throw new Error("median requires at least one finite number");
77456
+ return (left + right) / 2;
77457
+ }
77458
+ function reduceNumbers(reducer, values) {
77459
+ if (reducer === "min") return Math.min(...values);
77460
+ if (reducer === "max") return Math.max(...values);
77461
+ if (reducer === "sum") return values.reduce((sum, value) => sum + value, 0);
77462
+ if (reducer === "median") return median$1(values);
77463
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
77464
+ }
77465
+ function reduceBooleans(reducer, values) {
77466
+ return reducer === "all" ? values.every((value) => value) : values.some((value) => value);
77467
+ }
77468
+ function countsOf(included, total) {
77469
+ return {
77470
+ included,
77471
+ excluded: total - included,
77472
+ total
77473
+ };
77474
+ }
77475
+ function fatalReason(members) {
77476
+ const reasons = members.flatMap((member) => member.state === "unavailable" && member.fatal === true ? [member.reason ?? "source gone"] : []);
77477
+ return reasons.length === 0 ? null : reasons.join("; ");
77478
+ }
77479
+ function emptyOutcome(empty, counts) {
77480
+ if (empty === "null") return {
77481
+ kind: "value",
77482
+ value: null,
77483
+ counts
77484
+ };
77485
+ return {
77486
+ kind: "unavailable",
77487
+ fatal: false,
77488
+ reason: "no member included — unknown is not 0 or off",
77489
+ counts
77490
+ };
77491
+ }
77492
+ /** Pure. `members` is not mutated. An empty included set is null or unavailable, never 0 or false. */
77493
+ function evaluateAggregate(input) {
77494
+ const included = input.members.flatMap((member) => {
77495
+ const value = includedValue(input.reducer, member);
77496
+ return value === null ? [] : [value];
77497
+ });
77498
+ const counts = countsOf(included.length, input.members.length);
77499
+ const gone = fatalReason(input.members);
77500
+ if (gone !== null) return {
77501
+ kind: "unavailable",
77502
+ fatal: true,
77503
+ reason: gone,
77504
+ counts
77505
+ };
77506
+ if (input.publish === "included") return {
77507
+ kind: "value",
77508
+ value: counts.included,
77509
+ counts
77510
+ };
77511
+ if (input.publish === "excluded") return {
77512
+ kind: "value",
77513
+ value: counts.excluded,
77514
+ counts
77515
+ };
77516
+ if (input.publish === "total") return {
77517
+ kind: "value",
77518
+ value: counts.total,
77519
+ counts
77520
+ };
77521
+ if (included.length === 0) return emptyOutcome(input.empty, counts);
77522
+ if (isBinaryReducer(input.reducer)) {
77523
+ const flags = included.filter((value) => typeof value === "boolean");
77524
+ return {
77525
+ kind: "value",
77526
+ value: reduceBooleans(input.reducer, flags),
77527
+ counts
77528
+ };
77529
+ }
77530
+ const numbers = included.filter((value) => typeof value === "number");
77531
+ return {
77532
+ kind: "value",
77533
+ value: reduceNumbers(input.reducer, numbers),
77534
+ counts
77535
+ };
77536
+ }
76631
77537
  /**
76632
77538
  * Frozen unit → spec table. `•` in the doc marks each dimension's canonical
76633
77539
  * unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
@@ -77133,11 +78039,45 @@ function expressionOutcome(source, read, now, stateful) {
77133
78039
  deadline: deadlines.length > 0 ? Math.min(...deadlines) : null
77134
78040
  };
77135
78041
  }
78042
+ function aggregateRead(reading) {
78043
+ if (reading.state === "unavailable") return {
78044
+ state: "unavailable",
78045
+ fatal: reading.fatal,
78046
+ reason: reading.reason
78047
+ };
78048
+ return {
78049
+ state: reading.state,
78050
+ value: reading.value,
78051
+ ...reading.state === "stale" ? { reason: reading.reason } : {}
78052
+ };
78053
+ }
78054
+ function aggregateField(source, read) {
78055
+ const outcome = evaluateAggregate({
78056
+ reducer: source.reducer,
78057
+ members: source.reads.map((item) => aggregateRead(read(item))),
78058
+ publish: source.publish,
78059
+ empty: source.empty
78060
+ });
78061
+ if (outcome.kind === "value") return {
78062
+ state: "fresh",
78063
+ value: outcome.value,
78064
+ reason: null,
78065
+ deadline: null
78066
+ };
78067
+ return {
78068
+ state: "unavailable",
78069
+ value: null,
78070
+ reason: outcome.reason,
78071
+ fatal: outcome.fatal,
78072
+ confirmed: true
78073
+ };
78074
+ }
77136
78075
  function evaluateCompositionField(input) {
77137
78076
  const { source } = input;
77138
78077
  switch (source.kind) {
77139
78078
  case "from": return fromReading(input.read(source), source);
77140
78079
  case "expression": return expressionOutcome(source, input.read, input.now, input.stateful);
78080
+ case "aggregate": return aggregateField(source, input.read);
77141
78081
  case "code": return {
77142
78082
  state: "unavailable",
77143
78083
  value: null,
@@ -77484,6 +78424,8 @@ var DEVICE_LOCAL_STATE_CAPS = {
77484
78424
  featureProbe: featureProbeCapability,
77485
78425
  flood: floodCapability,
77486
78426
  gas: gasCapability,
78427
+ groupCommands: groupCommandsCapability,
78428
+ groupStatus: groupStatusCapability,
77487
78429
  heatingValve: heatingValveCapability,
77488
78430
  humidifier: humidifierCapability,
77489
78431
  humiditySensor: humiditySensorCapability,
@@ -78638,6 +79580,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
78638
79580
  access: "view",
78639
79581
  role: "admin"
78640
79582
  },
79583
+ "addons.getPackageDocs": {
79584
+ capName: "addons",
79585
+ capScope: "system",
79586
+ addonId: null,
79587
+ access: "view",
79588
+ role: "admin"
79589
+ },
78641
79590
  "addons.getVersions": {
78642
79591
  capName: "addons",
78643
79592
  capScope: "system",
@@ -81746,6 +82695,20 @@ var METHOD_ACCESS_MAP = Object.freeze({
81746
82695
  access: "view",
81747
82696
  role: "viewer"
81748
82697
  },
82698
+ "groupCommands.getStatus": {
82699
+ capName: "group-commands",
82700
+ capScope: "device",
82701
+ addonId: null,
82702
+ access: "view",
82703
+ role: "viewer"
82704
+ },
82705
+ "groupStatus.getStatus": {
82706
+ capName: "group-status",
82707
+ capScope: "device",
82708
+ addonId: null,
82709
+ access: "view",
82710
+ role: "viewer"
82711
+ },
81749
82712
  "heatingValve.getStatus": {
81750
82713
  capName: "heating-valve",
81751
82714
  capScope: "device",
@@ -91568,6 +92531,37 @@ var SENSOR_CAP_VOCABULARY = {
91568
92531
  icon: "flame"
91569
92532
  }]
91570
92533
  },
92534
+ "group-commands": {
92535
+ scope: "device",
92536
+ noun: t("Group command", "Comando di gruppo")
92537
+ },
92538
+ "group-status": {
92539
+ scope: "device",
92540
+ noun: t("Group", "Gruppo"),
92541
+ state: [
92542
+ {
92543
+ kind: "numeric",
92544
+ field: "included",
92545
+ quantity: t("the members reporting", "i membri che rispondono"),
92546
+ label: t("Reporting", "Rispondono"),
92547
+ icon: "users"
92548
+ },
92549
+ {
92550
+ kind: "numeric",
92551
+ field: "excluded",
92552
+ quantity: t("the members left out", "i membri esclusi"),
92553
+ label: t("Excluded", "Esclusi"),
92554
+ icon: "users"
92555
+ },
92556
+ {
92557
+ kind: "numeric",
92558
+ field: "total",
92559
+ quantity: t("the member count", "il numero di membri"),
92560
+ label: t("Members", "Membri"),
92561
+ icon: "sigma"
92562
+ }
92563
+ ]
92564
+ },
91571
92565
  "humidity-sensor": {
91572
92566
  scope: "device",
91573
92567
  noun: t("Humidity", "Umidità"),
@@ -92104,6 +93098,8 @@ var CAP_NAMES_WITH_STATUS = [
92104
93098
  "feature-probe",
92105
93099
  "flood",
92106
93100
  "gas",
93101
+ "group-commands",
93102
+ "group-status",
92107
93103
  "heating-valve",
92108
93104
  "humidifier",
92109
93105
  "humidity-sensor",
@@ -92233,6 +93229,8 @@ var ALL_CAPABILITY_DEFINITIONS = [
92233
93229
  filesystemBrowseCapability,
92234
93230
  floodCapability,
92235
93231
  gasCapability,
93232
+ groupCommandsCapability,
93233
+ groupStatusCapability,
92236
93234
  heatingValveCapability,
92237
93235
  humidifierCapability,
92238
93236
  humiditySensorCapability,
@@ -93307,6 +94305,16 @@ Object.freeze({
93307
94305
  form: "single",
93308
94306
  optional: false
93309
94307
  }],
94308
+ "groupCommands.getStatus": [{
94309
+ name: "deviceId",
94310
+ form: "single",
94311
+ optional: false
94312
+ }],
94313
+ "groupStatus.getStatus": [{
94314
+ name: "deviceId",
94315
+ form: "single",
94316
+ optional: false
94317
+ }],
93310
94318
  "heatingValve.getStatus": [{
93311
94319
  name: "deviceId",
93312
94320
  form: "single",
@@ -95116,7 +96124,7 @@ Object.freeze({
95116
96124
  });
95117
96125
  /**
95118
96126
  * Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
95119
- * `runtimeState`. 72 caps: 38 `restored`, 34 `session`.
96127
+ * `runtimeState`. 74 caps: 38 `restored`, 36 `session`.
95120
96128
  *
95121
96129
  * A cap absent from this map has no runtime-state slice at all. A cap PRESENT
95122
96130
  * with `durability: 'session'` has one and has decided not to keep it.
@@ -95234,6 +96242,14 @@ var RUNTIME_STATE_POLICY = {
95234
96242
  durability: "restored",
95235
96243
  volatileFields: ["lastChangedAt"]
95236
96244
  },
96245
+ "group-commands": {
96246
+ durability: "session",
96247
+ volatileFields: []
96248
+ },
96249
+ "group-status": {
96250
+ durability: "session",
96251
+ volatileFields: []
96252
+ },
95237
96253
  "heating-valve": {
95238
96254
  durability: "session",
95239
96255
  volatileFields: ["lastFetchedAt"]
@@ -95428,7 +96444,7 @@ var SESSION_ONLY_POLICY = {
95428
96444
  };
95429
96445
  /**
95430
96446
  * Cap history catalog, projected from every `*.cap.ts` `history` block.
95431
- * 41 caps with series (75 series), 30 caps answered `'none'`.
96447
+ * 41 caps with series (75 series), 32 caps answered `'none'`.
95432
96448
  * Field keys are `runtimeState` paths (`a.b` into fixed objects only).
95433
96449
  */
95434
96450
  var HISTORY_CATALOG = {
@@ -96000,6 +97016,8 @@ new Map(Object.entries({
96000
97016
  "detection-blind": "device-events",
96001
97017
  "motion-noisy": "device-events",
96002
97018
  "motion-calm": "device-events",
97019
+ "package-llm-silent": "device-events",
97020
+ "package-llm-answered": "device-events",
96003
97021
  "recording-stalled": "device-events",
96004
97022
  "recording-healthy": "device-events",
96005
97023
  "recording-degraded": "device-events",
@@ -96083,6 +97101,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
96083
97101
  label: "Motion without a subject",
96084
97102
  kinds: ["motion-noisy", "motion-calm"]
96085
97103
  },
97104
+ {
97105
+ id: "package-llm",
97106
+ family: "device-events",
97107
+ label: "Package confirm",
97108
+ kinds: ["package-llm-silent", "package-llm-answered"]
97109
+ },
96086
97110
  {
96087
97111
  id: "recording",
96088
97112
  family: "device-events",
@@ -96306,6 +97330,8 @@ var DEVICE_EVENTS = [
96306
97330
  "detection-blind",
96307
97331
  "motion-noisy",
96308
97332
  "motion-calm",
97333
+ "package-llm-silent",
97334
+ "package-llm-answered",
96309
97335
  "recording-stalled",
96310
97336
  "recording-healthy",
96311
97337
  "recording-degraded",
@@ -96574,6 +97600,15 @@ new Map([
96574
97600
  snapshotLabel: "Cameras with constant motion now",
96575
97601
  snapshotSection: null
96576
97602
  },
97603
+ {
97604
+ id: "package-llm-confirm",
97605
+ family: "device-events",
97606
+ label: "Package confirm (not answering / answering again)",
97607
+ bad: ["package-llm-silent"],
97608
+ recovery: ["package-llm-answered"],
97609
+ snapshotLabel: "Cameras whose package confirm is not answering",
97610
+ snapshotSection: null
97611
+ },
96577
97612
  {
96578
97613
  id: "recording-health",
96579
97614
  family: "device-events",
@@ -97547,4 +98582,4 @@ function armRemovalReconcile(opts) {
97547
98582
  return () => clearInterval(timer);
97548
98583
  }
97549
98584
  //#endregion
97550
- export { PreferenceDeviceIdSchema as $, historyItemFieldPath as $i, planComposition as $n, DeviceRole as $r, deviceExtensionCapability as $t, DEVICE_SAN_USER_PREFIX as A, withoutCallerStamp as Aa, StoredRecordKindDeclarationSchema as Ai, keychainAdminCapability as An, streamCatalogCapability as Ar, buildDeviceSignatureMessage as At, HISTORY_ITEM_CATALOG as B, buildSecretRef as Bi, mayReadLocation as Bn, COMPOSER_ADDON_ID as Br, coreBlockComposition as Bt, DATA_STORE_DATABASES as C, secretTreeFromPaths as Ca, ReadinessTimeoutError as Ci, isCollectionArrayMethod as Cn, snapshotCapability as Cr, armRemovalReconcile as Ct, DEVICE_HISTORY_ENERGY_KEY as D, toSecretFieldView as Da, RecordUniqueViolationError as Di, isObjectInput as Dn, storageMigrationCapability as Dr, batteryCapability as Dt, DEVICE_ENROLLMENT_TTL_MS as E, toNodeId as Ea, RecordTooLargeError as Ei, isLocationEnabled as En, storageCapability as Er, bareAddonId as Et, DeviceTombstoneSchema as F, asJsonObject as Fi, localNetworkCapability as Fn, validateCustomAddress as Fr, checkRoleAddress as Ft, KeychainResetRecordSchema as G, createEvent as Gi, motionCapability as Gn, compositionFeatureEnabled as Gr, dataStoreProviderCapability as Gt, HUB_MDNS_TXT_KEYS as H, collectSecretLeaves as Hi, memoizePinnedFfmpeg as Hn, cloneStatefulExpressionMemory as Hr, coreBlockSourceKind as Ht, FIRST_LEVEL_MACRO_CLASSES as I, asNumber as Ii, locationIconKey as In, vectorDimFromBase64 as Ir, composerCapability as It, METHOD_ACCESS_MAP as J, defineRecordKinds as Ji, objectInputDeclaresAddonId as Jn, compositionSourceKey as Jr, decodeVectorBase64 as Jt, LOG_LEVEL_RANK as K, customAction as Ki, normalizeCoreBlockWrite as Kn, compositionItemFieldPath as Kr, databaseSnapshotCapability as Kt, FieldClaimModeSchema as L, asString$1 as Li, logDestinationCapability as Ln, vectorIndexDimConflictError as Lr, compositionFieldKey as Lt, DataStoreDatabaseSchema as M, UnindexedFilterError as Mi, legacyAutoLinkIds as Mn, supportedRuntimes as Mr, calendarsCapability as Mt, DeclaredDevices as N, UnknownRecordKindError as Ni, legacyModeOf as Nn, userManagementCapability as Nr, cameraGridLayoutCapability as Nt, DEVICE_NONCE_TTL_MS as O, transformSecretWrite as Oa, RevConflictError as Oi, isVoidInput as On, storageOccupancyCapability as Or, buildCapabilityLookup as Ot, DeviceStatusSchema as P, WELL_KNOWN_TAB_MAP as Pi, lifecycleJobSchema as Pn, validateComposition as Pr, canonicalIconKey as Pt, PREFERENCES_MAX_VALUE_BYTES as Q, formatSecretScope as Qi, pickAppLinkHub as Qn, DeviceFeature as Qr, deviceCredentialsCapability as Qt, FieldClaimSchema as R, assertTransactScope as Ri, logLevelAtMost as Rn, vectorStoreCapability as Rr, compositionSourceRefs as Rt, DATABASE_SNAPSHOT_TIMEOUT_MS as S, scopeKey as Sa, ReadinessRegistry as Si, isArrayOutputSchema as Sn, siteZoneKey as Sr, alertsCapability as St, DERIVED_CAMERA_SILENCED_CAP_NAMES as T, sleep as Ta, RecordNotFoundError as Ti, isDefaultAppConnectionEndpoint as Tn, storageAdminCapability as Tr, backupCapability as Tt, KEYCHAIN_RESET_TRIGGER_ACTOR as U, collectSecretMarkerRefs as Ui, metricsProviderCapability as Un, composedDeviceRef as Ur, coreBlocksCapability as Ut, HUB_MDNS_SERVICE_TYPE as V, collectSecretConfigKeys as Vi, mayWriteToLocation as Vn, buildFfmpegArgs as Vr, coreBlockIdFromAddonId as Vt, KeychainAuditEntrySchema as W, collectZodSecretPaths as Wi, modeMayWrite as Wn, composedDeviceStableId as Wr, createDeviceExtensionProvider as Wt, MOTION_CLOSE_AFTER_MS as X, emitReadiness as Xi, parseAcceleratorFactsJson as Xn, disarmRoseMemory as Xr, deriveBatteryPresence as Xt, MINUTES_PER_DAY as Y, emitDownForOwnedCaps as Yi, objectInputDeclaresRequiredDeviceId as Yn, createStatefulExpressionMemory as Yr, defineExtensionSlotProvider as Yt, NetworkTunnelStartedDataSchema as Z, expandCapMethods as Zi, parseStreamParamsFormPatch as Zn, toExpressionValue as Zr, describeComposableCaps as Zt, CatalogFileSchema as _, parseSecretRef as _a, RECORD_DELETE_BATCH as _i, gbToBytes as _n, scopesAllowAddon as _r, addonPagesCapability as _t, BaseDevice as a, isReadingQuantity as aa, DATAPLANE_SECRET_HEADER as ai, enumerateInferenceDevices as an, recordsCapability as ar, STORAGE_ACCESS_FALLBACK as at, DATABASE_SNAPSHOT_PARTIAL_SUFFIX as b, resolveCapMount as ba, REMOVE_LEAF as bi, isAlertEpisodeSeverity as bn, settingsStoreCapability as br, alertEpisodeId as bt, CAMSTACK_APP_LINK_ORIGIN as c, isSecretMarkerLike as ca, DeclarationRefusedError as ci, evaluateCompositionField as cn, resolveAppConnections as cr, ServerNameSchema as ct, COMPOSED_ITEM_FIXED_FIELDS as d, mapSecretLeaves as da, HISTORY_DEFAULT_MIN_INTERVAL_MS as di, expressionContainsBuiltinCall as dn, resolveCoreBlockFiles as dr, StorageLocationModeSchema as dt, historyUnitFor as ea, DeviceType as ei, deviceHistoryCapability as en, platformProbeCapability as er, PreferenceNamespaceSchema as et, COMPOSER_RUNNER_ID as f, nodePin as fa, InvalidRecordError as fi, extractNestedAddonId as fn, resolveHubAddressRoles as fr, StorageLocationTypeSchema as ft, CalendarPreferencesSchema as g, parseJsonUnknown as ga, RECORD_BATCH_MAX_BYTES as gi, formatMinutes as gn, runtimeStatePolicyFor as gr, UserRecordSchema as gt, CREDENTIAL_TOKEN_AUDIENCE as h, parseJsonObject as ha, RECORD_BATCH_MAX as hi, formatDeviceRevoker as hn, resolveNotificationTapAddress as hr, UNATTRIBUTED_BUCKET_KEY as ht, AlertSchema as i, isKeychainStoredField as ia, CALLER_STAMPED_CAPABILITIES as ii, deviceStatusCapability as in, recordEntriesCapability as ir, RecordingStatusSchema as it, DEVICE_TOMBSTONE_RETENTION_MS as j, EventCategory as ja, TransactRefusedError as ji, keychainCapability as jn, streamQualityLabel as jr, buildStreamParamsConfigSchema as jt, DEVICE_SAN_CREDENTIAL_PREFIX as k, userError as ka, SECRET_CLEAR as ki, kebabToCamel as kn, storageProviderCapability as kr, buildDeviceEnrollmentLink as kt, CAP_NAMES_WITH_STATUS as l, isSecretRefOwnedBy as la, FilterRequiredError as li, evictionPolicyOfLocation as ln, resolveBucketMs as lr, SsoBridgeClaimsSchema as lt, CORE_BLOCK_ADDON_PREFIX as m, normalizeSecretOwner as ma, PlaintextSecretError as mi, foldSnapshotByFunction as mn, resolveMethodAuth as mr, TokenScopeSchema as mt, AGENT_MDNS_TXT_KEYS as n, isDeviceConfigCap as na, BaseAddon as ni, deviceRemovalHookCapability as nn, procedureAuthKey as nr, RECORDING_SOURCE_CAMSTACK_ADDON as nt, BatteryStatusSchema as o, isSecretClear as oa, DEVICE_SETTINGS_CONTRIBUTION_METHODS as oi, enumerateItemArrayFields as on, reducePoints as or, STREAM_PROFILE_META as ot, CORE_BLOCKS_ADDON_ID as p, normalizeNodeId as pa, NoCallerError as pi, filesystemBrowseCapability as pn, resolveLocationMode as pr, StorageMigrationJobSchema as pt, LegacyStorageLocationDefaultSchema as q, defineCustomActions as qi, normalizeUnit as qn, compositionSliceKey as qr, declarationOwnerNodeId as qt, ALL_CAPABILITY_DEFINITIONS as r, isEvent as ra, BatchTooLargeError as ri, deviceStateCapability as rn, ptzAutotrackCapability as rr, ROOT_BUCKET_KEY as rt, CAMERA_SWITCH_ORDER as s, isSecretMarker as sa, DEVICE_STATUS_METHOD as si, enumerateSchemaFields as sn, replacedFieldKeys as sr, ScopedTokenSchema as st, AGENT_MDNS_SERVICE_TYPE as t, hydrateSchema as ta, errMsg as ti, deviceManagerCapability as tn, problemsBlockSave as tr, PreferenceValueSchema as tt, CATALOG_LANGS as u, makeSecretMarker as ua, ForeignSecretMarkerError as ui, expandContainer as un, resolveCoreBlockEntry as ur, StorageCleanupJobSchema as ut, CoreBlockSchema as v, readinessKey as va, RECORD_SWEEP_INTERVAL_MS as vi, interpolate as vn, scopesAllowDeviceCap as vr, addonSettingsCapability as vt, DAY_NAMES as w, secretTreeFromSchema as wa, RecordKindDeclarationSchema as wi, isCredentialTokenPayload as wn, splitTranslationRef as wr, authProviderCapability as wt, DATABASE_SNAPSHOT_SUFFIX as x, resolveSecretMarkers as xa, RUNTIME_DEFAULTS as xi, isAppLinkBase as xn, shortHostname as xr, alertEpisodePayload as xt, CredentialTokenClaimsSchema as y, recordSecretRef as ya, REDACTED_SECRET as yi, isAlertEpisodeOpen as yn, scoreRuntimes as yr, addonWidgetsCapability as yt, HISTORY_CATALOG as z, assertValidDeclaration as zi, looseSchema as zn, withLocationMode as zr, coreBlockAddonId as zt };
98585
+ export { PREFERENCES_MAX_VALUE_BYTES as $, collectSecretLeaves as $i, normalizeUnit as $n, cloneStatefulExpressionMemory as $r, deriveBatteryPresence as $t, DEVICE_SAN_USER_PREFIX as A, recordSecretRef as Aa, REDACTED_SECRET as Ai, isCredentialTokenPayload as An, sharedLightCaps as Ar, buildCapabilityLookup as At, HISTORY_CATALOG as B, userError as Ba, SECRET_CLEAR as Bi, lifecycleJobSchema as Bn, streamCatalogCapability as Br, compositionFieldKey as Bt, DATA_STORE_DATABASES as C, nodePin as Ca, InvalidRecordError as Ci, groupTemplate as Cn, runFanOut as Cr, alertsCapability as Ct, DEVICE_HISTORY_ENERGY_KEY as D, parseJsonUnknown as Da, RECORD_BATCH_MAX_BYTES as Di, isAppLinkBase as Dn, scoreRuntimes as Dr, bareAddonId as Dt, DEVICE_ENROLLMENT_TTL_MS as E, parseJsonObject as Ea, RECORD_BATCH_MAX as Ei, isAlertEpisodeSeverity as En, scopesAllowDeviceCap as Er, backupCapability as Et, DeviceTombstoneSchema as F, secretTreeFromSchema as Fa, RecordKindDeclarationSchema as Fi, kebabToCamel as Fn, storageAdminCapability as Fr, cameraGridLayoutCapability as Ft, KeychainAuditEntrySchema as G, WELL_KNOWN_TAB_MAP as Gi, looseSchema as Gn, validateComposition as Gr, coreBlockSourceKind as Gt, HUB_MDNS_SERVICE_TYPE as H, EventCategory as Ha, TransactRefusedError as Hi, locationIconKey as Hn, supportedRuntimes as Hr, coreBlockAddonId as Ht, FIRST_LEVEL_MACRO_CLASSES as I, sleep as Ia, RecordNotFoundError as Ii, keychainAdminCapability as In, storageCapability as Ir, canonicalIconKey as It, LegacyStorageLocationDefaultSchema as J, asString$1 as Ji, memoizePinnedFfmpeg as Jn, vectorIndexDimConflictError as Jr, dataStoreProviderCapability as Jt, KeychainResetRecordSchema as K, asJsonObject as Ki, mayReadLocation as Kn, validateCustomAddress as Kr, coreBlocksCapability as Kt, FieldClaimModeSchema as L, toNodeId as La, RecordTooLargeError as Li, keychainCapability as Ln, storageMigrationCapability as Lr, checkRoleAddress as Lt, DataStoreDatabaseSchema as M, resolveSecretMarkers as Ma, RUNTIME_DEFAULTS as Mi, isLocationEnabled as Mn, siteZoneKey as Mr, buildDeviceSignatureMessage as Mt, DeclaredDevices as N, scopeKey as Na, ReadinessRegistry as Ni, isObjectInput as Nn, snapshotCapability as Nr, buildStreamParamsConfigSchema as Nt, DEVICE_NONCE_TTL_MS as O, parseSecretRef as Oa, RECORD_DELETE_BATCH as Oi, isArrayOutputSchema as On, settingsStoreCapability as Or, batteryCapability as Ot, DeviceStatusSchema as P, secretTreeFromPaths as Pa, ReadinessTimeoutError as Pi, isVoidInput as Pn, splitTranslationRef as Pr, calendarsCapability as Pt, NetworkTunnelStartedDataSchema as Q, collectSecretConfigKeys as Qi, normalizeCoreBlockWrite as Qn, buildFfmpegArgs as Qr, defineExtensionSlotProvider as Qt, FieldClaimSchema as R, toSecretFieldView as Ra, RecordUniqueViolationError as Ri, legacyAutoLinkIds as Rn, storageOccupancyCapability as Rr, colorCapability as Rt, DATABASE_SNAPSHOT_TIMEOUT_MS as S, mapSecretLeaves as Sa, HISTORY_DEFAULT_MIN_INTERVAL_MS as Si, groupCommandsCapability as Sn, resolveNotificationTapAddress as Sr, alertEpisodePayload as St, DERIVED_CAMERA_SILENCED_CAP_NAMES as T, normalizeSecretOwner as Ta, PlaintextSecretError as Ti, isAlertEpisodeOpen as Tn, scopesAllowAddon as Tr, authProviderCapability as Tt, HUB_MDNS_TXT_KEYS as U, UnindexedFilterError as Ui, logDestinationCapability as Un, switchCapability as Ur, coreBlockComposition as Ut, HISTORY_ITEM_CATALOG as V, withoutCallerStamp as Va, StoredRecordKindDeclarationSchema as Vi, localNetworkCapability as Vn, streamQualityLabel as Vr, compositionSourceRefs as Vt, KEYCHAIN_RESET_TRIGGER_ACTOR as W, UnknownRecordKindError as Wi, logLevelAtMost as Wn, userManagementCapability as Wr, coreBlockIdFromAddonId as Wt, MINUTES_PER_DAY as X, assertValidDeclaration as Xi, modeMayWrite as Xn, withLocationMode as Xr, declarationOwnerNodeId as Xt, METHOD_ACCESS_MAP as Y, assertTransactScope as Yi, metricsProviderCapability as Yn, vectorStoreCapability as Yr, databaseSnapshotCapability as Yt, MOTION_CLOSE_AFTER_MS as Z, buildSecretRef as Zi, motionCapability as Zn, COMPOSER_ADDON_ID as Zr, decodeVectorBase64 as Zt, CatalogFileSchema as _, isSecretClear as _a, DEVICE_SETTINGS_CONTRIBUTION_METHODS as _i, filesystemBrowseCapability as _n, resolveCoreBlockEntry as _r, UserRecordSchema as _t, BaseDevice as a, defineRecordKinds as aa, compositionSourceKey as ai, deviceRemovalHookCapability as an, pickAppLinkHub as ar, RecordingStatusSchema as at, DATABASE_SNAPSHOT_PARTIAL_SUFFIX as b, isSecretRefOwnedBy as ba, FilterRequiredError as bi, formatMinutes as bn, resolveLocationMode as br, addonWidgetsCapability as bt, CAMSTACK_APP_LINK_ORIGIN as c, expandCapMethods as ca, toExpressionValue as ci, enumerateInferenceDevices as cn, problemsBlockSave as cr, ScopedTokenSchema as ct, COMPOSED_ITEM_FIXED_FIELDS as d, historyUnitFor as da, DeviceType as di, evaluateCompositionField as dn, recordEntriesCapability as dr, StorageCleanupJobSchema as dt, collectSecretMarkerRefs as ea, composedDeviceRef as ei, describeComposableCaps as en, objectInputDeclaresAddonId as er, PreferenceDeviceIdSchema as et, COMPOSER_RUNNER_ID as f, hydrateSchema as fa, errMsg as fi, evictionPolicyOfLocation as fn, recordsCapability as fr, StorageLocationModeSchema as ft, CalendarPreferencesSchema as g, isReadingQuantity as ga, DATAPLANE_SECRET_HEADER as gi, fanOutTargets as gn, resolveBucketMs as gr, UNATTRIBUTED_BUCKET_KEY as gt, CREDENTIAL_TOKEN_AUDIENCE as h, isKeychainStoredField as ha, CALLER_STAMPED_CAPABILITIES as hi, extractNestedAddonId as hn, resolveAppConnections as hr, TokenScopeSchema as ht, AlertSchema as i, defineCustomActions as ia, compositionSliceKey as ii, deviceManagerCapability as in, parseStreamParamsFormPatch as ir, ROOT_BUCKET_KEY as it, DEVICE_TOMBSTONE_RETENTION_MS as j, resolveCapMount as ja, REMOVE_LEAF as ji, isDefaultAppConnectionEndpoint as jn, shortHostname as jr, buildDeviceEnrollmentLink as jt, DEVICE_SAN_CREDENTIAL_PREFIX as k, readinessKey as ka, RECORD_SWEEP_INTERVAL_MS as ki, isCollectionArrayMethod as kn, sharedColorModes as kr, brightnessCapability as kt, CAP_NAMES_WITH_STATUS as l, formatSecretScope as la, DeviceFeature as li, enumerateItemArrayFields as ln, procedureAuthKey as lr, ServerNameSchema as lt, CORE_BLOCK_ADDON_PREFIX as m, isEvent as ma, BatchTooLargeError as mi, expressionContainsBuiltinCall as mn, replacedFieldKeys as mr, StorageMigrationJobSchema as mt, AGENT_MDNS_TXT_KEYS as n, createEvent as na, compositionFeatureEnabled as ni, deviceExtensionCapability as nn, parseAcceleratorFactsJson as nr, PreferenceValueSchema as nt, BatteryStatusSchema as o, emitDownForOwnedCaps as oa, createStatefulExpressionMemory as oi, deviceStateCapability as on, planComposition as or, STORAGE_ACCESS_FALLBACK as ot, CORE_BLOCKS_ADDON_ID as p, isDeviceConfigCap as pa, BaseAddon as pi, expandContainer as pn, reducePoints as pr, StorageLocationTypeSchema as pt, LOG_LEVEL_RANK as q, asNumber as qi, mayWriteToLocation as qn, vectorDimFromBase64 as qr, createDeviceExtensionProvider as qt, ALL_CAPABILITY_DEFINITIONS as r, customAction as ra, compositionItemFieldPath as ri, deviceHistoryCapability as rn, parseColorInput as rr, RECORDING_SOURCE_CAMSTACK_ADDON as rt, CAMERA_SWITCH_ORDER as s, emitReadiness as sa, disarmRoseMemory as si, deviceStatusCapability as sn, platformProbeCapability as sr, STREAM_PROFILE_META as st, AGENT_MDNS_SERVICE_TYPE as t, collectZodSecretPaths as ta, composedDeviceStableId as ti, deviceCredentialsCapability as tn, objectInputDeclaresRequiredDeviceId as tr, PreferenceNamespaceSchema as tt, CATALOG_LANGS as u, historyItemFieldPath as ua, DeviceRole as ui, enumerateSchemaFields as un, ptzAutotrackCapability as ur, SsoBridgeClaimsSchema as ut, CoreBlockSchema as v, isSecretMarker as va, DEVICE_STATUS_METHOD as vi, foldSnapshotByFunction as vn, resolveCoreBlockFiles as vr, addonPagesCapability as vt, DAY_NAMES as w, normalizeNodeId as wa, NoCallerError as wi, interpolate as wn, runtimeStatePolicyFor as wr, armRemovalReconcile as wt, DATABASE_SNAPSHOT_SUFFIX as x, makeSecretMarker as xa, ForeignSecretMarkerError as xi, gbToBytes as xn, resolveMethodAuth as xr, alertEpisodeId as xt, CredentialTokenClaimsSchema as y, isSecretMarkerLike as ya, DeclarationRefusedError as yi, formatDeviceRevoker as yn, resolveHubAddressRoles as yr, addonSettingsCapability as yt, GroupCommandResultSchema as z, transformSecretWrite as za, RevConflictError as zi, legacyModeOf as zn, storageProviderCapability as zr, composerCapability as zt };