@camstack/addon-agent-ui 1.2.293 → 1.2.295

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.js CHANGED
@@ -15455,6 +15455,478 @@ object({
15455
15455
  path: ["expr"]
15456
15456
  });
15457
15457
  });
15458
+ /**
15459
+ * Identity envelope for a device's upstream-system metadata.
15460
+ *
15461
+ * Two jobs:
15462
+ *
15463
+ * 1. **Dispatch key.** `id` is the natural identifier the SOURCE system
15464
+ * uses to address this device (HA `entity_id`, Reolink MAC, ONVIF
15465
+ * WS-Discovery endpoint UUID, …). Provider code keeps a
15466
+ * `Map<sourceInfo.id, IDevice>` to route inbound push events in O(1)
15467
+ * without round-tripping through `stableId` / `id` mappings.
15468
+ *
15469
+ * 2. **Stability bridge.** `uniqueId` is the *immutable* upstream id when
15470
+ * one exists (HA `entity.unique_id`, Reolink MAC again — same as `id`
15471
+ * for vendors where MAC is the natural key). For systems where the
15472
+ * live dispatch key can be renamed (HA `entity_id` can be edited),
15473
+ * providers detect renames by matching `uniqueId` and patch `id`
15474
+ * in-place so dispatch keeps working.
15475
+ *
15476
+ * **Display unit and precision are NOT stored here.** They are a read-time
15477
+ * preference (D944). A polymorphic reading stores its `quantity` here once,
15478
+ * at adopt, and a date/time value stores `dateTimeShape` the same way —
15479
+ * neither is repeated on each sample. The `device_class` tag is an
15480
+ * HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
15481
+ * to derive the CamStack `DeviceRole`; it is never stored after that point.
15482
+ *
15483
+ * The `raw` escape hatch carries provider-specific attributes that don't
15484
+ * fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
15485
+ * details, …). Providers control what lands here.
15486
+ */
15487
+ var SourceInfoSchema = object({
15488
+ /** Live dispatch key — mutable when the source system allows rename. */
15489
+ id: string(),
15490
+ /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
15491
+ system: string(),
15492
+ /** Immutable upstream identifier when available (HA `unique_id`, … ).
15493
+ * Used to detect rename when `id` changes. */
15494
+ uniqueId: string().optional(),
15495
+ /** Quantity of a polymorphic reading, written once at adopt (D944). */
15496
+ quantity: ReadingQuantitySchema.optional(),
15497
+ /** Date / time / datetime shape of a string reading, written once at adopt. */
15498
+ dateTimeShape: _enum([
15499
+ "date",
15500
+ "time",
15501
+ "datetime"
15502
+ ]).optional(),
15503
+ /** Provider-specific extras that don't fit the structured slots.
15504
+ * Whitelist what goes here per provider — do NOT dump entire HA
15505
+ * attribute blobs (would explode the meta JSON column). */
15506
+ raw: record(string(), unknown()).optional()
15507
+ });
15508
+ /**
15509
+ * Frozen unit → spec table. `•` in the doc marks each dimension's canonical
15510
+ * unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
15511
+ * `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
15512
+ * decimals). K derives from `°C = K − 273.15`.
15513
+ */
15514
+ var UNIT_TABLE = {
15515
+ "°C": {
15516
+ dimension: "temperature",
15517
+ factor: 1,
15518
+ offset: 0
15519
+ },
15520
+ "°F": {
15521
+ dimension: "temperature",
15522
+ factor: 5 / 9,
15523
+ offset: -160 / 9
15524
+ },
15525
+ K: {
15526
+ dimension: "temperature",
15527
+ factor: 1,
15528
+ offset: -273.15
15529
+ },
15530
+ hPa: {
15531
+ dimension: "pressure",
15532
+ factor: 1,
15533
+ offset: 0
15534
+ },
15535
+ kPa: {
15536
+ dimension: "pressure",
15537
+ factor: 10,
15538
+ offset: 0
15539
+ },
15540
+ Pa: {
15541
+ dimension: "pressure",
15542
+ factor: .01,
15543
+ offset: 0
15544
+ },
15545
+ mbar: {
15546
+ dimension: "pressure",
15547
+ factor: 1,
15548
+ offset: 0
15549
+ },
15550
+ bar: {
15551
+ dimension: "pressure",
15552
+ factor: 1e3,
15553
+ offset: 0
15554
+ },
15555
+ inHg: {
15556
+ dimension: "pressure",
15557
+ factor: 33.8639,
15558
+ offset: 0
15559
+ },
15560
+ mmHg: {
15561
+ dimension: "pressure",
15562
+ factor: 1.33322,
15563
+ offset: 0
15564
+ },
15565
+ psi: {
15566
+ dimension: "pressure",
15567
+ factor: 68.9476,
15568
+ offset: 0
15569
+ },
15570
+ "m/s": {
15571
+ dimension: "speed",
15572
+ factor: 1,
15573
+ offset: 0
15574
+ },
15575
+ "km/h": {
15576
+ dimension: "speed",
15577
+ factor: 1 / 3.6,
15578
+ offset: 0
15579
+ },
15580
+ mph: {
15581
+ dimension: "speed",
15582
+ factor: .44704,
15583
+ offset: 0
15584
+ },
15585
+ kn: {
15586
+ dimension: "speed",
15587
+ factor: .514444,
15588
+ offset: 0
15589
+ },
15590
+ "mm/h": {
15591
+ dimension: "precipitation-rate",
15592
+ factor: 1,
15593
+ offset: 0
15594
+ },
15595
+ "in/h": {
15596
+ dimension: "precipitation-rate",
15597
+ factor: 25.4,
15598
+ offset: 0
15599
+ },
15600
+ m: {
15601
+ dimension: "length",
15602
+ factor: 1,
15603
+ offset: 0
15604
+ },
15605
+ mm: {
15606
+ dimension: "length",
15607
+ factor: .001,
15608
+ offset: 0
15609
+ },
15610
+ cm: {
15611
+ dimension: "length",
15612
+ factor: .01,
15613
+ offset: 0
15614
+ },
15615
+ km: {
15616
+ dimension: "length",
15617
+ factor: 1e3,
15618
+ offset: 0
15619
+ },
15620
+ in: {
15621
+ dimension: "length",
15622
+ factor: .0254,
15623
+ offset: 0
15624
+ },
15625
+ ft: {
15626
+ dimension: "length",
15627
+ factor: .3048,
15628
+ offset: 0
15629
+ },
15630
+ mi: {
15631
+ dimension: "length",
15632
+ factor: 1609.344,
15633
+ offset: 0
15634
+ },
15635
+ "m²": {
15636
+ dimension: "area",
15637
+ factor: 1,
15638
+ offset: 0
15639
+ },
15640
+ lx: {
15641
+ dimension: "illuminance",
15642
+ factor: 1,
15643
+ offset: 0
15644
+ },
15645
+ "W/m²": {
15646
+ dimension: "irradiance",
15647
+ factor: 1,
15648
+ offset: 0
15649
+ },
15650
+ W: {
15651
+ dimension: "power",
15652
+ factor: 1,
15653
+ offset: 0
15654
+ },
15655
+ kW: {
15656
+ dimension: "power",
15657
+ factor: 1e3,
15658
+ offset: 0
15659
+ },
15660
+ VA: {
15661
+ dimension: "apparent-power",
15662
+ factor: 1,
15663
+ offset: 0
15664
+ },
15665
+ Wh: {
15666
+ dimension: "energy",
15667
+ factor: 1,
15668
+ offset: 0
15669
+ },
15670
+ kWh: {
15671
+ dimension: "energy",
15672
+ factor: 1e3,
15673
+ offset: 0
15674
+ },
15675
+ MWh: {
15676
+ dimension: "energy",
15677
+ factor: 1e6,
15678
+ offset: 0
15679
+ },
15680
+ V: {
15681
+ dimension: "voltage",
15682
+ factor: 1,
15683
+ offset: 0
15684
+ },
15685
+ mV: {
15686
+ dimension: "voltage",
15687
+ factor: .001,
15688
+ offset: 0
15689
+ },
15690
+ A: {
15691
+ dimension: "current",
15692
+ factor: 1,
15693
+ offset: 0
15694
+ },
15695
+ mA: {
15696
+ dimension: "current",
15697
+ factor: .001,
15698
+ offset: 0
15699
+ },
15700
+ ppm: {
15701
+ dimension: "concentration-volume",
15702
+ factor: 1,
15703
+ offset: 0
15704
+ },
15705
+ ppb: {
15706
+ dimension: "concentration-volume",
15707
+ factor: .001,
15708
+ offset: 0
15709
+ },
15710
+ "µg/m³": {
15711
+ dimension: "concentration-mass",
15712
+ factor: 1,
15713
+ offset: 0
15714
+ },
15715
+ "mg/m³": {
15716
+ dimension: "concentration-mass",
15717
+ factor: 1e3,
15718
+ offset: 0
15719
+ },
15720
+ kg: {
15721
+ dimension: "mass",
15722
+ factor: 1,
15723
+ offset: 0
15724
+ },
15725
+ g: {
15726
+ dimension: "mass",
15727
+ factor: .001,
15728
+ offset: 0
15729
+ },
15730
+ lb: {
15731
+ dimension: "mass",
15732
+ factor: .453592,
15733
+ offset: 0
15734
+ },
15735
+ oz: {
15736
+ dimension: "mass",
15737
+ factor: .0283495,
15738
+ offset: 0
15739
+ },
15740
+ "%": {
15741
+ dimension: "percentage",
15742
+ factor: 1,
15743
+ offset: 0
15744
+ },
15745
+ L: {
15746
+ dimension: "volume",
15747
+ factor: 1,
15748
+ offset: 0
15749
+ },
15750
+ mL: {
15751
+ dimension: "volume",
15752
+ factor: .001,
15753
+ offset: 0
15754
+ },
15755
+ gal: {
15756
+ dimension: "volume",
15757
+ factor: 3.785411784,
15758
+ offset: 0
15759
+ },
15760
+ s: {
15761
+ dimension: "duration",
15762
+ factor: 1,
15763
+ offset: 0
15764
+ },
15765
+ ms: {
15766
+ dimension: "duration",
15767
+ factor: .001,
15768
+ offset: 0
15769
+ },
15770
+ min: {
15771
+ dimension: "duration",
15772
+ factor: 60,
15773
+ offset: 0
15774
+ },
15775
+ h: {
15776
+ dimension: "duration",
15777
+ factor: 3600,
15778
+ offset: 0
15779
+ },
15780
+ d: {
15781
+ dimension: "duration",
15782
+ factor: 86400,
15783
+ offset: 0
15784
+ },
15785
+ B: {
15786
+ dimension: "information",
15787
+ factor: 1,
15788
+ offset: 0
15789
+ },
15790
+ KiB: {
15791
+ dimension: "information",
15792
+ factor: 1024,
15793
+ offset: 0
15794
+ },
15795
+ MiB: {
15796
+ dimension: "information",
15797
+ factor: 1024 ** 2,
15798
+ offset: 0
15799
+ },
15800
+ GiB: {
15801
+ dimension: "information",
15802
+ factor: 1024 ** 3,
15803
+ offset: 0
15804
+ },
15805
+ TiB: {
15806
+ dimension: "information",
15807
+ factor: 1024 ** 4,
15808
+ offset: 0
15809
+ },
15810
+ kB: {
15811
+ dimension: "information",
15812
+ factor: 1e3,
15813
+ offset: 0
15814
+ },
15815
+ MB: {
15816
+ dimension: "information",
15817
+ factor: 1e6,
15818
+ offset: 0
15819
+ },
15820
+ GB: {
15821
+ dimension: "information",
15822
+ factor: 1e9,
15823
+ offset: 0
15824
+ },
15825
+ "°": {
15826
+ dimension: "angle",
15827
+ factor: 1,
15828
+ offset: 0
15829
+ },
15830
+ dBFS: {
15831
+ dimension: "sound-level",
15832
+ factor: 1,
15833
+ offset: 0
15834
+ },
15835
+ dBm: {
15836
+ dimension: "signal-level",
15837
+ factor: 1,
15838
+ offset: 0
15839
+ },
15840
+ mired: {
15841
+ dimension: "colour-temperature",
15842
+ factor: 1,
15843
+ offset: 0
15844
+ },
15845
+ kbps: {
15846
+ dimension: "bitrate",
15847
+ factor: 1,
15848
+ offset: 0
15849
+ },
15850
+ Mbps: {
15851
+ dimension: "bitrate",
15852
+ factor: 1e3,
15853
+ offset: 0
15854
+ },
15855
+ fps: {
15856
+ dimension: "rate",
15857
+ factor: 1,
15858
+ offset: 0
15859
+ }
15860
+ };
15861
+ /** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
15862
+ function specFor(unit) {
15863
+ return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
15864
+ }
15865
+ /** Value in `spec`'s unit → its dimension's canonical unit. */
15866
+ function toCanonical(value, spec) {
15867
+ return value * spec.factor + spec.offset;
15868
+ }
15869
+ /** Canonical-unit value → the unit described by `spec`. */
15870
+ function fromCanonical(canonical, spec) {
15871
+ return (canonical - spec.offset) / spec.factor;
15872
+ }
15873
+ /**
15874
+ * Graceful variant for the render path: returns the converted value, or
15875
+ * `undefined` when the conversion is refused (unknown unit / cross-dimension).
15876
+ * Never throws — a render caller falls back to the raw value + source unit.
15877
+ */
15878
+ function tryConvertUnit(value, from, to) {
15879
+ if (from === to) return value;
15880
+ const fromSpec = specFor(from);
15881
+ if (!fromSpec) return void 0;
15882
+ const toSpec = specFor(to);
15883
+ if (!toSpec) return void 0;
15884
+ if (fromSpec.dimension !== toSpec.dimension) return void 0;
15885
+ return fromCanonical(toCanonical(value, fromSpec), toSpec);
15886
+ }
15887
+ /**
15888
+ * A number a person types for a physical quantity — the input side of the
15889
+ * value + unit contract (D972).
15890
+ *
15891
+ * Readings are stored in the base unit of their quantity (D944); a cap method
15892
+ * param is stored in the unit its input schema DECLARES (`paramMeta`). The
15893
+ * wire pair {@link QuantityValue} says "this number is expressed in this
15894
+ * unit"; {@link convertQuantityInput} brings it to the stored unit and refuses,
15895
+ * with a typed {@link QuantityUnitError}, a unit that cannot be that quantity.
15896
+ */
15897
+ /** A unit that cannot be applied to the number it was given with. */
15898
+ var QuantityUnitError = class extends Error {
15899
+ code;
15900
+ constructor(code, message) {
15901
+ super(`[${code}] ${message}`);
15902
+ this.name = "QuantityUnitError";
15903
+ this.code = code;
15904
+ }
15905
+ };
15906
+ /** The wire pair: `value` is expressed in `unit`. */
15907
+ var QuantityValueSchema = object({
15908
+ value: number(),
15909
+ unit: string().min(1)
15910
+ });
15911
+ /**
15912
+ * Zod `.meta()` bag for a cap METHOD param that is a physical quantity — the
15913
+ * input-side twin of `readingMeta`. The value is carried in `unit` (a gram
15914
+ * portion stays in grams); the unit must belong to the quantity, checked once
15915
+ * when the cap is declared.
15916
+ */
15917
+ function paramMeta(declared) {
15918
+ const base = baseUnitOf(declared.quantity);
15919
+ if (base === void 0) throw new QuantityUnitError("unknown-unit", `quantity "${declared.quantity}" has no unit`);
15920
+ if (tryConvertUnit(1, declared.unit, base) === void 0) throw new QuantityUnitError("cross-dimension", `"${declared.unit}" is not a unit of ${declared.quantity}`);
15921
+ return {
15922
+ quantity: declared.quantity,
15923
+ unit: declared.unit
15924
+ };
15925
+ }
15926
+ object({
15927
+ quantity: ReadingQuantitySchema,
15928
+ unit: string().min(1)
15929
+ });
15458
15930
  /** How a leaf compares a device field to a value. Derived from the field's
15459
15931
  * `kind` in `deviceManager.getWireableFields`, never hand-maintained. */
15460
15932
  var AutomationConditionOperatorSchema = _enum([
@@ -15477,8 +15949,10 @@ var AutomationConditionLeafSchema = object({
15477
15949
  string(),
15478
15950
  number(),
15479
15951
  boolean(),
15480
- array(union([string(), number()]))
15481
- ])
15952
+ array(union([string(), number()])),
15953
+ QuantityValueSchema
15954
+ ]),
15955
+ unit: string().min(1).optional()
15482
15956
  });
15483
15957
  var AutomationConditionStationaryPresentSchema = object({
15484
15958
  kind: literal("stationary-present"),
@@ -15631,7 +16105,13 @@ var AutomationCapStepSchema = object({
15631
16105
  /** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
15632
16106
  * SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
15633
16107
  * the expression leaf. */
15634
- args: record(string(), unknown()).optional()
16108
+ args: record(string(), unknown()).optional(),
16109
+ /**
16110
+ * The unit the person picked per arg (display only). `args` always hold the
16111
+ * value in the unit the method's input DECLARES (`paramMeta`); on a write an
16112
+ * arg may be a {@link QuantityValue}, which the save boundary converts.
16113
+ */
16114
+ argUnits: record(string(), string().min(1)).optional()
15635
16115
  });
15636
16116
  /**
15637
16117
  * The steps an internal Action may contain: cap and wait, and nothing that can
@@ -16011,6 +16491,16 @@ object({
16011
16491
  lastRunAt: number().nullable(),
16012
16492
  lastError: string().nullable()
16013
16493
  });
16494
+ /** A bare number accepted as a base unit — the save succeeded, say so. */
16495
+ var UnitWarningSchema = object({
16496
+ /** Where in the saved record, e.g. `conditions.children.0` or `steps.2.args.grams`. */
16497
+ path: string(),
16498
+ deviceId: number().int().optional(),
16499
+ field: string(),
16500
+ value: number(),
16501
+ assumedUnit: string(),
16502
+ message: string()
16503
+ });
16014
16504
  /**
16015
16505
  * notification-output — canonical, capability-gated notification delivery.
16016
16506
  *
@@ -21355,56 +21845,6 @@ var DeviceAdminLinkSchema = object({
21355
21845
  });
21356
21846
  method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema.nullable(), { auth: "admin" });
21357
21847
  /**
21358
- * Identity envelope for a device's upstream-system metadata.
21359
- *
21360
- * Two jobs:
21361
- *
21362
- * 1. **Dispatch key.** `id` is the natural identifier the SOURCE system
21363
- * uses to address this device (HA `entity_id`, Reolink MAC, ONVIF
21364
- * WS-Discovery endpoint UUID, …). Provider code keeps a
21365
- * `Map<sourceInfo.id, IDevice>` to route inbound push events in O(1)
21366
- * without round-tripping through `stableId` / `id` mappings.
21367
- *
21368
- * 2. **Stability bridge.** `uniqueId` is the *immutable* upstream id when
21369
- * one exists (HA `entity.unique_id`, Reolink MAC again — same as `id`
21370
- * for vendors where MAC is the natural key). For systems where the
21371
- * live dispatch key can be renamed (HA `entity_id` can be edited),
21372
- * providers detect renames by matching `uniqueId` and patch `id`
21373
- * in-place so dispatch keeps working.
21374
- *
21375
- * **Display unit and precision are NOT stored here.** They are a read-time
21376
- * preference (D944). A polymorphic reading stores its `quantity` here once,
21377
- * at adopt, and a date/time value stores `dateTimeShape` the same way —
21378
- * neither is repeated on each sample. The `device_class` tag is an
21379
- * HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
21380
- * to derive the CamStack `DeviceRole`; it is never stored after that point.
21381
- *
21382
- * The `raw` escape hatch carries provider-specific attributes that don't
21383
- * fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
21384
- * details, …). Providers control what lands here.
21385
- */
21386
- var SourceInfoSchema = object({
21387
- /** Live dispatch key — mutable when the source system allows rename. */
21388
- id: string(),
21389
- /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
21390
- system: string(),
21391
- /** Immutable upstream identifier when available (HA `unique_id`, … ).
21392
- * Used to detect rename when `id` changes. */
21393
- uniqueId: string().optional(),
21394
- /** Quantity of a polymorphic reading, written once at adopt (D944). */
21395
- quantity: ReadingQuantitySchema.optional(),
21396
- /** Date / time / datetime shape of a string reading, written once at adopt. */
21397
- dateTimeShape: _enum([
21398
- "date",
21399
- "time",
21400
- "datetime"
21401
- ]).optional(),
21402
- /** Provider-specific extras that don't fit the structured slots.
21403
- * Whitelist what goes here per provider — do NOT dump entire HA
21404
- * attribute blobs (would explode the meta JSON column). */
21405
- raw: record(string(), unknown()).optional()
21406
- });
21407
- /**
21408
21848
  * device-discovery — device-scoped capability for parents that host /
21409
21849
  * enumerate child devices (Reolink Hub / NVR, ONVIF gateway, future
21410
21850
  * integrations). The parent advertises a list of discoverable children,
@@ -54151,11 +54591,13 @@ var ImageContractSchema = object({
54151
54591
  * The shell verdict (see {@link WrapperKindSchema}) with the proofs that
54152
54592
  * produced it.
54153
54593
  *
54154
- * There is deliberately NO `canSelfUpdate` and no apply action: a wrapper
54155
- * update is an ANNOUNCEMENT. The notification body carries the exact command
54156
- * for a `docker` shell and says the app restarts into the new build for
54157
- * `electron`, and that sentence is chosen from `kind` alone — a boolean
54158
- * nothing reads is the defect this repo keeps paying for.
54594
+ * There is deliberately NO `canSelfUpdate` boolean: a wrapper update is an
54595
+ * ANNOUNCEMENT. The notification body carries the exact command for a `docker`
54596
+ * shell and says the app restarts into the new build for `electron`, and that
54597
+ * sentence is chosen from `kind` alone — a boolean nothing reads is the defect
54598
+ * this repo keeps paying for. The one shell that CAN be acted on is the
54599
+ * Electron app, and only through `installDesktopUpdate` (see
54600
+ * {@link DesktopAppStatusSchema} for what the node reads from the app first).
54159
54601
  */
54160
54602
  var WrapperIdentitySchema = object({
54161
54603
  kind: _enum([
@@ -54203,6 +54645,49 @@ var ServerRollbackInfoSchema = object({
54203
54645
  reason: string()
54204
54646
  });
54205
54647
  /**
54648
+ * What the native desktop app (Electron) that hosts this node says about
54649
+ * itself, read from `<dataDir>/server-root/desktop-app-state.json` (ADR-0971).
54650
+ * Absent on the status = no desktop app, or it never wrote the file.
54651
+ *
54652
+ * `stale` is the honest answer to an app that stopped writing (closed, hung,
54653
+ * crashed): the update facts are then the LAST ones known, not current ones,
54654
+ * and a consumer must not read `update.available: false` from a stale record
54655
+ * as "no update". `stateAtMs` is when the app last wrote.
54656
+ */
54657
+ var DesktopAppStatusSchema = object({
54658
+ /** The Electron app's own version (not the node closure's). */
54659
+ version: string(),
54660
+ update: object({
54661
+ available: boolean(),
54662
+ /** The new build is downloaded and `installDesktopUpdate` can apply it. */
54663
+ downloaded: boolean(),
54664
+ version: string().nullable(),
54665
+ checking: boolean(),
54666
+ /** Why the app's last update check produced no answer; `null` when it did. */
54667
+ error: string().nullable()
54668
+ }),
54669
+ stateAtMs: number(),
54670
+ stale: boolean()
54671
+ });
54672
+ /**
54673
+ * Why `installDesktopUpdate` did nothing. Stable names a UI maps to a sentence:
54674
+ * - `not-electron` — this node does not run inside the desktop app.
54675
+ * - `no-app-state` — the app never published its state (or the file is unreadable).
54676
+ * - `app-state-stale` — the app stopped writing; it is probably not running.
54677
+ * - `not-downloaded` — no update is downloaded yet; nothing to install.
54678
+ */
54679
+ var InstallDesktopUpdateReasonSchema = _enum([
54680
+ "not-electron",
54681
+ "no-app-state",
54682
+ "app-state-stale",
54683
+ "not-downloaded"
54684
+ ]);
54685
+ var InstallDesktopUpdateResultSchema = object({
54686
+ accepted: boolean(),
54687
+ /** Non-null exactly when `accepted` is false. */
54688
+ reason: InstallDesktopUpdateReasonSchema.nullable()
54689
+ });
54690
+ /**
54206
54691
  * The runner boot check (D877): the runners this node PLANNED (hub: one per
54207
54692
  * `resolveRunnerId` over its forked addons; agent: the runners its process
54208
54693
  * service holds, because only the hub plans) against the states the process
@@ -54306,7 +54791,12 @@ var ServerPackageStatusSchema = object({
54306
54791
  * on a provider that predates it. Absent is "not checked yet", never "all
54307
54792
  * well": a consumer that needs the answer treats it as pending.
54308
54793
  */
54309
- runners: RunnerBootCheckSchema.optional()
54794
+ runners: RunnerBootCheckSchema.optional(),
54795
+ /**
54796
+ * The desktop app hosting this node (see {@link DesktopAppStatusSchema}).
54797
+ * Optional for version skew AND because most nodes have no desktop app.
54798
+ */
54799
+ desktopApp: DesktopAppStatusSchema.optional()
54310
54800
  });
54311
54801
  var ServerUpdateCheckResultSchema = object({
54312
54802
  packageName: string(),
@@ -54411,6 +54901,9 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
54411
54901
  kind: "mutation",
54412
54902
  auth: "admin",
54413
54903
  timeoutMs: 16 * 6e4
54904
+ }), method(_void(), InstallDesktopUpdateResultSchema, {
54905
+ kind: "mutation",
54906
+ auth: "admin"
54414
54907
  }), method(_void(), ServerUpdateActionResultSchema, {
54415
54908
  kind: "mutation",
54416
54909
  auth: "admin"
@@ -57358,13 +57851,19 @@ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57358
57851
  }), method(ActionIdInput, _void(), {
57359
57852
  kind: "mutation",
57360
57853
  auth: "admin"
57361
- }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
57854
+ }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({
57855
+ action: ActionEntrySchema,
57856
+ warnings: array(UnitWarningSchema).optional()
57857
+ }), {
57362
57858
  kind: "mutation",
57363
57859
  auth: "admin"
57364
57860
  }), method(object({
57365
57861
  actionId: string().min(1),
57366
57862
  action: ActionInputSchema.partial()
57367
- }), object({ action: ActionEntrySchema }), {
57863
+ }), object({
57864
+ action: ActionEntrySchema,
57865
+ warnings: array(UnitWarningSchema).optional()
57866
+ }), {
57368
57867
  kind: "mutation",
57369
57868
  auth: "admin"
57370
57869
  }), method(ActionIdInput, _void(), {
@@ -62011,6 +62510,14 @@ var PetFeederDeviceStatusSchema = _enum([
62011
62510
  "on_batteries"
62012
62511
  ]);
62013
62512
  var gramsPortion = number().int().min(4).max(200);
62513
+ /** A portion REQUESTED of the feeder is a mass the method takes in GRAMS (the
62514
+ * hardware's own unit). The bounds are grams; a caller entering another unit
62515
+ * converts to grams first (`paramMeta`, D972). The STATUS fields above stay
62516
+ * plain grams — they are not readings in the kilogram base. */
62517
+ var gramsParam = gramsPortion.meta(paramMeta({
62518
+ quantity: "mass",
62519
+ unit: "g"
62520
+ }));
62014
62521
  object({
62015
62522
  /** Food in the TANK (hopper), as the feeder's own sensor reports it
62016
62523
  * (`state.food`). A coarse level code, not grams — `0` is empty. The
@@ -62085,9 +62592,9 @@ object({
62085
62592
  });
62086
62593
  DeviceType.PetFeeder, method(object({
62087
62594
  deviceId: number().int().nonnegative(),
62088
- grams: gramsPortion.optional(),
62089
- hopper1: gramsPortion.optional(),
62090
- hopper2: gramsPortion.optional()
62595
+ grams: gramsParam.optional(),
62596
+ hopper1: gramsParam.optional(),
62597
+ hopper2: gramsParam.optional()
62091
62598
  }), _void(), {
62092
62599
  kind: "mutation",
62093
62600
  auth: "protected"
@@ -74769,6 +75276,13 @@ Object.freeze({
74769
75276
  access: "view",
74770
75277
  role: "admin"
74771
75278
  },
75279
+ "serverManagement.installDesktopUpdate": {
75280
+ capName: "server-management",
75281
+ capScope: "system",
75282
+ addonId: null,
75283
+ access: "create",
75284
+ role: "admin"
75285
+ },
74772
75286
  "serverManagement.restartServer": {
74773
75287
  capName: "server-management",
74774
75288
  capScope: "system",
@@ -78679,7 +79193,8 @@ var APPLIANCE_CAP_VOCABULARY = {
78679
79193
  min: 4,
78680
79194
  max: 200,
78681
79195
  step: 1,
78682
- unit: "g"
79196
+ unit: "g",
79197
+ quantity: "mass"
78683
79198
  },
78684
79199
  optional: true
78685
79200
  }]
@@ -78698,7 +79213,8 @@ var APPLIANCE_CAP_VOCABULARY = {
78698
79213
  min: 4,
78699
79214
  max: 200,
78700
79215
  step: 1,
78701
- unit: "g"
79216
+ unit: "g",
79217
+ quantity: "mass"
78702
79218
  },
78703
79219
  optional: true
78704
79220
  }, {
@@ -78709,7 +79225,8 @@ var APPLIANCE_CAP_VOCABULARY = {
78709
79225
  min: 4,
78710
79226
  max: 200,
78711
79227
  step: 1,
78712
- unit: "g"
79228
+ unit: "g",
79229
+ quantity: "mass"
78713
79230
  },
78714
79231
  optional: true
78715
79232
  }]
@@ -85140,7 +85657,7 @@ var AgentUIAddon = class extends BaseAddon {
85140
85657
  capability: adminUiCapability,
85141
85658
  provider: {
85142
85659
  getStaticDir: async () => ({ staticDir: path.resolve(__dirname) }),
85143
- getVersion: async () => ({ version: "1.2.293" })
85660
+ getVersion: async () => ({ version: "1.2.295" })
85144
85661
  }
85145
85662
  }];
85146
85663
  }