@camstack/addon-terminal 0.1.149 → 0.1.150

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 (3) hide show
  1. package/dist/addon.js +193 -117
  2. package/dist/addon.mjs +193 -117
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -5463,7 +5463,7 @@ var ZodIssueCode = {
5463
5463
  var ZodFirstPartyTypeKind;
5464
5464
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5465
5465
  //#endregion
5466
- //#region ../types/dist/sleep-DJFUfKvA.mjs
5466
+ //#region ../types/dist/sleep-CUp20JkO.mjs
5467
5467
  /**
5468
5468
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5469
5469
  * window to float samples (D455).
@@ -8414,7 +8414,11 @@ var ContributionSectionSchema = object({
8414
8414
  literal(4)
8415
8415
  ]).optional(),
8416
8416
  tab: string().optional(),
8417
- location: _enum(["settings", "top-tab"]).optional(),
8417
+ location: _enum([
8418
+ "settings",
8419
+ "top-tab",
8420
+ "hero"
8421
+ ]).optional(),
8418
8422
  order: number().optional(),
8419
8423
  fields: array(any())
8420
8424
  });
@@ -13379,7 +13383,11 @@ var ConfigSectionWithValuesSchema = object({
13379
13383
  literal(4)
13380
13384
  ]).optional(),
13381
13385
  tab: string().optional(),
13382
- location: _enum(["settings", "top-tab"]).optional(),
13386
+ location: _enum([
13387
+ "settings",
13388
+ "top-tab",
13389
+ "hero"
13390
+ ]).optional(),
13383
13391
  order: number().optional(),
13384
13392
  fields: array(any())
13385
13393
  });
@@ -17259,6 +17267,52 @@ var TierStatusSchema = object({
17259
17267
  countedAt: number().nullable()
17260
17268
  });
17261
17269
  /** Operator/diagnostic view: rows per tier, last runs, refusals and drops since boot. */
17270
+ /**
17271
+ * Why a series is orphan. `device-gone`: its device is absent from the
17272
+ * successful device listings (the departure clock). `undeclared`: its `cap:`
17273
+ * key is declared by no capability any more (a field a cap removed).
17274
+ */
17275
+ var DeviceHistoryOrphanReasonSchema = _enum(["device-gone", "undeclared"]);
17276
+ /** Rows held per stored tier. */
17277
+ var TierRowsSchema = object({
17278
+ raw: number().int(),
17279
+ "5m": number().int(),
17280
+ "1h": number().int(),
17281
+ "1d": number().int()
17282
+ });
17283
+ var OrphanSeriesSchema = object({
17284
+ seriesId: number().int(),
17285
+ deviceId: number().int(),
17286
+ key: string(),
17287
+ scope: string(),
17288
+ /** The metric's display name; `null` when its metric row is gone too. */
17289
+ displayName: string().nullable(),
17290
+ reason: DeviceHistoryOrphanReasonSchema,
17291
+ /** `device-gone`: since when the device has been absent; `null` otherwise. */
17292
+ missingSince: number().nullable(),
17293
+ firstTs: number(),
17294
+ lastTs: number(),
17295
+ rows: TierRowsSchema
17296
+ });
17297
+ var DeviceHistoryOrphanDeleteRefusalSchema = _enum([
17298
+ "not-found",
17299
+ "not-orphan",
17300
+ "failed"
17301
+ ]);
17302
+ var OrphanDeleteEntrySchema = discriminatedUnion("ok", [object({
17303
+ seriesId: number().int(),
17304
+ ok: literal(true),
17305
+ deleted: TierRowsSchema
17306
+ }), object({
17307
+ seriesId: number().int(),
17308
+ ok: literal(false),
17309
+ reason: DeviceHistoryOrphanDeleteRefusalSchema
17310
+ })]);
17311
+ var OrphanListSchema = object({
17312
+ series: array(OrphanSeriesSchema).readonly(),
17313
+ /** More orphans exist than {@link DEVICE_HISTORY_ORPHAN_LIST_MAX}. */
17314
+ truncated: boolean()
17315
+ });
17262
17316
  var DeviceHistoryStatusSchema = object({
17263
17317
  startedAt: number(),
17264
17318
  /** The store is declared, series loaded and the first reconcile has answered. */
@@ -17356,7 +17410,10 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
17356
17410
  }), object({ enabled: boolean() }), {
17357
17411
  kind: "mutation",
17358
17412
  auth: "admin"
17359
- }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" });
17413
+ }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" }), method(object({}), OrphanListSchema, { auth: "admin" }), method(object({ seriesIds: array(number().int()).min(1).max(50) }), object({ results: array(OrphanDeleteEntrySchema).readonly() }), {
17414
+ kind: "mutation",
17415
+ auth: "admin"
17416
+ });
17360
17417
  var DeviceCaStatusSchema = discriminatedUnion("state", [
17361
17418
  object({ state: literal("absent") }),
17362
17419
  object({
@@ -55266,17 +55323,69 @@ var connectivityCapability = {
55266
55323
  volatileStateFields: ["lastChangedAt"]
55267
55324
  };
55268
55325
  /**
55269
- * Generic device-consumables capability — surfaces a device's
55270
- * maintenance items (vacuum filters/brushes, replaceable cartridges,
55271
- * descaling cycles, …) with their remaining life and an optional
55272
- * "Replaced" reset action. Device-agnostic: any provider that knows its
55273
- * device tracks consumables can register it; the cap declares no
55274
- * vocabulary of its own — the provider names each item verbatim.
55326
+ * Generic device-consumables capability — the ONE place a device reports what
55327
+ * it uses up or fills: wear parts (vacuum filters/brushes, cartridges,
55328
+ * descaling cycles), supplies it draws from (a vacuum's clean-water tank and
55329
+ * detergent, a dishwasher's salt and rinse aid) and waste it collects (a dirty
55330
+ * water tank, a dust bin). Each item carries its remaining life or fill and an
55331
+ * optional "Replaced" reset action. Device-agnostic: any provider that knows
55332
+ * its device tracks consumables registers it; the provider names each item
55333
+ * verbatim and says which `kind` it is.
55334
+ *
55335
+ * The admin UI renders it as ONE collapsible section directly under the
55336
+ * device page's hero card (`placement: 'hero'`), for every device bound to
55337
+ * this cap — never drawn by a device type's hero card itself (D915).
55275
55338
  *
55276
55339
  * Like `childLayout`, the cap is INERT until a provider sets items: no
55277
55340
  * provider populates it by guessing (no HA inference). The UI renders a
55278
55341
  * "No consumables reported" placeholder when `items` is empty.
55279
55342
  */
55343
+ /**
55344
+ * What an item IS, which decides which direction is bad:
55345
+ * - `wear` — a part that wears out (a brush, a filter); low life is bad.
55346
+ * - `supply` — something the device draws from (clean water, detergent,
55347
+ * salt, rinse aid); low or empty is bad.
55348
+ * - `waste` — something the device fills (dirty water, a dust bin); full is
55349
+ * bad.
55350
+ * Absent = `wear`.
55351
+ */
55352
+ var ConsumableKindSchema = _enum([
55353
+ "wear",
55354
+ "supply",
55355
+ "waste"
55356
+ ]);
55357
+ /**
55358
+ * What an item LOOKS like, which decides how a client draws it — independent
55359
+ * of `kind`, which decides which direction is bad:
55360
+ * - `part` — a part that wears (a brush, a filter, a mop pad): a wear bar,
55361
+ * remaining time and a reset.
55362
+ * - `tank` — a container of liquid (clean water, dirty water): a fill gauge.
55363
+ * - `product` — something bought and refilled (detergent, salt, rinse aid):
55364
+ * a stepped level and "refill".
55365
+ * - `bin` — a container that collects waste (a dust bin): a fill gauge
55366
+ * that warns when full.
55367
+ * Absent = derived from the kind ({@link consumableFormOf}).
55368
+ */
55369
+ var ConsumableFormSchema = _enum([
55370
+ "part",
55371
+ "tank",
55372
+ "product",
55373
+ "bin"
55374
+ ]);
55375
+ /** The provider's own discrete verdict on an item. */
55376
+ var ConsumableStatusSchema = _enum([
55377
+ "ok",
55378
+ "low",
55379
+ "empty",
55380
+ "full",
55381
+ "replace"
55382
+ ]);
55383
+ _enum([
55384
+ "ok",
55385
+ "low",
55386
+ "empty",
55387
+ "full"
55388
+ ]);
55280
55389
  /** Units a remaining-life counter is reported in. Closed: the panel renders
55281
55390
  * each. */
55282
55391
  var ConsumableRemainingUnitSchema = _enum([
@@ -55291,18 +55400,23 @@ var ConsumableRemainingSchema = object({
55291
55400
  unit: ConsumableRemainingUnitSchema
55292
55401
  });
55293
55402
  /** A single consumable item. Either a continuous `level` (remaining
55294
- * life %) or a discrete `status` may be known — both may be null when a
55295
- * provider only knows the item exists. `level` and `status` are not
55296
- * mutually exclusive; a provider may report both. */
55403
+ * life %, or fill % for a `supply` / `waste` item) or a discrete `status`
55404
+ * may be known — both may be null when a provider only knows the item
55405
+ * exists. `level` and `status` are not mutually exclusive; a provider may
55406
+ * report both. */
55297
55407
  var ConsumableItemSchema = object({
55298
55408
  /** Stable id, e.g. 'main-brush'. */
55299
55409
  key: string().min(1),
55300
55410
  /** Display name. */
55301
55411
  label: string().min(1),
55302
- /** Remaining life % when known (0..100). */
55412
+ /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
55303
55413
  level: number().min(0).max(100).nullable(),
55304
- /** Discrete state when known (binary mode). */
55305
- status: _enum(["ok", "replace"]).nullable(),
55414
+ /** The provider's discrete verdict when known (binary mode). */
55415
+ status: ConsumableStatusSchema.nullable(),
55416
+ /** What the item is — decides whether low or full is bad. Absent = `wear`. */
55417
+ kind: ConsumableKindSchema.optional(),
55418
+ /** How the item is drawn (part, tank, product, bin). Absent = derived from `kind`. */
55419
+ form: ConsumableFormSchema.optional(),
55306
55420
  /** Ms epoch of the last replace, when known. */
55307
55421
  lastResetAt: number().nullable(),
55308
55422
  /** Whether `reset()` is meaningful for this item. */
@@ -55325,7 +55439,7 @@ var consumablesCapability = {
55325
55439
  kind: "widget",
55326
55440
  widgetId: "host/consumables-panel",
55327
55441
  tab: "consumables",
55328
- topTab: true,
55442
+ placement: "hero",
55329
55443
  label: "Consumables",
55330
55444
  order: 5
55331
55445
  } },
@@ -55386,9 +55500,37 @@ reset: method(object({
55386
55500
  */
55387
55501
  durability: "restored",
55388
55502
  /**
55389
- * History (D850): none — `items` is an array keyed by runtime ids; a history path never enters it.
55503
+ * History (D850, D917): one series per (item field, item `key`) — the item key
55504
+ * is the series scope, the item `label` names it. A vacuum tank's fill, a
55505
+ * brush's remaining life and a dishwasher's salt are each recorded the moment
55506
+ * their provider reports them; an item that appears later gets its series.
55390
55507
  */
55391
- history: "none",
55508
+ history: {
55509
+ fields: {},
55510
+ items: {
55511
+ path: "items",
55512
+ key: "key",
55513
+ label: "label",
55514
+ fields: {
55515
+ level: {
55516
+ kind: "gauge",
55517
+ unit: "%",
55518
+ deadband: 2,
55519
+ displayName: "Level"
55520
+ },
55521
+ status: {
55522
+ kind: "enum",
55523
+ displayName: "Status"
55524
+ },
55525
+ "remaining.value": {
55526
+ kind: "gauge",
55527
+ unitFrom: "remaining.unit",
55528
+ deadband: 1,
55529
+ displayName: "Remaining"
55530
+ }
55531
+ }
55532
+ }
55533
+ },
55392
55534
  /** Clocks, not content: a re-read that changed no item costs no commit. */
55393
55535
  volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
55394
55536
  };
@@ -55803,8 +55945,9 @@ onStatusChanged: { data: object({
55803
55945
  volatileStateFields: ["lastChangedAt"]
55804
55946
  };
55805
55947
  /**
55806
- * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
55807
- * consumable levels (salt, rinse aid) and common program options.
55948
+ * Smart-dishwasher cap — program lifecycle, door / remote-start gates and
55949
+ * common program options. Salt and rinse aid are NOT here: they are items of
55950
+ * the device's `consumables` cap, like every other device's (D915).
55808
55951
  *
55809
55952
  * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
55810
55953
  * by any integration that exposes the same program / option surface.
@@ -55852,11 +55995,6 @@ var DishwasherAvailabilitySchema = _enum([
55852
55995
  "offline",
55853
55996
  "description-missing"
55854
55997
  ]);
55855
- var DishwasherConsumableLevelSchema = _enum([
55856
- "ok",
55857
- "low",
55858
- "empty"
55859
- ]);
55860
55998
  var DishwasherStatusSchema = object({
55861
55999
  availability: DishwasherAvailabilitySchema,
55862
56000
  /** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
@@ -55889,8 +56027,6 @@ var DishwasherStatusSchema = object({
55889
56027
  powerOn: boolean().nullable(),
55890
56028
  /** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
55891
56029
  powerState: string().nullable(),
55892
- saltLevel: DishwasherConsumableLevelSchema.nullable(),
55893
- rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
55894
56030
  /**
55895
56031
  * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
55896
56032
  * combined care-and-filter reminder raised); false when every such reminder reads clear; null
@@ -64706,60 +64842,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
64706
64842
  auth: "admin",
64707
64843
  access: "delete"
64708
64844
  });
64709
- /**
64710
- * Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
64711
- * cleaning lifecycle plus a return-to-base / locate surface and an
64712
- * optional fan-speed selector.
64713
- *
64714
- * State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
64715
- * `paused` / `returning` / `docked` / `error`. `batteryLevel`
64716
- * (0..100) is nullable — some vacuums don't report a battery
64717
- * percentage. `fanSpeed` is the current speed token (provider-verbatim,
64718
- * e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
64719
- * tokens the hardware accepts so the UI renders only supported choices.
64720
- *
64721
- * The `setFanSpeed` method takes the bare `speed` token — the provider
64722
- * validates it against the vacuum's own list. `locate` triggers the
64723
- * find-me chirp; `returnToBase` sends it home.
64724
- *
64725
- * Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
64726
- * `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
64727
- * 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
64728
- * SHOULD populate whichever tanks the hardware has — leave a field `null`
64729
- * only when the device has no such tank at all, and use a `TankStatus`
64730
- * with both inner fields `null` when the tank exists but its level is
64731
- * currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
64732
- * so the HA provider leaves all four `null`.
64733
- */
64734
- var VacuumStateSchema = _enum([
64735
- "idle",
64736
- "cleaning",
64737
- "paused",
64738
- "returning",
64739
- "docked",
64740
- "drying",
64741
- "error"
64742
- ]);
64743
- /**
64744
- * One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
64745
- * detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
64746
- * a discrete `status` (binary-style hardware), or both. Both `null` means the
64747
- * level is currently unknown; the OWNING field being `null` means the
64748
- * hardware has no such tank at all.
64749
- */
64750
- var TankStatusSchema = object({
64751
- /** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
64752
- level: number().min(0).max(100).nullable(),
64753
- /** Discrete state when the hardware is binary-mode; null otherwise. */
64754
- status: _enum([
64755
- "ok",
64756
- "low",
64757
- "full"
64758
- ]).nullable()
64759
- });
64760
64845
  var VacuumControlStatusSchema = object({
64761
64846
  /** Lifecycle state of the vacuum. */
64762
- state: VacuumStateSchema,
64847
+ state: _enum([
64848
+ "idle",
64849
+ "cleaning",
64850
+ "paused",
64851
+ "returning",
64852
+ "docked",
64853
+ "drying",
64854
+ "error"
64855
+ ]),
64763
64856
  /** 0..100 battery percentage. Null when the device has no battery
64764
64857
  * reading. */
64765
64858
  batteryLevel: number().min(0).max(100).nullable(),
@@ -64768,14 +64861,6 @@ var VacuumControlStatusSchema = object({
64768
64861
  fanSpeed: string().nullable(),
64769
64862
  /** Speed tokens the hardware accepts — drives the UI selector. */
64770
64863
  availableFanSpeeds: array(string()),
64771
- /** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
64772
- cleanWater: TankStatusSchema.nullable(),
64773
- /** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
64774
- dirtyWater: TankStatusSchema.nullable(),
64775
- /** Detergent tank. Null when the hardware has no detergent tank. */
64776
- detergent: TankStatusSchema.nullable(),
64777
- /** Dust bin. Null when the hardware has no dust bin. */
64778
- dustBin: TankStatusSchema.nullable(),
64779
64864
  /** 0..100 cleaning-completion percentage of the current task, or null. */
64780
64865
  progressPercent: number().min(0).max(100).nullable(),
64781
64866
  /** Current error code (0 / null = no error). */
@@ -64837,35 +64922,14 @@ var vacuumControlCapability = {
64837
64922
  */
64838
64923
  durability: "session",
64839
64924
  /**
64840
- * History (D850): recorded series. Tank levels are fixed-object paths (`cleanWater.level`, ...).
64925
+ * History (D850): recorded series. The tanks moved to `consumables` (D915), whose
64926
+ * items are keyed by runtime ids and record no history.
64841
64927
  */
64842
- history: { fields: {
64843
- batteryLevel: {
64844
- kind: "gauge",
64845
- unit: "%",
64846
- deadband: 2
64847
- },
64848
- "cleanWater.level": {
64849
- kind: "gauge",
64850
- unit: "%",
64851
- deadband: 2
64852
- },
64853
- "dirtyWater.level": {
64854
- kind: "gauge",
64855
- unit: "%",
64856
- deadband: 2
64857
- },
64858
- "detergent.level": {
64859
- kind: "gauge",
64860
- unit: "%",
64861
- deadband: 2
64862
- },
64863
- "dustBin.level": {
64864
- kind: "gauge",
64865
- unit: "%",
64866
- deadband: 2
64867
- }
64868
- } }
64928
+ history: { fields: { batteryLevel: {
64929
+ kind: "gauge",
64930
+ unit: "%",
64931
+ deadband: 2
64932
+ } } }
64869
64933
  };
64870
64934
  var ValveStatusSchema = object({
64871
64935
  /** Lifecycle state of the valve. */
@@ -68776,6 +68840,12 @@ Object.freeze({
68776
68840
  addonId: null,
68777
68841
  access: "create"
68778
68842
  },
68843
+ "deviceHistory.deleteOrphanSeries": {
68844
+ capName: "device-history",
68845
+ capScope: "system",
68846
+ addonId: null,
68847
+ access: "delete"
68848
+ },
68779
68849
  "deviceHistory.getDeviceEnabled": {
68780
68850
  capName: "device-history",
68781
68851
  capScope: "system",
@@ -68794,6 +68864,12 @@ Object.freeze({
68794
68864
  addonId: null,
68795
68865
  access: "view"
68796
68866
  },
68867
+ "deviceHistory.listOrphanSeries": {
68868
+ capName: "device-history",
68869
+ capScope: "system",
68870
+ addonId: null,
68871
+ access: "view"
68872
+ },
68797
68873
  "deviceHistory.listSeries": {
68798
68874
  capName: "device-history",
68799
68875
  capScope: "system",
@@ -78799,7 +78875,7 @@ var STATE_SUMMARY_VARS = [
78799
78875
  ([...RULE_TEXT], [...COMBINED_ALARM]),
78800
78876
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
78801
78877
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
78802
- ([...RULE_TEXT], [...CONSUMABLE]),
78878
+ ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
78803
78879
  ([...RULE_TEXT], [...TANK]),
78804
78880
  [...RULE_TEXT],
78805
78881
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
package/dist/addon.mjs CHANGED
@@ -5440,7 +5440,7 @@ var ZodIssueCode = {
5440
5440
  var ZodFirstPartyTypeKind;
5441
5441
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5442
5442
  //#endregion
5443
- //#region ../types/dist/sleep-DJFUfKvA.mjs
5443
+ //#region ../types/dist/sleep-CUp20JkO.mjs
5444
5444
  /**
5445
5445
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5446
5446
  * window to float samples (D455).
@@ -8391,7 +8391,11 @@ var ContributionSectionSchema = object({
8391
8391
  literal(4)
8392
8392
  ]).optional(),
8393
8393
  tab: string().optional(),
8394
- location: _enum(["settings", "top-tab"]).optional(),
8394
+ location: _enum([
8395
+ "settings",
8396
+ "top-tab",
8397
+ "hero"
8398
+ ]).optional(),
8395
8399
  order: number().optional(),
8396
8400
  fields: array(any())
8397
8401
  });
@@ -13356,7 +13360,11 @@ var ConfigSectionWithValuesSchema = object({
13356
13360
  literal(4)
13357
13361
  ]).optional(),
13358
13362
  tab: string().optional(),
13359
- location: _enum(["settings", "top-tab"]).optional(),
13363
+ location: _enum([
13364
+ "settings",
13365
+ "top-tab",
13366
+ "hero"
13367
+ ]).optional(),
13360
13368
  order: number().optional(),
13361
13369
  fields: array(any())
13362
13370
  });
@@ -17236,6 +17244,52 @@ var TierStatusSchema = object({
17236
17244
  countedAt: number().nullable()
17237
17245
  });
17238
17246
  /** Operator/diagnostic view: rows per tier, last runs, refusals and drops since boot. */
17247
+ /**
17248
+ * Why a series is orphan. `device-gone`: its device is absent from the
17249
+ * successful device listings (the departure clock). `undeclared`: its `cap:`
17250
+ * key is declared by no capability any more (a field a cap removed).
17251
+ */
17252
+ var DeviceHistoryOrphanReasonSchema = _enum(["device-gone", "undeclared"]);
17253
+ /** Rows held per stored tier. */
17254
+ var TierRowsSchema = object({
17255
+ raw: number().int(),
17256
+ "5m": number().int(),
17257
+ "1h": number().int(),
17258
+ "1d": number().int()
17259
+ });
17260
+ var OrphanSeriesSchema = object({
17261
+ seriesId: number().int(),
17262
+ deviceId: number().int(),
17263
+ key: string(),
17264
+ scope: string(),
17265
+ /** The metric's display name; `null` when its metric row is gone too. */
17266
+ displayName: string().nullable(),
17267
+ reason: DeviceHistoryOrphanReasonSchema,
17268
+ /** `device-gone`: since when the device has been absent; `null` otherwise. */
17269
+ missingSince: number().nullable(),
17270
+ firstTs: number(),
17271
+ lastTs: number(),
17272
+ rows: TierRowsSchema
17273
+ });
17274
+ var DeviceHistoryOrphanDeleteRefusalSchema = _enum([
17275
+ "not-found",
17276
+ "not-orphan",
17277
+ "failed"
17278
+ ]);
17279
+ var OrphanDeleteEntrySchema = discriminatedUnion("ok", [object({
17280
+ seriesId: number().int(),
17281
+ ok: literal(true),
17282
+ deleted: TierRowsSchema
17283
+ }), object({
17284
+ seriesId: number().int(),
17285
+ ok: literal(false),
17286
+ reason: DeviceHistoryOrphanDeleteRefusalSchema
17287
+ })]);
17288
+ var OrphanListSchema = object({
17289
+ series: array(OrphanSeriesSchema).readonly(),
17290
+ /** More orphans exist than {@link DEVICE_HISTORY_ORPHAN_LIST_MAX}. */
17291
+ truncated: boolean()
17292
+ });
17239
17293
  var DeviceHistoryStatusSchema = object({
17240
17294
  startedAt: number(),
17241
17295
  /** The store is declared, series loaded and the first reconcile has answered. */
@@ -17333,7 +17387,10 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
17333
17387
  }), object({ enabled: boolean() }), {
17334
17388
  kind: "mutation",
17335
17389
  auth: "admin"
17336
- }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" });
17390
+ }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" }), method(object({}), OrphanListSchema, { auth: "admin" }), method(object({ seriesIds: array(number().int()).min(1).max(50) }), object({ results: array(OrphanDeleteEntrySchema).readonly() }), {
17391
+ kind: "mutation",
17392
+ auth: "admin"
17393
+ });
17337
17394
  var DeviceCaStatusSchema = discriminatedUnion("state", [
17338
17395
  object({ state: literal("absent") }),
17339
17396
  object({
@@ -55243,17 +55300,69 @@ var connectivityCapability = {
55243
55300
  volatileStateFields: ["lastChangedAt"]
55244
55301
  };
55245
55302
  /**
55246
- * Generic device-consumables capability — surfaces a device's
55247
- * maintenance items (vacuum filters/brushes, replaceable cartridges,
55248
- * descaling cycles, …) with their remaining life and an optional
55249
- * "Replaced" reset action. Device-agnostic: any provider that knows its
55250
- * device tracks consumables can register it; the cap declares no
55251
- * vocabulary of its own — the provider names each item verbatim.
55303
+ * Generic device-consumables capability — the ONE place a device reports what
55304
+ * it uses up or fills: wear parts (vacuum filters/brushes, cartridges,
55305
+ * descaling cycles), supplies it draws from (a vacuum's clean-water tank and
55306
+ * detergent, a dishwasher's salt and rinse aid) and waste it collects (a dirty
55307
+ * water tank, a dust bin). Each item carries its remaining life or fill and an
55308
+ * optional "Replaced" reset action. Device-agnostic: any provider that knows
55309
+ * its device tracks consumables registers it; the provider names each item
55310
+ * verbatim and says which `kind` it is.
55311
+ *
55312
+ * The admin UI renders it as ONE collapsible section directly under the
55313
+ * device page's hero card (`placement: 'hero'`), for every device bound to
55314
+ * this cap — never drawn by a device type's hero card itself (D915).
55252
55315
  *
55253
55316
  * Like `childLayout`, the cap is INERT until a provider sets items: no
55254
55317
  * provider populates it by guessing (no HA inference). The UI renders a
55255
55318
  * "No consumables reported" placeholder when `items` is empty.
55256
55319
  */
55320
+ /**
55321
+ * What an item IS, which decides which direction is bad:
55322
+ * - `wear` — a part that wears out (a brush, a filter); low life is bad.
55323
+ * - `supply` — something the device draws from (clean water, detergent,
55324
+ * salt, rinse aid); low or empty is bad.
55325
+ * - `waste` — something the device fills (dirty water, a dust bin); full is
55326
+ * bad.
55327
+ * Absent = `wear`.
55328
+ */
55329
+ var ConsumableKindSchema = _enum([
55330
+ "wear",
55331
+ "supply",
55332
+ "waste"
55333
+ ]);
55334
+ /**
55335
+ * What an item LOOKS like, which decides how a client draws it — independent
55336
+ * of `kind`, which decides which direction is bad:
55337
+ * - `part` — a part that wears (a brush, a filter, a mop pad): a wear bar,
55338
+ * remaining time and a reset.
55339
+ * - `tank` — a container of liquid (clean water, dirty water): a fill gauge.
55340
+ * - `product` — something bought and refilled (detergent, salt, rinse aid):
55341
+ * a stepped level and "refill".
55342
+ * - `bin` — a container that collects waste (a dust bin): a fill gauge
55343
+ * that warns when full.
55344
+ * Absent = derived from the kind ({@link consumableFormOf}).
55345
+ */
55346
+ var ConsumableFormSchema = _enum([
55347
+ "part",
55348
+ "tank",
55349
+ "product",
55350
+ "bin"
55351
+ ]);
55352
+ /** The provider's own discrete verdict on an item. */
55353
+ var ConsumableStatusSchema = _enum([
55354
+ "ok",
55355
+ "low",
55356
+ "empty",
55357
+ "full",
55358
+ "replace"
55359
+ ]);
55360
+ _enum([
55361
+ "ok",
55362
+ "low",
55363
+ "empty",
55364
+ "full"
55365
+ ]);
55257
55366
  /** Units a remaining-life counter is reported in. Closed: the panel renders
55258
55367
  * each. */
55259
55368
  var ConsumableRemainingUnitSchema = _enum([
@@ -55268,18 +55377,23 @@ var ConsumableRemainingSchema = object({
55268
55377
  unit: ConsumableRemainingUnitSchema
55269
55378
  });
55270
55379
  /** A single consumable item. Either a continuous `level` (remaining
55271
- * life %) or a discrete `status` may be known — both may be null when a
55272
- * provider only knows the item exists. `level` and `status` are not
55273
- * mutually exclusive; a provider may report both. */
55380
+ * life %, or fill % for a `supply` / `waste` item) or a discrete `status`
55381
+ * may be known — both may be null when a provider only knows the item
55382
+ * exists. `level` and `status` are not mutually exclusive; a provider may
55383
+ * report both. */
55274
55384
  var ConsumableItemSchema = object({
55275
55385
  /** Stable id, e.g. 'main-brush'. */
55276
55386
  key: string().min(1),
55277
55387
  /** Display name. */
55278
55388
  label: string().min(1),
55279
- /** Remaining life % when known (0..100). */
55389
+ /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
55280
55390
  level: number().min(0).max(100).nullable(),
55281
- /** Discrete state when known (binary mode). */
55282
- status: _enum(["ok", "replace"]).nullable(),
55391
+ /** The provider's discrete verdict when known (binary mode). */
55392
+ status: ConsumableStatusSchema.nullable(),
55393
+ /** What the item is — decides whether low or full is bad. Absent = `wear`. */
55394
+ kind: ConsumableKindSchema.optional(),
55395
+ /** How the item is drawn (part, tank, product, bin). Absent = derived from `kind`. */
55396
+ form: ConsumableFormSchema.optional(),
55283
55397
  /** Ms epoch of the last replace, when known. */
55284
55398
  lastResetAt: number().nullable(),
55285
55399
  /** Whether `reset()` is meaningful for this item. */
@@ -55302,7 +55416,7 @@ var consumablesCapability = {
55302
55416
  kind: "widget",
55303
55417
  widgetId: "host/consumables-panel",
55304
55418
  tab: "consumables",
55305
- topTab: true,
55419
+ placement: "hero",
55306
55420
  label: "Consumables",
55307
55421
  order: 5
55308
55422
  } },
@@ -55363,9 +55477,37 @@ reset: method(object({
55363
55477
  */
55364
55478
  durability: "restored",
55365
55479
  /**
55366
- * History (D850): none — `items` is an array keyed by runtime ids; a history path never enters it.
55480
+ * History (D850, D917): one series per (item field, item `key`) — the item key
55481
+ * is the series scope, the item `label` names it. A vacuum tank's fill, a
55482
+ * brush's remaining life and a dishwasher's salt are each recorded the moment
55483
+ * their provider reports them; an item that appears later gets its series.
55367
55484
  */
55368
- history: "none",
55485
+ history: {
55486
+ fields: {},
55487
+ items: {
55488
+ path: "items",
55489
+ key: "key",
55490
+ label: "label",
55491
+ fields: {
55492
+ level: {
55493
+ kind: "gauge",
55494
+ unit: "%",
55495
+ deadband: 2,
55496
+ displayName: "Level"
55497
+ },
55498
+ status: {
55499
+ kind: "enum",
55500
+ displayName: "Status"
55501
+ },
55502
+ "remaining.value": {
55503
+ kind: "gauge",
55504
+ unitFrom: "remaining.unit",
55505
+ deadband: 1,
55506
+ displayName: "Remaining"
55507
+ }
55508
+ }
55509
+ }
55510
+ },
55369
55511
  /** Clocks, not content: a re-read that changed no item costs no commit. */
55370
55512
  volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
55371
55513
  };
@@ -55780,8 +55922,9 @@ onStatusChanged: { data: object({
55780
55922
  volatileStateFields: ["lastChangedAt"]
55781
55923
  };
55782
55924
  /**
55783
- * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
55784
- * consumable levels (salt, rinse aid) and common program options.
55925
+ * Smart-dishwasher cap — program lifecycle, door / remote-start gates and
55926
+ * common program options. Salt and rinse aid are NOT here: they are items of
55927
+ * the device's `consumables` cap, like every other device's (D915).
55785
55928
  *
55786
55929
  * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
55787
55930
  * by any integration that exposes the same program / option surface.
@@ -55829,11 +55972,6 @@ var DishwasherAvailabilitySchema = _enum([
55829
55972
  "offline",
55830
55973
  "description-missing"
55831
55974
  ]);
55832
- var DishwasherConsumableLevelSchema = _enum([
55833
- "ok",
55834
- "low",
55835
- "empty"
55836
- ]);
55837
55975
  var DishwasherStatusSchema = object({
55838
55976
  availability: DishwasherAvailabilitySchema,
55839
55977
  /** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
@@ -55866,8 +56004,6 @@ var DishwasherStatusSchema = object({
55866
56004
  powerOn: boolean().nullable(),
55867
56005
  /** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
55868
56006
  powerState: string().nullable(),
55869
- saltLevel: DishwasherConsumableLevelSchema.nullable(),
55870
- rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
55871
56007
  /**
55872
56008
  * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
55873
56009
  * combined care-and-filter reminder raised); false when every such reminder reads clear; null
@@ -64683,60 +64819,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
64683
64819
  auth: "admin",
64684
64820
  access: "delete"
64685
64821
  });
64686
- /**
64687
- * Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
64688
- * cleaning lifecycle plus a return-to-base / locate surface and an
64689
- * optional fan-speed selector.
64690
- *
64691
- * State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
64692
- * `paused` / `returning` / `docked` / `error`. `batteryLevel`
64693
- * (0..100) is nullable — some vacuums don't report a battery
64694
- * percentage. `fanSpeed` is the current speed token (provider-verbatim,
64695
- * e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
64696
- * tokens the hardware accepts so the UI renders only supported choices.
64697
- *
64698
- * The `setFanSpeed` method takes the bare `speed` token — the provider
64699
- * validates it against the vacuum's own list. `locate` triggers the
64700
- * find-me chirp; `returnToBase` sends it home.
64701
- *
64702
- * Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
64703
- * `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
64704
- * 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
64705
- * SHOULD populate whichever tanks the hardware has — leave a field `null`
64706
- * only when the device has no such tank at all, and use a `TankStatus`
64707
- * with both inner fields `null` when the tank exists but its level is
64708
- * currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
64709
- * so the HA provider leaves all four `null`.
64710
- */
64711
- var VacuumStateSchema = _enum([
64712
- "idle",
64713
- "cleaning",
64714
- "paused",
64715
- "returning",
64716
- "docked",
64717
- "drying",
64718
- "error"
64719
- ]);
64720
- /**
64721
- * One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
64722
- * detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
64723
- * a discrete `status` (binary-style hardware), or both. Both `null` means the
64724
- * level is currently unknown; the OWNING field being `null` means the
64725
- * hardware has no such tank at all.
64726
- */
64727
- var TankStatusSchema = object({
64728
- /** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
64729
- level: number().min(0).max(100).nullable(),
64730
- /** Discrete state when the hardware is binary-mode; null otherwise. */
64731
- status: _enum([
64732
- "ok",
64733
- "low",
64734
- "full"
64735
- ]).nullable()
64736
- });
64737
64822
  var VacuumControlStatusSchema = object({
64738
64823
  /** Lifecycle state of the vacuum. */
64739
- state: VacuumStateSchema,
64824
+ state: _enum([
64825
+ "idle",
64826
+ "cleaning",
64827
+ "paused",
64828
+ "returning",
64829
+ "docked",
64830
+ "drying",
64831
+ "error"
64832
+ ]),
64740
64833
  /** 0..100 battery percentage. Null when the device has no battery
64741
64834
  * reading. */
64742
64835
  batteryLevel: number().min(0).max(100).nullable(),
@@ -64745,14 +64838,6 @@ var VacuumControlStatusSchema = object({
64745
64838
  fanSpeed: string().nullable(),
64746
64839
  /** Speed tokens the hardware accepts — drives the UI selector. */
64747
64840
  availableFanSpeeds: array(string()),
64748
- /** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
64749
- cleanWater: TankStatusSchema.nullable(),
64750
- /** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
64751
- dirtyWater: TankStatusSchema.nullable(),
64752
- /** Detergent tank. Null when the hardware has no detergent tank. */
64753
- detergent: TankStatusSchema.nullable(),
64754
- /** Dust bin. Null when the hardware has no dust bin. */
64755
- dustBin: TankStatusSchema.nullable(),
64756
64841
  /** 0..100 cleaning-completion percentage of the current task, or null. */
64757
64842
  progressPercent: number().min(0).max(100).nullable(),
64758
64843
  /** Current error code (0 / null = no error). */
@@ -64814,35 +64899,14 @@ var vacuumControlCapability = {
64814
64899
  */
64815
64900
  durability: "session",
64816
64901
  /**
64817
- * History (D850): recorded series. Tank levels are fixed-object paths (`cleanWater.level`, ...).
64902
+ * History (D850): recorded series. The tanks moved to `consumables` (D915), whose
64903
+ * items are keyed by runtime ids and record no history.
64818
64904
  */
64819
- history: { fields: {
64820
- batteryLevel: {
64821
- kind: "gauge",
64822
- unit: "%",
64823
- deadband: 2
64824
- },
64825
- "cleanWater.level": {
64826
- kind: "gauge",
64827
- unit: "%",
64828
- deadband: 2
64829
- },
64830
- "dirtyWater.level": {
64831
- kind: "gauge",
64832
- unit: "%",
64833
- deadband: 2
64834
- },
64835
- "detergent.level": {
64836
- kind: "gauge",
64837
- unit: "%",
64838
- deadband: 2
64839
- },
64840
- "dustBin.level": {
64841
- kind: "gauge",
64842
- unit: "%",
64843
- deadband: 2
64844
- }
64845
- } }
64905
+ history: { fields: { batteryLevel: {
64906
+ kind: "gauge",
64907
+ unit: "%",
64908
+ deadband: 2
64909
+ } } }
64846
64910
  };
64847
64911
  var ValveStatusSchema = object({
64848
64912
  /** Lifecycle state of the valve. */
@@ -68753,6 +68817,12 @@ Object.freeze({
68753
68817
  addonId: null,
68754
68818
  access: "create"
68755
68819
  },
68820
+ "deviceHistory.deleteOrphanSeries": {
68821
+ capName: "device-history",
68822
+ capScope: "system",
68823
+ addonId: null,
68824
+ access: "delete"
68825
+ },
68756
68826
  "deviceHistory.getDeviceEnabled": {
68757
68827
  capName: "device-history",
68758
68828
  capScope: "system",
@@ -68771,6 +68841,12 @@ Object.freeze({
68771
68841
  addonId: null,
68772
68842
  access: "view"
68773
68843
  },
68844
+ "deviceHistory.listOrphanSeries": {
68845
+ capName: "device-history",
68846
+ capScope: "system",
68847
+ addonId: null,
68848
+ access: "view"
68849
+ },
68774
68850
  "deviceHistory.listSeries": {
68775
68851
  capName: "device-history",
68776
68852
  capScope: "system",
@@ -78776,7 +78852,7 @@ var STATE_SUMMARY_VARS = [
78776
78852
  ([...RULE_TEXT], [...COMBINED_ALARM]),
78777
78853
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
78778
78854
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
78779
- ([...RULE_TEXT], [...CONSUMABLE]),
78855
+ ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
78780
78856
  ([...RULE_TEXT], [...TANK]),
78781
78857
  [...RULE_TEXT],
78782
78858
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-terminal",
3
- "version": "0.1.149",
3
+ "version": "0.1.150",
4
4
  "description": "Interactive terminal sessions (pty + xterm) as a CamStack addon",
5
5
  "keywords": [
6
6
  "camstack",