@camstack/addon-matter-broker 0.2.148 → 0.2.149

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.mjs CHANGED
@@ -11,7 +11,7 @@ import { networkInterfaces, tmpdir, uptime } from "node:os";
11
11
  import { finished } from "node:stream/promises";
12
12
  import { createConnection, createServer as createServer$2 } from "node:net";
13
13
  import * as dgram from "node:dgram";
14
- //#region ../types/dist/event-category-DHXxB8t9.mjs
14
+ //#region ../types/dist/event-category-CT-hz5Rb.mjs
15
15
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
16
16
  EventCategory["SystemBoot"] = "system.boot";
17
17
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -337,6 +337,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
337
337
  /** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
338
338
  EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
339
339
  /**
340
+ * A camera's package LLM confirm has failed closed three times in a row
341
+ * (D931, 2026-10-26). One edge per camera until
342
+ * {@link PipelinePackageLlmAnswered}.
343
+ */
344
+ EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
345
+ /** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
346
+ EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
347
+ /**
340
348
  * Per-camera pipeline config was mutated by the orchestrator
341
349
  * (a settings change via `setAgentInferenceDevices` /
342
350
  * `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
@@ -5579,7 +5587,7 @@ var ZodIssueCode = {
5579
5587
  var ZodFirstPartyTypeKind;
5580
5588
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5581
5589
  //#endregion
5582
- //#region ../types/dist/sleep-CARd6wZF.mjs
5590
+ //#region ../types/dist/sleep-bykKrTgu.mjs
5583
5591
  /**
5584
5592
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5585
5593
  * window to float samples (D455).
@@ -8360,6 +8368,53 @@ var READING_QUANTITIES = [
8360
8368
  ];
8361
8369
  var ReadingQuantitySchema = _enum(READING_QUANTITIES);
8362
8370
  new Set(READING_QUANTITIES);
8371
+ /**
8372
+ * Stored unit symbol for a quantity. `none` means the number is dimensionless
8373
+ * (or an index / ratio / count). `device` means the cap has no single unit.
8374
+ */
8375
+ var QUANTITY_BASE = {
8376
+ temperature: "°C",
8377
+ pressure: "hPa",
8378
+ speed: "m/s",
8379
+ precipitation: "mm",
8380
+ "precipitation-rate": "mm/h",
8381
+ length: "m",
8382
+ area: "m²",
8383
+ illuminance: "lx",
8384
+ irradiance: "W/m²",
8385
+ power: "W",
8386
+ energy: "kWh",
8387
+ voltage: "V",
8388
+ current: "A",
8389
+ "apparent-power": "VA",
8390
+ humidity: "%",
8391
+ percentage: "%",
8392
+ "concentration-volume": "ppm",
8393
+ "concentration-mass": "µg/m³",
8394
+ "concentration-ppb": "ppb",
8395
+ volume: "L",
8396
+ duration: "s",
8397
+ "duration-ms": "ms",
8398
+ information: "B",
8399
+ "sound-level": "dBFS",
8400
+ "signal-level": "dBm",
8401
+ "colour-temperature": "mired",
8402
+ angle: "°",
8403
+ bitrate: "kbps",
8404
+ rate: "fps",
8405
+ mass: "kg",
8406
+ index: "none",
8407
+ ratio: "none",
8408
+ count: "none",
8409
+ none: "none",
8410
+ device: "device"
8411
+ };
8412
+ /** The stored unit, or `undefined` when the quantity has no unit symbol. */
8413
+ function baseUnitOf(quantity) {
8414
+ const symbol = QUANTITY_BASE[quantity];
8415
+ if (symbol === "none" || symbol === "device") return void 0;
8416
+ return symbol;
8417
+ }
8363
8418
  function readingMeta(quantity, extras) {
8364
8419
  return {
8365
8420
  quantity,
@@ -8913,6 +8968,8 @@ var CAP_NAMES = Object.freeze([
8913
8968
  "filesystem-browse",
8914
8969
  "flood",
8915
8970
  "gas",
8971
+ "group-commands",
8972
+ "group-status",
8916
8973
  "heating-valve",
8917
8974
  "humidifier",
8918
8975
  "humidity-sensor",
@@ -9731,6 +9788,20 @@ Object.freeze({
9731
9788
  "path": "detected",
9732
9789
  "valueType": "boolean"
9733
9790
  }],
9791
+ "group-status": [
9792
+ {
9793
+ "path": "included",
9794
+ "valueType": "number"
9795
+ },
9796
+ {
9797
+ "path": "excluded",
9798
+ "valueType": "number"
9799
+ },
9800
+ {
9801
+ "path": "total",
9802
+ "valueType": "number"
9803
+ }
9804
+ ],
9734
9805
  "heating-valve": [{
9735
9806
  "path": "position",
9736
9807
  "valueType": "number"
@@ -11072,7 +11143,7 @@ function errMsg(err) {
11072
11143
  return String(err);
11073
11144
  }
11074
11145
  //#endregion
11075
- //#region ../types/dist/composition-kEl9mevu.mjs
11146
+ //#region ../types/dist/composition-OhpuespA.mjs
11076
11147
  /**
11077
11148
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11078
11149
  *
@@ -11827,15 +11898,74 @@ function validateExpressionSource(src) {
11827
11898
  }
11828
11899
  return null;
11829
11900
  }
11830
- /** A composed device's stableId is this prefix plus the block id. */
11831
- var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11832
- /** Longest snippet a `code` source may carry (slice 4). */
11833
- var MAX_COMPOSITION_CODE_LENGTH = 2e4;
11901
+ /**
11902
+ * A composition source identity: `(addonId, stableId)`, never a numeric device
11903
+ * id. Split out so helper schemas can name it without a cycle through
11904
+ * `composition.ts` (D659).
11905
+ */
11834
11906
  var CompositionSourceRefSchema = object({
11835
11907
  /** The owning addon; `stableId` is unique only within it. */
11836
11908
  addonId: string$2().min(1),
11837
11909
  stableId: string$2().min(1)
11838
11910
  });
11911
+ var GROUP_TEMPLATE_IDS = [
11912
+ "temperature",
11913
+ "humidity",
11914
+ "pressure",
11915
+ "illuminance",
11916
+ "power",
11917
+ "energy",
11918
+ "battery",
11919
+ "numeric",
11920
+ "motion",
11921
+ "contact",
11922
+ "leak",
11923
+ "smoke",
11924
+ "occupancy",
11925
+ "binary",
11926
+ "switch",
11927
+ "light"
11928
+ ];
11929
+ var NUMERIC_AGGREGATES = [
11930
+ "mean",
11931
+ "median",
11932
+ "min",
11933
+ "max",
11934
+ "sum"
11935
+ ];
11936
+ var BINARY_AGGREGATES = ["any", "all"];
11937
+ /** How an actuator group decides it is on. Unknown members never count as off. */
11938
+ var ACTIVE_CRITERIA = ["at-least-one", "all"];
11939
+ var AGGREGATE_REDUCERS = [
11940
+ "mean",
11941
+ "median",
11942
+ "min",
11943
+ "max",
11944
+ "sum",
11945
+ "any",
11946
+ "all"
11947
+ ];
11948
+ var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
11949
+ var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
11950
+ var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
11951
+ /** One member. The field is stored so occupancy can name motion or binary. */
11952
+ var HelperMemberSchema = object({
11953
+ source: CompositionSourceRefSchema,
11954
+ cap: string$2().min(1),
11955
+ fieldPath: string$2().min(1)
11956
+ });
11957
+ var HelperSpecSchema = discriminatedUnion("kind", [object({
11958
+ kind: literal("group"),
11959
+ templateId: GroupTemplateIdSchema,
11960
+ aggregate: AggregateReducerSchema,
11961
+ members: array(HelperMemberSchema).min(1).max(64),
11962
+ /** Actuator groups only. Readings leave this unset. */
11963
+ active: ActiveCriterionSchema.optional()
11964
+ })]);
11965
+ /** A composed device's stableId is this prefix plus the block id. */
11966
+ var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11967
+ /** Longest snippet a `code` source may carry (slice 4). */
11968
+ var MAX_COMPOSITION_CODE_LENGTH = 2e4;
11839
11969
  /** One field of one capability of one source device. */
11840
11970
  var CompositionFieldReadSchema = object({
11841
11971
  source: CompositionSourceRefSchema,
@@ -11879,7 +12009,33 @@ var CompositionCodeSourceSchema = object({
11879
12009
  var CompositionFieldSourceSchema = discriminatedUnion("kind", [
11880
12010
  CompositionFromSourceSchema,
11881
12011
  CompositionExpressionSourceSchema,
11882
- CompositionCodeSourceSchema
12012
+ CompositionCodeSourceSchema,
12013
+ object({
12014
+ kind: literal("aggregate"),
12015
+ reducer: _enum([
12016
+ "mean",
12017
+ "median",
12018
+ "min",
12019
+ "max",
12020
+ "sum",
12021
+ "any",
12022
+ "all"
12023
+ ]),
12024
+ reads: array(CompositionFieldReadSchema).min(1).max(64),
12025
+ /** `value` is the reading; the others are the member counts. */
12026
+ publish: _enum([
12027
+ "value",
12028
+ "included",
12029
+ "excluded",
12030
+ "total"
12031
+ ]),
12032
+ /** What a `value` publish does when nobody is included. Counts ignore this. */
12033
+ empty: _enum([
12034
+ "null",
12035
+ "omit",
12036
+ "offline"
12037
+ ])
12038
+ })
11883
12039
  ]);
11884
12040
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
11885
12041
  kind: literal("forward"),
@@ -11925,7 +12081,13 @@ var CompositionSchema = object({
11925
12081
  kind: literal("existing"),
11926
12082
  device: CompositionSourceRefSchema
11927
12083
  })]),
11928
- features: array(CompositionFeatureSchema).min(1).max(16)
12084
+ features: array(CompositionFeatureSchema).min(1).max(16),
12085
+ /**
12086
+ * Present when the block is a helper template. Absent on a free
12087
+ * composition (the room example, device 4603). The editor reads this,
12088
+ * never the compiled features.
12089
+ */
12090
+ helper: HelperSpecSchema.optional()
11929
12091
  }).superRefine((composition, ctx) => {
11930
12092
  const seen = /* @__PURE__ */ new Set();
11931
12093
  composition.features.forEach((feature, index) => {
@@ -18183,7 +18345,10 @@ var CompositionProblemSchema = object({
18183
18345
  "target-missing",
18184
18346
  "target-unreadable",
18185
18347
  "not-replaceable",
18186
- "native-capability-replace"
18348
+ "native-capability-replace",
18349
+ "mixed-quantity",
18350
+ "helper-mismatch",
18351
+ "member-constraint"
18187
18352
  ]),
18188
18353
  path: string$2(),
18189
18354
  message: string$2()
@@ -18204,7 +18369,8 @@ var CompositionUnavailableModeSchema = _enum([
18204
18369
  "null",
18205
18370
  "offline",
18206
18371
  "unknown",
18207
- "release"
18372
+ "release",
18373
+ "omit"
18208
18374
  ]);
18209
18375
  /**
18210
18376
  * `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
@@ -18418,6 +18584,275 @@ Object.freeze({
18418
18584
  result: ["number", "null"]
18419
18585
  }
18420
18586
  });
18587
+ /**
18588
+ * One catalog row per base reading a group helper can build (D944 §3).
18589
+ * Data, not a form default written into the block.
18590
+ */
18591
+ var NOW = {
18592
+ fieldPath: "lastFetchedAt",
18593
+ expr: "now"
18594
+ };
18595
+ var CHANGED = {
18596
+ fieldPath: "lastChangedAt",
18597
+ expr: "now"
18598
+ };
18599
+ function numeric(input) {
18600
+ return {
18601
+ ...input,
18602
+ family: "numeric",
18603
+ deviceType: DeviceType.Sensor,
18604
+ memberDeviceType: DeviceType.Sensor,
18605
+ commandCaps: [],
18606
+ baseUnit: baseUnitOf(input.quantity),
18607
+ aggregates: NUMERIC_AGGREGATES,
18608
+ accept: [{
18609
+ cap: input.outputCap,
18610
+ fieldPath: input.outputField
18611
+ }]
18612
+ };
18613
+ }
18614
+ function binary(input) {
18615
+ return {
18616
+ ...input,
18617
+ family: "binary",
18618
+ deviceType: DeviceType.Sensor,
18619
+ memberDeviceType: DeviceType.Sensor,
18620
+ commandCaps: [],
18621
+ quantity: "none",
18622
+ baseUnit: void 0,
18623
+ aggregates: BINARY_AGGREGATES,
18624
+ empty: "offline"
18625
+ };
18626
+ }
18627
+ var GROUP_TEMPLATES = [
18628
+ numeric({
18629
+ id: "temperature",
18630
+ summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
18631
+ role: DeviceRole.TemperatureSensor,
18632
+ outputCap: "temperature-sensor",
18633
+ outputField: "celsius",
18634
+ quantity: "temperature",
18635
+ defaultAggregate: "mean",
18636
+ empty: "null",
18637
+ companions: [NOW]
18638
+ }),
18639
+ numeric({
18640
+ id: "humidity",
18641
+ summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
18642
+ role: DeviceRole.HumiditySensor,
18643
+ outputCap: "humidity-sensor",
18644
+ outputField: "percent",
18645
+ quantity: "humidity",
18646
+ defaultAggregate: "mean",
18647
+ empty: "null",
18648
+ companions: [NOW]
18649
+ }),
18650
+ numeric({
18651
+ id: "pressure",
18652
+ summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
18653
+ role: DeviceRole.PressureSensor,
18654
+ outputCap: "pressure-sensor",
18655
+ outputField: "hpa",
18656
+ quantity: "pressure",
18657
+ defaultAggregate: "mean",
18658
+ empty: "null",
18659
+ companions: [NOW]
18660
+ }),
18661
+ numeric({
18662
+ id: "illuminance",
18663
+ summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
18664
+ role: DeviceRole.AmbientLightSensor,
18665
+ outputCap: "ambient-light-sensor",
18666
+ outputField: "lux",
18667
+ quantity: "illuminance",
18668
+ defaultAggregate: "mean",
18669
+ empty: "null",
18670
+ companions: [NOW]
18671
+ }),
18672
+ numeric({
18673
+ id: "power",
18674
+ summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
18675
+ role: DeviceRole.PowerSensor,
18676
+ outputCap: "power-meter",
18677
+ outputField: "watts",
18678
+ quantity: "power",
18679
+ defaultAggregate: "sum",
18680
+ empty: "omit",
18681
+ companions: [NOW]
18682
+ }),
18683
+ numeric({
18684
+ id: "energy",
18685
+ summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
18686
+ role: DeviceRole.EnergySensor,
18687
+ outputCap: "power-meter",
18688
+ outputField: "kwhTotal",
18689
+ quantity: "energy",
18690
+ defaultAggregate: "sum",
18691
+ empty: "omit",
18692
+ companions: [NOW]
18693
+ }),
18694
+ numeric({
18695
+ id: "battery",
18696
+ summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
18697
+ role: DeviceRole.BatterySensor,
18698
+ outputCap: "battery",
18699
+ outputField: "percentage",
18700
+ quantity: "percentage",
18701
+ defaultAggregate: "mean",
18702
+ empty: "null",
18703
+ companions: [
18704
+ {
18705
+ fieldPath: "charging",
18706
+ expr: "\"unknown\""
18707
+ },
18708
+ {
18709
+ fieldPath: "sleeping",
18710
+ expr: "false"
18711
+ },
18712
+ {
18713
+ fieldPath: "lastUpdated",
18714
+ expr: "now"
18715
+ }
18716
+ ]
18717
+ }),
18718
+ numeric({
18719
+ id: "numeric",
18720
+ summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
18721
+ role: DeviceRole.NumericSensor,
18722
+ outputCap: "numeric-sensor",
18723
+ outputField: "value",
18724
+ quantity: "device",
18725
+ defaultAggregate: "mean",
18726
+ empty: "null",
18727
+ companions: [NOW]
18728
+ }),
18729
+ binary({
18730
+ id: "motion",
18731
+ summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
18732
+ role: DeviceRole.MotionSensor,
18733
+ outputCap: "motion",
18734
+ outputField: "detected",
18735
+ defaultAggregate: "any",
18736
+ accept: [{
18737
+ cap: "motion",
18738
+ fieldPath: "detected"
18739
+ }],
18740
+ companions: [{
18741
+ fieldPath: "lastDetectedAt",
18742
+ expr: "null"
18743
+ }, {
18744
+ fieldPath: "autoClearAfterMs",
18745
+ expr: "null"
18746
+ }]
18747
+ }),
18748
+ binary({
18749
+ id: "contact",
18750
+ summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
18751
+ role: DeviceRole.ContactSensor,
18752
+ outputCap: "contact",
18753
+ outputField: "entryOpen",
18754
+ defaultAggregate: "any",
18755
+ accept: [{
18756
+ cap: "contact",
18757
+ fieldPath: "entryOpen"
18758
+ }],
18759
+ companions: [CHANGED]
18760
+ }),
18761
+ binary({
18762
+ id: "leak",
18763
+ summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
18764
+ role: DeviceRole.LeakSensor,
18765
+ outputCap: "flood",
18766
+ outputField: "flooded",
18767
+ defaultAggregate: "any",
18768
+ accept: [{
18769
+ cap: "flood",
18770
+ fieldPath: "flooded"
18771
+ }],
18772
+ companions: [CHANGED]
18773
+ }),
18774
+ binary({
18775
+ id: "smoke",
18776
+ summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
18777
+ role: DeviceRole.SmokeSensor,
18778
+ outputCap: "smoke",
18779
+ outputField: "detected",
18780
+ defaultAggregate: "any",
18781
+ accept: [{
18782
+ cap: "smoke",
18783
+ fieldPath: "detected"
18784
+ }],
18785
+ companions: [CHANGED]
18786
+ }),
18787
+ binary({
18788
+ id: "occupancy",
18789
+ summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
18790
+ role: DeviceRole.BinarySensor,
18791
+ outputCap: "binary",
18792
+ outputField: "on",
18793
+ defaultAggregate: "any",
18794
+ accept: [{
18795
+ cap: "motion",
18796
+ fieldPath: "detected"
18797
+ }, {
18798
+ cap: "binary",
18799
+ fieldPath: "on"
18800
+ }],
18801
+ companions: [CHANGED]
18802
+ }),
18803
+ binary({
18804
+ id: "binary",
18805
+ summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
18806
+ role: DeviceRole.BinarySensor,
18807
+ outputCap: "binary",
18808
+ outputField: "on",
18809
+ defaultAggregate: "any",
18810
+ accept: [{
18811
+ cap: "binary",
18812
+ fieldPath: "on"
18813
+ }],
18814
+ companions: [CHANGED]
18815
+ }),
18816
+ actuator({
18817
+ id: "switch",
18818
+ 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.",
18819
+ deviceType: DeviceType.Switch,
18820
+ outputCap: "switch",
18821
+ commandCaps: ["switch"]
18822
+ }),
18823
+ actuator({
18824
+ id: "light",
18825
+ 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.",
18826
+ deviceType: DeviceType.Light,
18827
+ outputCap: "switch",
18828
+ commandCaps: [
18829
+ "switch",
18830
+ "brightness",
18831
+ "color"
18832
+ ]
18833
+ })
18834
+ ];
18835
+ function actuator(input) {
18836
+ return {
18837
+ ...input,
18838
+ family: "actuator",
18839
+ role: void 0,
18840
+ memberDeviceType: input.deviceType,
18841
+ outputField: "on",
18842
+ quantity: "none",
18843
+ baseUnit: void 0,
18844
+ aggregates: BINARY_AGGREGATES,
18845
+ defaultAggregate: "any",
18846
+ empty: "offline",
18847
+ accept: [{
18848
+ cap: "switch",
18849
+ fieldPath: "on"
18850
+ }],
18851
+ companions: [CHANGED]
18852
+ };
18853
+ }
18854
+ new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18855
+ DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
18421
18856
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18422
18857
  /**
18423
18858
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -45237,6 +45672,8 @@ var NcSystemEventKindSchema = _enum([
45237
45672
  "detection-blind",
45238
45673
  "motion-noisy",
45239
45674
  "motion-calm",
45675
+ "package-llm-silent",
45676
+ "package-llm-answered",
45240
45677
  "recording-stalled",
45241
45678
  "recording-healthy",
45242
45679
  "recording-degraded",
@@ -56328,6 +56765,28 @@ var PackageVersionInfoSchema = object({
56328
56765
  deprecated: string$2().optional(),
56329
56766
  distTags: array(string$2()).readonly()
56330
56767
  });
56768
+ /**
56769
+ * One published document. `ok` is markdown from the registry. `missing` means
56770
+ * the registry answered and the file was not there. `error` is a registry or
56771
+ * tarball failure — never an empty string standing in for either.
56772
+ */
56773
+ var PackageDocBodySchema = discriminatedUnion("status", [
56774
+ object({
56775
+ status: literal("ok"),
56776
+ markdown: string$2()
56777
+ }),
56778
+ object({ status: literal("missing") }),
56779
+ object({
56780
+ status: literal("error"),
56781
+ message: string$2()
56782
+ })
56783
+ ]);
56784
+ var PackageDocsSchema = object({
56785
+ name: string$2(),
56786
+ version: string$2(),
56787
+ readme: PackageDocBodySchema,
56788
+ changelog: PackageDocBodySchema
56789
+ });
56331
56790
  var SearchResultSchema = object({
56332
56791
  name: string$2(),
56333
56792
  version: string$2(),
@@ -56546,7 +57005,10 @@ method(object({ nodeId: string$2().optional() }).optional(), array(AddonListItem
56546
57005
  }), object({ success: literal(true) }), {
56547
57006
  kind: "mutation",
56548
57007
  auth: "admin"
56549
- }), method(object({ name: string$2() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string$2() }), RestartAddonResultSchema, {
57008
+ }), method(object({ name: string$2() }), array(PackageVersionInfoSchema).readonly()), method(object({
57009
+ name: string$2().min(1),
57010
+ version: string$2().min(1).optional()
57011
+ }), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string$2() }), RestartAddonResultSchema, {
56550
57012
  kind: "mutation",
56551
57013
  auth: "admin"
56552
57014
  }), method(object({ packageName: string$2() }), object({ success: literal(true) }), {
@@ -59882,6 +60344,88 @@ var gasCapability = {
59882
60344
  * whether persisting is worth a SQLite commit. */
59883
60345
  volatileStateFields: ["lastChangedAt"]
59884
60346
  };
60347
+ var GroupCommandsSchema = object({
60348
+ /** One row per member that has been commanded. A later command replaces that member's row. */
60349
+ results: array(object({
60350
+ deviceId: number().int().nonnegative(),
60351
+ cap: string$2().min(1),
60352
+ method: string$2().min(1),
60353
+ ok: boolean(),
60354
+ error: string$2().optional(),
60355
+ /** Ms epoch of the attempt. */
60356
+ at: number()
60357
+ })) });
60358
+ var groupCommandsCapability = {
60359
+ name: "group-commands",
60360
+ scope: "device",
60361
+ deviceNative: true,
60362
+ mode: "singleton",
60363
+ deviceTypes: [DeviceType.Switch, DeviceType.Light],
60364
+ methods: {},
60365
+ status: {
60366
+ schema: GroupCommandsSchema,
60367
+ kind: "push"
60368
+ },
60369
+ runtimeState: GroupCommandsSchema,
60370
+ /**
60371
+ * Runtime-state durability: **session** — the last attempt. A restored
60372
+ * failure would outlive the command that caused it.
60373
+ *
60374
+ * See `RuntimeStateDurability`. Enforced by
60375
+ * `scripts/check-runtime-state-durability.ts`.
60376
+ */
60377
+ durability: "session",
60378
+ history: "none"
60379
+ };
60380
+ /**
60381
+ * How many members of a helper group answered (D944). Counts are integers,
60382
+ * not measurements: zero included is a real count, never a stand-in reading.
60383
+ * The reading itself stays on the output capability. History is none — the
60384
+ * series that later statistics read is the output cap's own history block.
60385
+ */
60386
+ var GroupStatusSchema = object({
60387
+ /** Members whose current value entered the aggregate. */
60388
+ included: number().int().nonnegative().meta(readingMeta("count", {
60389
+ precision: 0,
60390
+ label: "Reporting"
60391
+ })),
60392
+ /** Members left out: offline, unknown, or not a finite reading (D393). */
60393
+ excluded: number().int().nonnegative().meta(readingMeta("count", {
60394
+ precision: 0,
60395
+ label: "Excluded"
60396
+ })),
60397
+ /** `included` + `excluded`. */
60398
+ total: number().int().nonnegative().meta(readingMeta("count", {
60399
+ precision: 0,
60400
+ label: "Members"
60401
+ }))
60402
+ });
60403
+ var groupStatusCapability = {
60404
+ name: "group-status",
60405
+ scope: "device",
60406
+ deviceNative: true,
60407
+ mode: "singleton",
60408
+ deviceTypes: [
60409
+ DeviceType.Sensor,
60410
+ DeviceType.Switch,
60411
+ DeviceType.Light
60412
+ ],
60413
+ methods: {},
60414
+ status: {
60415
+ schema: GroupStatusSchema,
60416
+ kind: "push"
60417
+ },
60418
+ runtimeState: GroupStatusSchema,
60419
+ /**
60420
+ * Runtime-state durability: **session** — recomputed from members on the
60421
+ * next source event; a restored count would outlive the readings it named.
60422
+ *
60423
+ * See `RuntimeStateDurability`. Enforced by
60424
+ * `scripts/check-runtime-state-durability.ts`.
60425
+ */
60426
+ durability: "session",
60427
+ history: "none"
60428
+ };
59885
60429
  var HeatingValveStatusSchema = object({
59886
60430
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
59887
60431
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -61651,12 +62195,18 @@ var motionCapability = {
61651
62195
  methods: {
61652
62196
  /**
61653
62197
  * Pull the current motion state synchronously. Convenience shortcut
61654
- * for consumers that don't need the full status object; equivalent
61655
- * to `getStatus()?.detected ?? false`. Will likely be folded into
61656
- * `getStatus` once the auto-injected status surface lands in every
61657
- * consumer.
62198
+ * for consumers that don't need the full status object. A composed
62199
+ * group answers from its slice (D944): unknown throws, it is not off.
61658
62200
  */
61659
62201
  isDetected: method(object({ deviceId: number() }), boolean()) },
62202
+ /**
62203
+ * A composed motion group serves `isDetected` from `detected` (D944).
62204
+ * Without this the cap stays uncomposable (`has-commands`).
62205
+ */
62206
+ composedMethods: { isDetected: {
62207
+ kind: "slice",
62208
+ field: "detected"
62209
+ } },
61660
62210
  events: {
61661
62211
  /**
61662
62212
  * Fires every time the runner transitions a camera between
@@ -69464,6 +70014,8 @@ var DEVICE_LOCAL_STATE_CAPS = {
69464
70014
  featureProbe: featureProbeCapability,
69465
70015
  flood: floodCapability,
69466
70016
  gas: gasCapability,
70017
+ groupCommands: groupCommandsCapability,
70018
+ groupStatus: groupStatusCapability,
69467
70019
  heatingValve: heatingValveCapability,
69468
70020
  humidifier: humidifierCapability,
69469
70021
  humiditySensor: humiditySensorCapability,
@@ -70840,6 +71392,13 @@ Object.freeze({
70840
71392
  access: "view",
70841
71393
  role: "admin"
70842
71394
  },
71395
+ "addons.getPackageDocs": {
71396
+ capName: "addons",
71397
+ capScope: "system",
71398
+ addonId: null,
71399
+ access: "view",
71400
+ role: "admin"
71401
+ },
70843
71402
  "addons.getVersions": {
70844
71403
  capName: "addons",
70845
71404
  capScope: "system",
@@ -73948,6 +74507,20 @@ Object.freeze({
73948
74507
  access: "view",
73949
74508
  role: "viewer"
73950
74509
  },
74510
+ "groupCommands.getStatus": {
74511
+ capName: "group-commands",
74512
+ capScope: "device",
74513
+ addonId: null,
74514
+ access: "view",
74515
+ role: "viewer"
74516
+ },
74517
+ "groupStatus.getStatus": {
74518
+ capName: "group-status",
74519
+ capScope: "device",
74520
+ addonId: null,
74521
+ access: "view",
74522
+ role: "viewer"
74523
+ },
73951
74524
  "heatingValve.getStatus": {
73952
74525
  capName: "heating-valve",
73953
74526
  capScope: "device",
@@ -83770,6 +84343,37 @@ var SENSOR_CAP_VOCABULARY = {
83770
84343
  icon: "flame"
83771
84344
  }]
83772
84345
  },
84346
+ "group-commands": {
84347
+ scope: "device",
84348
+ noun: t("Group command", "Comando di gruppo")
84349
+ },
84350
+ "group-status": {
84351
+ scope: "device",
84352
+ noun: t("Group", "Gruppo"),
84353
+ state: [
84354
+ {
84355
+ kind: "numeric",
84356
+ field: "included",
84357
+ quantity: t("the members reporting", "i membri che rispondono"),
84358
+ label: t("Reporting", "Rispondono"),
84359
+ icon: "users"
84360
+ },
84361
+ {
84362
+ kind: "numeric",
84363
+ field: "excluded",
84364
+ quantity: t("the members left out", "i membri esclusi"),
84365
+ label: t("Excluded", "Esclusi"),
84366
+ icon: "users"
84367
+ },
84368
+ {
84369
+ kind: "numeric",
84370
+ field: "total",
84371
+ quantity: t("the member count", "il numero di membri"),
84372
+ label: t("Members", "Membri"),
84373
+ icon: "sigma"
84374
+ }
84375
+ ]
84376
+ },
83773
84377
  "humidity-sensor": {
83774
84378
  scope: "device",
83775
84379
  noun: t("Humidity", "Umidità"),
@@ -85235,6 +85839,16 @@ Object.freeze({
85235
85839
  form: "single",
85236
85840
  optional: false
85237
85841
  }],
85842
+ "groupCommands.getStatus": [{
85843
+ name: "deviceId",
85844
+ form: "single",
85845
+ optional: false
85846
+ }],
85847
+ "groupStatus.getStatus": [{
85848
+ name: "deviceId",
85849
+ form: "single",
85850
+ optional: false
85851
+ }],
85238
85852
  "heatingValve.getStatus": [{
85239
85853
  name: "deviceId",
85240
85854
  form: "single",
@@ -87219,6 +87833,8 @@ new Map(Object.entries({
87219
87833
  "detection-blind": "device-events",
87220
87834
  "motion-noisy": "device-events",
87221
87835
  "motion-calm": "device-events",
87836
+ "package-llm-silent": "device-events",
87837
+ "package-llm-answered": "device-events",
87222
87838
  "recording-stalled": "device-events",
87223
87839
  "recording-healthy": "device-events",
87224
87840
  "recording-degraded": "device-events",
@@ -87302,6 +87918,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
87302
87918
  label: "Motion without a subject",
87303
87919
  kinds: ["motion-noisy", "motion-calm"]
87304
87920
  },
87921
+ {
87922
+ id: "package-llm",
87923
+ family: "device-events",
87924
+ label: "Package confirm",
87925
+ kinds: ["package-llm-silent", "package-llm-answered"]
87926
+ },
87305
87927
  {
87306
87928
  id: "recording",
87307
87929
  family: "device-events",
@@ -87483,6 +88105,8 @@ var DEVICE_EVENTS = [
87483
88105
  "detection-blind",
87484
88106
  "motion-noisy",
87485
88107
  "motion-calm",
88108
+ "package-llm-silent",
88109
+ "package-llm-answered",
87486
88110
  "recording-stalled",
87487
88111
  "recording-healthy",
87488
88112
  "recording-degraded",
@@ -87751,6 +88375,15 @@ new Map([
87751
88375
  snapshotLabel: "Cameras with constant motion now",
87752
88376
  snapshotSection: null
87753
88377
  },
88378
+ {
88379
+ id: "package-llm-confirm",
88380
+ family: "device-events",
88381
+ label: "Package confirm (not answering / answering again)",
88382
+ bad: ["package-llm-silent"],
88383
+ recovery: ["package-llm-answered"],
88384
+ snapshotLabel: "Cameras whose package confirm is not answering",
88385
+ snapshotSection: null
88386
+ },
87754
88387
  {
87755
88388
  id: "recording-health",
87756
88389
  family: "device-events",