@camstack/addon-provider-unraid 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
@@ -1,4 +1,4 @@
1
- //#region ../types/dist/event-category-DHXxB8t9.mjs
1
+ //#region ../types/dist/event-category-CT-hz5Rb.mjs
2
2
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
3
3
  EventCategory["SystemBoot"] = "system.boot";
4
4
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -324,6 +324,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
324
324
  /** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
325
325
  EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
326
326
  /**
327
+ * A camera's package LLM confirm has failed closed three times in a row
328
+ * (D931, 2026-10-26). One edge per camera until
329
+ * {@link PipelinePackageLlmAnswered}.
330
+ */
331
+ EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
332
+ /** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
333
+ EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
334
+ /**
327
335
  * Per-camera pipeline config was mutated by the orchestrator
328
336
  * (a settings change via `setAgentInferenceDevices` /
329
337
  * `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
@@ -5433,7 +5441,7 @@ var ZodIssueCode = {
5433
5441
  var ZodFirstPartyTypeKind;
5434
5442
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5435
5443
  //#endregion
5436
- //#region ../types/dist/sleep-CARd6wZF.mjs
5444
+ //#region ../types/dist/sleep-bykKrTgu.mjs
5437
5445
  /**
5438
5446
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5439
5447
  * window to float samples (D455).
@@ -8026,6 +8034,53 @@ var READING_QUANTITIES = [
8026
8034
  ];
8027
8035
  var ReadingQuantitySchema = _enum(READING_QUANTITIES);
8028
8036
  new Set(READING_QUANTITIES);
8037
+ /**
8038
+ * Stored unit symbol for a quantity. `none` means the number is dimensionless
8039
+ * (or an index / ratio / count). `device` means the cap has no single unit.
8040
+ */
8041
+ var QUANTITY_BASE = {
8042
+ temperature: "°C",
8043
+ pressure: "hPa",
8044
+ speed: "m/s",
8045
+ precipitation: "mm",
8046
+ "precipitation-rate": "mm/h",
8047
+ length: "m",
8048
+ area: "m²",
8049
+ illuminance: "lx",
8050
+ irradiance: "W/m²",
8051
+ power: "W",
8052
+ energy: "kWh",
8053
+ voltage: "V",
8054
+ current: "A",
8055
+ "apparent-power": "VA",
8056
+ humidity: "%",
8057
+ percentage: "%",
8058
+ "concentration-volume": "ppm",
8059
+ "concentration-mass": "µg/m³",
8060
+ "concentration-ppb": "ppb",
8061
+ volume: "L",
8062
+ duration: "s",
8063
+ "duration-ms": "ms",
8064
+ information: "B",
8065
+ "sound-level": "dBFS",
8066
+ "signal-level": "dBm",
8067
+ "colour-temperature": "mired",
8068
+ angle: "°",
8069
+ bitrate: "kbps",
8070
+ rate: "fps",
8071
+ mass: "kg",
8072
+ index: "none",
8073
+ ratio: "none",
8074
+ count: "none",
8075
+ none: "none",
8076
+ device: "device"
8077
+ };
8078
+ /** The stored unit, or `undefined` when the quantity has no unit symbol. */
8079
+ function baseUnitOf(quantity) {
8080
+ const symbol = QUANTITY_BASE[quantity];
8081
+ if (symbol === "none" || symbol === "device") return void 0;
8082
+ return symbol;
8083
+ }
8029
8084
  function readingMeta(quantity, extras) {
8030
8085
  return {
8031
8086
  quantity,
@@ -8579,6 +8634,8 @@ var CAP_NAMES = Object.freeze([
8579
8634
  "filesystem-browse",
8580
8635
  "flood",
8581
8636
  "gas",
8637
+ "group-commands",
8638
+ "group-status",
8582
8639
  "heating-valve",
8583
8640
  "humidifier",
8584
8641
  "humidity-sensor",
@@ -9397,6 +9454,20 @@ Object.freeze({
9397
9454
  "path": "detected",
9398
9455
  "valueType": "boolean"
9399
9456
  }],
9457
+ "group-status": [
9458
+ {
9459
+ "path": "included",
9460
+ "valueType": "number"
9461
+ },
9462
+ {
9463
+ "path": "excluded",
9464
+ "valueType": "number"
9465
+ },
9466
+ {
9467
+ "path": "total",
9468
+ "valueType": "number"
9469
+ }
9470
+ ],
9400
9471
  "heating-valve": [{
9401
9472
  "path": "position",
9402
9473
  "valueType": "number"
@@ -10752,7 +10823,7 @@ function errMsg(err) {
10752
10823
  return String(err);
10753
10824
  }
10754
10825
  //#endregion
10755
- //#region ../types/dist/composition-kEl9mevu.mjs
10826
+ //#region ../types/dist/composition-OhpuespA.mjs
10756
10827
  /**
10757
10828
  * The ffmpeg build every CamStack node downloads, per platform and arch.
10758
10829
  *
@@ -11507,15 +11578,74 @@ function validateExpressionSource(src) {
11507
11578
  }
11508
11579
  return null;
11509
11580
  }
11510
- /** A composed device's stableId is this prefix plus the block id. */
11511
- var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11512
- /** Longest snippet a `code` source may carry (slice 4). */
11513
- var MAX_COMPOSITION_CODE_LENGTH = 2e4;
11581
+ /**
11582
+ * A composition source identity: `(addonId, stableId)`, never a numeric device
11583
+ * id. Split out so helper schemas can name it without a cycle through
11584
+ * `composition.ts` (D659).
11585
+ */
11514
11586
  var CompositionSourceRefSchema = object({
11515
11587
  /** The owning addon; `stableId` is unique only within it. */
11516
11588
  addonId: string().min(1),
11517
11589
  stableId: string().min(1)
11518
11590
  });
11591
+ var GROUP_TEMPLATE_IDS = [
11592
+ "temperature",
11593
+ "humidity",
11594
+ "pressure",
11595
+ "illuminance",
11596
+ "power",
11597
+ "energy",
11598
+ "battery",
11599
+ "numeric",
11600
+ "motion",
11601
+ "contact",
11602
+ "leak",
11603
+ "smoke",
11604
+ "occupancy",
11605
+ "binary",
11606
+ "switch",
11607
+ "light"
11608
+ ];
11609
+ var NUMERIC_AGGREGATES = [
11610
+ "mean",
11611
+ "median",
11612
+ "min",
11613
+ "max",
11614
+ "sum"
11615
+ ];
11616
+ var BINARY_AGGREGATES = ["any", "all"];
11617
+ /** How an actuator group decides it is on. Unknown members never count as off. */
11618
+ var ACTIVE_CRITERIA = ["at-least-one", "all"];
11619
+ var AGGREGATE_REDUCERS = [
11620
+ "mean",
11621
+ "median",
11622
+ "min",
11623
+ "max",
11624
+ "sum",
11625
+ "any",
11626
+ "all"
11627
+ ];
11628
+ var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
11629
+ var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
11630
+ var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
11631
+ /** One member. The field is stored so occupancy can name motion or binary. */
11632
+ var HelperMemberSchema = object({
11633
+ source: CompositionSourceRefSchema,
11634
+ cap: string().min(1),
11635
+ fieldPath: string().min(1)
11636
+ });
11637
+ var HelperSpecSchema = discriminatedUnion("kind", [object({
11638
+ kind: literal("group"),
11639
+ templateId: GroupTemplateIdSchema,
11640
+ aggregate: AggregateReducerSchema,
11641
+ members: array(HelperMemberSchema).min(1).max(64),
11642
+ /** Actuator groups only. Readings leave this unset. */
11643
+ active: ActiveCriterionSchema.optional()
11644
+ })]);
11645
+ /** A composed device's stableId is this prefix plus the block id. */
11646
+ var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11647
+ /** Longest snippet a `code` source may carry (slice 4). */
11648
+ var MAX_COMPOSITION_CODE_LENGTH = 2e4;
11519
11649
  /** One field of one capability of one source device. */
11520
11650
  var CompositionFieldReadSchema = object({
11521
11651
  source: CompositionSourceRefSchema,
@@ -11559,7 +11689,33 @@ var CompositionCodeSourceSchema = object({
11559
11689
  var CompositionFieldSourceSchema = discriminatedUnion("kind", [
11560
11690
  CompositionFromSourceSchema,
11561
11691
  CompositionExpressionSourceSchema,
11562
- CompositionCodeSourceSchema
11692
+ CompositionCodeSourceSchema,
11693
+ object({
11694
+ kind: literal("aggregate"),
11695
+ reducer: _enum([
11696
+ "mean",
11697
+ "median",
11698
+ "min",
11699
+ "max",
11700
+ "sum",
11701
+ "any",
11702
+ "all"
11703
+ ]),
11704
+ reads: array(CompositionFieldReadSchema).min(1).max(64),
11705
+ /** `value` is the reading; the others are the member counts. */
11706
+ publish: _enum([
11707
+ "value",
11708
+ "included",
11709
+ "excluded",
11710
+ "total"
11711
+ ]),
11712
+ /** What a `value` publish does when nobody is included. Counts ignore this. */
11713
+ empty: _enum([
11714
+ "null",
11715
+ "omit",
11716
+ "offline"
11717
+ ])
11718
+ })
11563
11719
  ]);
11564
11720
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
11565
11721
  kind: literal("forward"),
@@ -11605,7 +11761,13 @@ var CompositionSchema = object({
11605
11761
  kind: literal("existing"),
11606
11762
  device: CompositionSourceRefSchema
11607
11763
  })]),
11608
- features: array(CompositionFeatureSchema).min(1).max(16)
11764
+ features: array(CompositionFeatureSchema).min(1).max(16),
11765
+ /**
11766
+ * Present when the block is a helper template. Absent on a free
11767
+ * composition (the room example, device 4603). The editor reads this,
11768
+ * never the compiled features.
11769
+ */
11770
+ helper: HelperSpecSchema.optional()
11609
11771
  }).superRefine((composition, ctx) => {
11610
11772
  const seen = /* @__PURE__ */ new Set();
11611
11773
  composition.features.forEach((feature, index) => {
@@ -17814,7 +17976,10 @@ var CompositionProblemSchema = object({
17814
17976
  "target-missing",
17815
17977
  "target-unreadable",
17816
17978
  "not-replaceable",
17817
- "native-capability-replace"
17979
+ "native-capability-replace",
17980
+ "mixed-quantity",
17981
+ "helper-mismatch",
17982
+ "member-constraint"
17818
17983
  ]),
17819
17984
  path: string(),
17820
17985
  message: string()
@@ -17835,7 +18000,8 @@ var CompositionUnavailableModeSchema = _enum([
17835
18000
  "null",
17836
18001
  "offline",
17837
18002
  "unknown",
17838
- "release"
18003
+ "release",
18004
+ "omit"
17839
18005
  ]);
17840
18006
  /**
17841
18007
  * `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
@@ -18049,6 +18215,275 @@ Object.freeze({
18049
18215
  result: ["number", "null"]
18050
18216
  }
18051
18217
  });
18218
+ /**
18219
+ * One catalog row per base reading a group helper can build (D944 §3).
18220
+ * Data, not a form default written into the block.
18221
+ */
18222
+ var NOW = {
18223
+ fieldPath: "lastFetchedAt",
18224
+ expr: "now"
18225
+ };
18226
+ var CHANGED = {
18227
+ fieldPath: "lastChangedAt",
18228
+ expr: "now"
18229
+ };
18230
+ function numeric(input) {
18231
+ return {
18232
+ ...input,
18233
+ family: "numeric",
18234
+ deviceType: DeviceType.Sensor,
18235
+ memberDeviceType: DeviceType.Sensor,
18236
+ commandCaps: [],
18237
+ baseUnit: baseUnitOf(input.quantity),
18238
+ aggregates: NUMERIC_AGGREGATES,
18239
+ accept: [{
18240
+ cap: input.outputCap,
18241
+ fieldPath: input.outputField
18242
+ }]
18243
+ };
18244
+ }
18245
+ function binary(input) {
18246
+ return {
18247
+ ...input,
18248
+ family: "binary",
18249
+ deviceType: DeviceType.Sensor,
18250
+ memberDeviceType: DeviceType.Sensor,
18251
+ commandCaps: [],
18252
+ quantity: "none",
18253
+ baseUnit: void 0,
18254
+ aggregates: BINARY_AGGREGATES,
18255
+ empty: "offline"
18256
+ };
18257
+ }
18258
+ var GROUP_TEMPLATES = [
18259
+ numeric({
18260
+ id: "temperature",
18261
+ summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
18262
+ role: DeviceRole.TemperatureSensor,
18263
+ outputCap: "temperature-sensor",
18264
+ outputField: "celsius",
18265
+ quantity: "temperature",
18266
+ defaultAggregate: "mean",
18267
+ empty: "null",
18268
+ companions: [NOW]
18269
+ }),
18270
+ numeric({
18271
+ id: "humidity",
18272
+ summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
18273
+ role: DeviceRole.HumiditySensor,
18274
+ outputCap: "humidity-sensor",
18275
+ outputField: "percent",
18276
+ quantity: "humidity",
18277
+ defaultAggregate: "mean",
18278
+ empty: "null",
18279
+ companions: [NOW]
18280
+ }),
18281
+ numeric({
18282
+ id: "pressure",
18283
+ summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
18284
+ role: DeviceRole.PressureSensor,
18285
+ outputCap: "pressure-sensor",
18286
+ outputField: "hpa",
18287
+ quantity: "pressure",
18288
+ defaultAggregate: "mean",
18289
+ empty: "null",
18290
+ companions: [NOW]
18291
+ }),
18292
+ numeric({
18293
+ id: "illuminance",
18294
+ summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
18295
+ role: DeviceRole.AmbientLightSensor,
18296
+ outputCap: "ambient-light-sensor",
18297
+ outputField: "lux",
18298
+ quantity: "illuminance",
18299
+ defaultAggregate: "mean",
18300
+ empty: "null",
18301
+ companions: [NOW]
18302
+ }),
18303
+ numeric({
18304
+ id: "power",
18305
+ summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
18306
+ role: DeviceRole.PowerSensor,
18307
+ outputCap: "power-meter",
18308
+ outputField: "watts",
18309
+ quantity: "power",
18310
+ defaultAggregate: "sum",
18311
+ empty: "omit",
18312
+ companions: [NOW]
18313
+ }),
18314
+ numeric({
18315
+ id: "energy",
18316
+ summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
18317
+ role: DeviceRole.EnergySensor,
18318
+ outputCap: "power-meter",
18319
+ outputField: "kwhTotal",
18320
+ quantity: "energy",
18321
+ defaultAggregate: "sum",
18322
+ empty: "omit",
18323
+ companions: [NOW]
18324
+ }),
18325
+ numeric({
18326
+ id: "battery",
18327
+ summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
18328
+ role: DeviceRole.BatterySensor,
18329
+ outputCap: "battery",
18330
+ outputField: "percentage",
18331
+ quantity: "percentage",
18332
+ defaultAggregate: "mean",
18333
+ empty: "null",
18334
+ companions: [
18335
+ {
18336
+ fieldPath: "charging",
18337
+ expr: "\"unknown\""
18338
+ },
18339
+ {
18340
+ fieldPath: "sleeping",
18341
+ expr: "false"
18342
+ },
18343
+ {
18344
+ fieldPath: "lastUpdated",
18345
+ expr: "now"
18346
+ }
18347
+ ]
18348
+ }),
18349
+ numeric({
18350
+ id: "numeric",
18351
+ summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
18352
+ role: DeviceRole.NumericSensor,
18353
+ outputCap: "numeric-sensor",
18354
+ outputField: "value",
18355
+ quantity: "device",
18356
+ defaultAggregate: "mean",
18357
+ empty: "null",
18358
+ companions: [NOW]
18359
+ }),
18360
+ binary({
18361
+ id: "motion",
18362
+ summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
18363
+ role: DeviceRole.MotionSensor,
18364
+ outputCap: "motion",
18365
+ outputField: "detected",
18366
+ defaultAggregate: "any",
18367
+ accept: [{
18368
+ cap: "motion",
18369
+ fieldPath: "detected"
18370
+ }],
18371
+ companions: [{
18372
+ fieldPath: "lastDetectedAt",
18373
+ expr: "null"
18374
+ }, {
18375
+ fieldPath: "autoClearAfterMs",
18376
+ expr: "null"
18377
+ }]
18378
+ }),
18379
+ binary({
18380
+ id: "contact",
18381
+ summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
18382
+ role: DeviceRole.ContactSensor,
18383
+ outputCap: "contact",
18384
+ outputField: "entryOpen",
18385
+ defaultAggregate: "any",
18386
+ accept: [{
18387
+ cap: "contact",
18388
+ fieldPath: "entryOpen"
18389
+ }],
18390
+ companions: [CHANGED]
18391
+ }),
18392
+ binary({
18393
+ id: "leak",
18394
+ summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
18395
+ role: DeviceRole.LeakSensor,
18396
+ outputCap: "flood",
18397
+ outputField: "flooded",
18398
+ defaultAggregate: "any",
18399
+ accept: [{
18400
+ cap: "flood",
18401
+ fieldPath: "flooded"
18402
+ }],
18403
+ companions: [CHANGED]
18404
+ }),
18405
+ binary({
18406
+ id: "smoke",
18407
+ summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
18408
+ role: DeviceRole.SmokeSensor,
18409
+ outputCap: "smoke",
18410
+ outputField: "detected",
18411
+ defaultAggregate: "any",
18412
+ accept: [{
18413
+ cap: "smoke",
18414
+ fieldPath: "detected"
18415
+ }],
18416
+ companions: [CHANGED]
18417
+ }),
18418
+ binary({
18419
+ id: "occupancy",
18420
+ summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
18421
+ role: DeviceRole.BinarySensor,
18422
+ outputCap: "binary",
18423
+ outputField: "on",
18424
+ defaultAggregate: "any",
18425
+ accept: [{
18426
+ cap: "motion",
18427
+ fieldPath: "detected"
18428
+ }, {
18429
+ cap: "binary",
18430
+ fieldPath: "on"
18431
+ }],
18432
+ companions: [CHANGED]
18433
+ }),
18434
+ binary({
18435
+ id: "binary",
18436
+ summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
18437
+ role: DeviceRole.BinarySensor,
18438
+ outputCap: "binary",
18439
+ outputField: "on",
18440
+ defaultAggregate: "any",
18441
+ accept: [{
18442
+ cap: "binary",
18443
+ fieldPath: "on"
18444
+ }],
18445
+ companions: [CHANGED]
18446
+ }),
18447
+ actuator({
18448
+ id: "switch",
18449
+ 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.",
18450
+ deviceType: DeviceType.Switch,
18451
+ outputCap: "switch",
18452
+ commandCaps: ["switch"]
18453
+ }),
18454
+ actuator({
18455
+ id: "light",
18456
+ 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.",
18457
+ deviceType: DeviceType.Light,
18458
+ outputCap: "switch",
18459
+ commandCaps: [
18460
+ "switch",
18461
+ "brightness",
18462
+ "color"
18463
+ ]
18464
+ })
18465
+ ];
18466
+ function actuator(input) {
18467
+ return {
18468
+ ...input,
18469
+ family: "actuator",
18470
+ role: void 0,
18471
+ memberDeviceType: input.deviceType,
18472
+ outputField: "on",
18473
+ quantity: "none",
18474
+ baseUnit: void 0,
18475
+ aggregates: BINARY_AGGREGATES,
18476
+ defaultAggregate: "any",
18477
+ empty: "offline",
18478
+ accept: [{
18479
+ cap: "switch",
18480
+ fieldPath: "on"
18481
+ }],
18482
+ companions: [CHANGED]
18483
+ };
18484
+ }
18485
+ new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18486
+ DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
18052
18487
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18053
18488
  /**
18054
18489
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -44964,6 +45399,8 @@ var NcSystemEventKindSchema = _enum([
44964
45399
  "detection-blind",
44965
45400
  "motion-noisy",
44966
45401
  "motion-calm",
45402
+ "package-llm-silent",
45403
+ "package-llm-answered",
44967
45404
  "recording-stalled",
44968
45405
  "recording-healthy",
44969
45406
  "recording-degraded",
@@ -56055,6 +56492,28 @@ var PackageVersionInfoSchema = object({
56055
56492
  deprecated: string().optional(),
56056
56493
  distTags: array(string()).readonly()
56057
56494
  });
56495
+ /**
56496
+ * One published document. `ok` is markdown from the registry. `missing` means
56497
+ * the registry answered and the file was not there. `error` is a registry or
56498
+ * tarball failure — never an empty string standing in for either.
56499
+ */
56500
+ var PackageDocBodySchema = discriminatedUnion("status", [
56501
+ object({
56502
+ status: literal("ok"),
56503
+ markdown: string()
56504
+ }),
56505
+ object({ status: literal("missing") }),
56506
+ object({
56507
+ status: literal("error"),
56508
+ message: string()
56509
+ })
56510
+ ]);
56511
+ var PackageDocsSchema = object({
56512
+ name: string(),
56513
+ version: string(),
56514
+ readme: PackageDocBodySchema,
56515
+ changelog: PackageDocBodySchema
56516
+ });
56058
56517
  var SearchResultSchema = object({
56059
56518
  name: string(),
56060
56519
  version: string(),
@@ -56273,7 +56732,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
56273
56732
  }), object({ success: literal(true) }), {
56274
56733
  kind: "mutation",
56275
56734
  auth: "admin"
56276
- }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
56735
+ }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
56736
+ name: string().min(1),
56737
+ version: string().min(1).optional()
56738
+ }), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
56277
56739
  kind: "mutation",
56278
56740
  auth: "admin"
56279
56741
  }), method(object({ packageName: string() }), object({ success: literal(true) }), {
@@ -59609,6 +60071,88 @@ var gasCapability = {
59609
60071
  * whether persisting is worth a SQLite commit. */
59610
60072
  volatileStateFields: ["lastChangedAt"]
59611
60073
  };
60074
+ var GroupCommandsSchema = object({
60075
+ /** One row per member that has been commanded. A later command replaces that member's row. */
60076
+ results: array(object({
60077
+ deviceId: number().int().nonnegative(),
60078
+ cap: string().min(1),
60079
+ method: string().min(1),
60080
+ ok: boolean(),
60081
+ error: string().optional(),
60082
+ /** Ms epoch of the attempt. */
60083
+ at: number()
60084
+ })) });
60085
+ var groupCommandsCapability = {
60086
+ name: "group-commands",
60087
+ scope: "device",
60088
+ deviceNative: true,
60089
+ mode: "singleton",
60090
+ deviceTypes: [DeviceType.Switch, DeviceType.Light],
60091
+ methods: {},
60092
+ status: {
60093
+ schema: GroupCommandsSchema,
60094
+ kind: "push"
60095
+ },
60096
+ runtimeState: GroupCommandsSchema,
60097
+ /**
60098
+ * Runtime-state durability: **session** — the last attempt. A restored
60099
+ * failure would outlive the command that caused it.
60100
+ *
60101
+ * See `RuntimeStateDurability`. Enforced by
60102
+ * `scripts/check-runtime-state-durability.ts`.
60103
+ */
60104
+ durability: "session",
60105
+ history: "none"
60106
+ };
60107
+ /**
60108
+ * How many members of a helper group answered (D944). Counts are integers,
60109
+ * not measurements: zero included is a real count, never a stand-in reading.
60110
+ * The reading itself stays on the output capability. History is none — the
60111
+ * series that later statistics read is the output cap's own history block.
60112
+ */
60113
+ var GroupStatusSchema = object({
60114
+ /** Members whose current value entered the aggregate. */
60115
+ included: number().int().nonnegative().meta(readingMeta("count", {
60116
+ precision: 0,
60117
+ label: "Reporting"
60118
+ })),
60119
+ /** Members left out: offline, unknown, or not a finite reading (D393). */
60120
+ excluded: number().int().nonnegative().meta(readingMeta("count", {
60121
+ precision: 0,
60122
+ label: "Excluded"
60123
+ })),
60124
+ /** `included` + `excluded`. */
60125
+ total: number().int().nonnegative().meta(readingMeta("count", {
60126
+ precision: 0,
60127
+ label: "Members"
60128
+ }))
60129
+ });
60130
+ var groupStatusCapability = {
60131
+ name: "group-status",
60132
+ scope: "device",
60133
+ deviceNative: true,
60134
+ mode: "singleton",
60135
+ deviceTypes: [
60136
+ DeviceType.Sensor,
60137
+ DeviceType.Switch,
60138
+ DeviceType.Light
60139
+ ],
60140
+ methods: {},
60141
+ status: {
60142
+ schema: GroupStatusSchema,
60143
+ kind: "push"
60144
+ },
60145
+ runtimeState: GroupStatusSchema,
60146
+ /**
60147
+ * Runtime-state durability: **session** — recomputed from members on the
60148
+ * next source event; a restored count would outlive the readings it named.
60149
+ *
60150
+ * See `RuntimeStateDurability`. Enforced by
60151
+ * `scripts/check-runtime-state-durability.ts`.
60152
+ */
60153
+ durability: "session",
60154
+ history: "none"
60155
+ };
59612
60156
  var HeatingValveStatusSchema = object({
59613
60157
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
59614
60158
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -61378,12 +61922,18 @@ var motionCapability = {
61378
61922
  methods: {
61379
61923
  /**
61380
61924
  * Pull the current motion state synchronously. Convenience shortcut
61381
- * for consumers that don't need the full status object; equivalent
61382
- * to `getStatus()?.detected ?? false`. Will likely be folded into
61383
- * `getStatus` once the auto-injected status surface lands in every
61384
- * consumer.
61925
+ * for consumers that don't need the full status object. A composed
61926
+ * group answers from its slice (D944): unknown throws, it is not off.
61385
61927
  */
61386
61928
  isDetected: method(object({ deviceId: number() }), boolean()) },
61929
+ /**
61930
+ * A composed motion group serves `isDetected` from `detected` (D944).
61931
+ * Without this the cap stays uncomposable (`has-commands`).
61932
+ */
61933
+ composedMethods: { isDetected: {
61934
+ kind: "slice",
61935
+ field: "detected"
61936
+ } },
61387
61937
  events: {
61388
61938
  /**
61389
61939
  * Fires every time the runner transitions a camera between
@@ -69191,6 +69741,8 @@ var DEVICE_LOCAL_STATE_CAPS = {
69191
69741
  featureProbe: featureProbeCapability,
69192
69742
  flood: floodCapability,
69193
69743
  gas: gasCapability,
69744
+ groupCommands: groupCommandsCapability,
69745
+ groupStatus: groupStatusCapability,
69194
69746
  heatingValve: heatingValveCapability,
69195
69747
  humidifier: humidifierCapability,
69196
69748
  humiditySensor: humiditySensorCapability,
@@ -70567,6 +71119,13 @@ Object.freeze({
70567
71119
  access: "view",
70568
71120
  role: "admin"
70569
71121
  },
71122
+ "addons.getPackageDocs": {
71123
+ capName: "addons",
71124
+ capScope: "system",
71125
+ addonId: null,
71126
+ access: "view",
71127
+ role: "admin"
71128
+ },
70570
71129
  "addons.getVersions": {
70571
71130
  capName: "addons",
70572
71131
  capScope: "system",
@@ -73675,6 +74234,20 @@ Object.freeze({
73675
74234
  access: "view",
73676
74235
  role: "viewer"
73677
74236
  },
74237
+ "groupCommands.getStatus": {
74238
+ capName: "group-commands",
74239
+ capScope: "device",
74240
+ addonId: null,
74241
+ access: "view",
74242
+ role: "viewer"
74243
+ },
74244
+ "groupStatus.getStatus": {
74245
+ capName: "group-status",
74246
+ capScope: "device",
74247
+ addonId: null,
74248
+ access: "view",
74249
+ role: "viewer"
74250
+ },
73678
74251
  "heatingValve.getStatus": {
73679
74252
  capName: "heating-valve",
73680
74253
  capScope: "device",
@@ -83497,6 +84070,37 @@ var SENSOR_CAP_VOCABULARY = {
83497
84070
  icon: "flame"
83498
84071
  }]
83499
84072
  },
84073
+ "group-commands": {
84074
+ scope: "device",
84075
+ noun: t("Group command", "Comando di gruppo")
84076
+ },
84077
+ "group-status": {
84078
+ scope: "device",
84079
+ noun: t("Group", "Gruppo"),
84080
+ state: [
84081
+ {
84082
+ kind: "numeric",
84083
+ field: "included",
84084
+ quantity: t("the members reporting", "i membri che rispondono"),
84085
+ label: t("Reporting", "Rispondono"),
84086
+ icon: "users"
84087
+ },
84088
+ {
84089
+ kind: "numeric",
84090
+ field: "excluded",
84091
+ quantity: t("the members left out", "i membri esclusi"),
84092
+ label: t("Excluded", "Esclusi"),
84093
+ icon: "users"
84094
+ },
84095
+ {
84096
+ kind: "numeric",
84097
+ field: "total",
84098
+ quantity: t("the member count", "il numero di membri"),
84099
+ label: t("Members", "Membri"),
84100
+ icon: "sigma"
84101
+ }
84102
+ ]
84103
+ },
83500
84104
  "humidity-sensor": {
83501
84105
  scope: "device",
83502
84106
  noun: t("Humidity", "Umidità"),
@@ -84962,6 +85566,16 @@ Object.freeze({
84962
85566
  form: "single",
84963
85567
  optional: false
84964
85568
  }],
85569
+ "groupCommands.getStatus": [{
85570
+ name: "deviceId",
85571
+ form: "single",
85572
+ optional: false
85573
+ }],
85574
+ "groupStatus.getStatus": [{
85575
+ name: "deviceId",
85576
+ form: "single",
85577
+ optional: false
85578
+ }],
84965
85579
  "heatingValve.getStatus": [{
84966
85580
  name: "deviceId",
84967
85581
  form: "single",
@@ -86946,6 +87560,8 @@ new Map(Object.entries({
86946
87560
  "detection-blind": "device-events",
86947
87561
  "motion-noisy": "device-events",
86948
87562
  "motion-calm": "device-events",
87563
+ "package-llm-silent": "device-events",
87564
+ "package-llm-answered": "device-events",
86949
87565
  "recording-stalled": "device-events",
86950
87566
  "recording-healthy": "device-events",
86951
87567
  "recording-degraded": "device-events",
@@ -87029,6 +87645,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
87029
87645
  label: "Motion without a subject",
87030
87646
  kinds: ["motion-noisy", "motion-calm"]
87031
87647
  },
87648
+ {
87649
+ id: "package-llm",
87650
+ family: "device-events",
87651
+ label: "Package confirm",
87652
+ kinds: ["package-llm-silent", "package-llm-answered"]
87653
+ },
87032
87654
  {
87033
87655
  id: "recording",
87034
87656
  family: "device-events",
@@ -87210,6 +87832,8 @@ var DEVICE_EVENTS = [
87210
87832
  "detection-blind",
87211
87833
  "motion-noisy",
87212
87834
  "motion-calm",
87835
+ "package-llm-silent",
87836
+ "package-llm-answered",
87213
87837
  "recording-stalled",
87214
87838
  "recording-healthy",
87215
87839
  "recording-degraded",
@@ -87478,6 +88102,15 @@ new Map([
87478
88102
  snapshotLabel: "Cameras with constant motion now",
87479
88103
  snapshotSection: null
87480
88104
  },
88105
+ {
88106
+ id: "package-llm-confirm",
88107
+ family: "device-events",
88108
+ label: "Package confirm (not answering / answering again)",
88109
+ bad: ["package-llm-silent"],
88110
+ recovery: ["package-llm-answered"],
88111
+ snapshotLabel: "Cameras whose package confirm is not answering",
88112
+ snapshotSection: null
88113
+ },
87481
88114
  {
87482
88115
  id: "recording-health",
87483
88116
  family: "device-events",