@camstack/types 1.2.267 → 1.2.269

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 (69) hide show
  1. package/dist/addon.js +4 -4
  2. package/dist/addon.mjs +3 -3
  3. package/dist/capabilities/battery.cap.d.ts +17 -2
  4. package/dist/capabilities/capability-definition.d.ts +30 -1
  5. package/dist/capabilities/composer.cap.d.ts +105 -0
  6. package/dist/capabilities/consumables.cap.d.ts +79 -0
  7. package/dist/capabilities/core-blocks.cap.d.ts +1213 -104
  8. package/dist/capabilities/device-extension.cap.d.ts +12 -13
  9. package/dist/capabilities/device-manager.cap.d.ts +4 -4
  10. package/dist/capabilities/device-state.cap.d.ts +186 -2
  11. package/dist/capabilities/doorbell.cap.d.ts +4 -0
  12. package/dist/capabilities/index.d.ts +3 -3
  13. package/dist/capabilities/media-player.cap.d.ts +4 -4
  14. package/dist/capabilities/recording-archive.cap.d.ts +3 -3
  15. package/dist/catalogs/sensor-active-state.d.ts +25 -1
  16. package/dist/composition/composition-events.d.ts +42 -0
  17. package/dist/composition/composition-graph.d.ts +42 -9
  18. package/dist/composition/composition-items.d.ts +25 -0
  19. package/dist/composition/composition-report.d.ts +115 -12
  20. package/dist/composition/composition.d.ts +162 -3
  21. package/dist/composition/customization-name.d.ts +6 -0
  22. package/dist/composition/evaluate-field.d.ts +20 -0
  23. package/dist/composition/examples.d.ts +33 -0
  24. package/dist/composition/expression-kinds.d.ts +1 -0
  25. package/dist/composition/field-kinds.d.ts +42 -0
  26. package/dist/composition/index.d.ts +2 -0
  27. package/dist/composition/plan-result.d.ts +18 -0
  28. package/dist/composition/state-fields.d.ts +6 -0
  29. package/dist/composition/validate-composition.d.ts +44 -9
  30. package/dist/composition-BAH3n-zq.js +2582 -0
  31. package/dist/composition-D5BQywfe.mjs +2055 -0
  32. package/dist/device/device-context.d.ts +9 -0
  33. package/dist/device/device-runtime-state.d.ts +15 -1
  34. package/dist/device/index.d.ts +1 -1
  35. package/dist/device-extension/slot-descriptor.d.ts +8 -11
  36. package/dist/device-extension/slot-provider.d.ts +0 -2
  37. package/dist/enums/event-category.d.ts +25 -0
  38. package/dist/enums.js +1 -1
  39. package/dist/enums.mjs +1 -1
  40. package/dist/err-msg-DX6i_MY4.mjs +339 -0
  41. package/dist/err-msg-Dx2Kor0g.js +368 -0
  42. package/dist/{event-category-BVDXG4tB.mjs → event-category-C5xZWqz6.mjs} +31 -1
  43. package/dist/{event-category-BVfsrBYA.js → event-category-MbnB-6AN.js} +48 -0
  44. package/dist/expression/ast.d.ts +2 -0
  45. package/dist/expression/builtins.d.ts +9 -0
  46. package/dist/expression/evaluator.d.ts +8 -2
  47. package/dist/expression/expression-source.d.ts +26 -4
  48. package/dist/expression/index.d.ts +6 -6
  49. package/dist/generated/addon-api.d.ts +42 -0
  50. package/dist/generated/device-proxy.d.ts +1 -1
  51. package/dist/generated/method-access-map.d.ts +1 -1
  52. package/dist/generated/method-device-selectors.d.ts +2 -2
  53. package/dist/generated/system-proxy.d.ts +2 -2
  54. package/dist/index.d.ts +7 -6
  55. package/dist/index.js +1687 -1833
  56. package/dist/index.mjs +1359 -1550
  57. package/dist/interfaces/kernel-abstractions.d.ts +16 -0
  58. package/dist/interfaces/recording-config.d.ts +3 -3
  59. package/dist/interfaces/status-overlay.d.ts +42 -0
  60. package/dist/node.d.ts +1 -0
  61. package/dist/node.js +29 -8
  62. package/dist/node.mjs +23 -3
  63. package/dist/{sleep-8K9gue-H.js → sleep-Bg0IB7gg.js} +10 -367
  64. package/dist/{sleep-DC-wdyeS.mjs → sleep-E6eD4yQS.mjs} +11 -344
  65. package/package.json +1 -1
  66. package/dist/canonical-hash-CPK2Dy60.mjs +0 -715
  67. package/dist/canonical-hash-CSE4ioRi.js +0 -792
  68. package/dist/err-msg-COpsHMw2.js +0 -18
  69. package/dist/err-msg-IQTHeDzc.mjs +0 -13
@@ -5,15 +5,15 @@
5
5
  import { z } from 'zod';
6
6
  export declare const CompositionProblemCodeSchema: z.ZodEnum<{
7
7
  "source-missing": "source-missing";
8
+ "unknown-field": "unknown-field";
9
+ "kind-mismatch": "kind-mismatch";
10
+ "not-composable": "not-composable";
8
11
  "reserved-variant": "reserved-variant";
9
12
  "unknown-capability": "unknown-capability";
10
- "not-composable": "not-composable";
11
13
  "wrong-device-type": "wrong-device-type";
12
14
  "has-commands": "has-commands";
13
- "unknown-field": "unknown-field";
14
15
  "nested-field": "nested-field";
15
16
  "missing-field": "missing-field";
16
- "kind-mismatch": "kind-mismatch";
17
17
  "may-be-null": "may-be-null";
18
18
  "source-unreadable": "source-unreadable";
19
19
  "source-capability-missing": "source-capability-missing";
@@ -21,21 +21,26 @@ export declare const CompositionProblemCodeSchema: z.ZodEnum<{
21
21
  "expression-invalid": "expression-invalid";
22
22
  cycle: "cycle";
23
23
  "duplicate-target": "duplicate-target";
24
+ "not-item-array": "not-item-array";
25
+ "item-field-reserved": "item-field-reserved";
26
+ "target-missing": "target-missing";
27
+ "target-unreadable": "target-unreadable";
28
+ "not-replaceable": "not-replaceable";
24
29
  }>;
25
30
  export type CompositionProblemCode = z.infer<typeof CompositionProblemCodeSchema>;
26
31
  /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
27
32
  export declare const CompositionProblemSchema: z.ZodObject<{
28
33
  code: z.ZodEnum<{
29
34
  "source-missing": "source-missing";
35
+ "unknown-field": "unknown-field";
36
+ "kind-mismatch": "kind-mismatch";
37
+ "not-composable": "not-composable";
30
38
  "reserved-variant": "reserved-variant";
31
39
  "unknown-capability": "unknown-capability";
32
- "not-composable": "not-composable";
33
40
  "wrong-device-type": "wrong-device-type";
34
41
  "has-commands": "has-commands";
35
- "unknown-field": "unknown-field";
36
42
  "nested-field": "nested-field";
37
43
  "missing-field": "missing-field";
38
- "kind-mismatch": "kind-mismatch";
39
44
  "may-be-null": "may-be-null";
40
45
  "source-unreadable": "source-unreadable";
41
46
  "source-capability-missing": "source-capability-missing";
@@ -43,6 +48,11 @@ export declare const CompositionProblemSchema: z.ZodObject<{
43
48
  "expression-invalid": "expression-invalid";
44
49
  cycle: "cycle";
45
50
  "duplicate-target": "duplicate-target";
51
+ "not-item-array": "not-item-array";
52
+ "item-field-reserved": "item-field-reserved";
53
+ "target-missing": "target-missing";
54
+ "target-unreadable": "target-unreadable";
55
+ "not-replaceable": "not-replaceable";
46
56
  }>;
47
57
  path: z.ZodString;
48
58
  message: z.ZodString;
@@ -55,25 +65,46 @@ export declare const CompositionFieldKindSchema: z.ZodEnum<{
55
65
  enum: "enum";
56
66
  }>;
57
67
  export type CompositionFieldKind = z.infer<typeof CompositionFieldKindSchema>;
58
- /** How a field says "unavailable": `null` when its schema allows it, else the device goes offline (D393). */
68
+ /**
69
+ * How a field says "unavailable" (D393, D663): `null` when its schema allows it;
70
+ * `unknown` — the enum's own word — for an ADDED field that has one; `release`
71
+ * for a REPLACED field of an existing device, whose claim is released so the
72
+ * native provider's reading shows again; else the (composed) device goes offline.
73
+ */
59
74
  export declare const CompositionUnavailableModeSchema: z.ZodEnum<{
60
75
  null: "null";
76
+ unknown: "unknown";
61
77
  offline: "offline";
78
+ release: "release";
62
79
  }>;
63
80
  export type CompositionUnavailableMode = z.infer<typeof CompositionUnavailableModeSchema>;
64
81
  /**
65
82
  * `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
66
- * field of its cap changes value · `constant` reads nothing, computed once.
83
+ * field of its cap changes value · `constant` reads nothing, computed once ·
84
+ * `accumulator` advances from the target's seed/current output.
67
85
  */
68
86
  export declare const CompositionFieldRoleSchema: z.ZodEnum<{
69
87
  derived: "derived";
70
88
  clock: "clock";
71
89
  constant: "constant";
90
+ accumulator: "accumulator";
72
91
  }>;
73
92
  export type CompositionFieldRole = z.infer<typeof CompositionFieldRoleSchema>;
93
+ /** The item a planned field belongs to; its `path` is then the dotted path INSIDE the item. */
94
+ export declare const CompositionFieldItemSchema: z.ZodObject<{
95
+ arrayPath: z.ZodString;
96
+ key: z.ZodString;
97
+ label: z.ZodString;
98
+ }, z.core.$strip>;
99
+ export type CompositionFieldItem = z.infer<typeof CompositionFieldItemSchema>;
74
100
  export declare const CompositionFieldPlanSchema: z.ZodObject<{
75
101
  cap: z.ZodString;
76
102
  path: z.ZodString;
103
+ item: z.ZodOptional<z.ZodObject<{
104
+ arrayPath: z.ZodString;
105
+ key: z.ZodString;
106
+ label: z.ZodString;
107
+ }, z.core.$strip>>;
77
108
  featureIndex: z.ZodNumber;
78
109
  kind: z.ZodEnum<{
79
110
  string: "string";
@@ -85,12 +116,15 @@ export declare const CompositionFieldPlanSchema: z.ZodObject<{
85
116
  required: z.ZodBoolean;
86
117
  unavailable: z.ZodEnum<{
87
118
  null: "null";
119
+ unknown: "unknown";
88
120
  offline: "offline";
121
+ release: "release";
89
122
  }>;
90
123
  role: z.ZodEnum<{
91
124
  derived: "derived";
92
125
  clock: "clock";
93
126
  constant: "constant";
127
+ accumulator: "accumulator";
94
128
  }>;
95
129
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
96
130
  source: z.ZodObject<{
@@ -129,20 +163,43 @@ export declare const CompositionFieldPlanSchema: z.ZodObject<{
129
163
  }, z.core.$strip>>;
130
164
  }, z.core.$strip>;
131
165
  export type CompositionFieldPlan = z.infer<typeof CompositionFieldPlanSchema>;
166
+ /** The key every record map, log line and graph node uses for a planned field. Two items' `status` are two keys. */
167
+ export declare function compositionFieldKey(plan: Pick<CompositionFieldPlan, 'cap' | 'path' | 'item'>): string;
168
+ /**
169
+ * What a feature does to its target (D663): `new` builds a capability on a new
170
+ * device; on an existing device it `add`s a capability the device lacks, or
171
+ * `replace`s named fields of one it has natively.
172
+ */
173
+ export declare const CompositionFeatureModeSchema: z.ZodEnum<{
174
+ new: "new";
175
+ replace: "replace";
176
+ add: "add";
177
+ }>;
178
+ export type CompositionFeatureMode = z.infer<typeof CompositionFeatureModeSchema>;
179
+ export declare const CompositionFeaturePlanSchema: z.ZodObject<{
180
+ featureIndex: z.ZodNumber;
181
+ cap: z.ZodString;
182
+ mode: z.ZodEnum<{
183
+ new: "new";
184
+ replace: "replace";
185
+ add: "add";
186
+ }>;
187
+ }, z.core.$strip>;
188
+ export type CompositionFeaturePlan = z.infer<typeof CompositionFeaturePlanSchema>;
132
189
  export declare const CompositionValidationSchema: z.ZodObject<{
133
190
  ok: z.ZodBoolean;
134
191
  problems: z.ZodArray<z.ZodObject<{
135
192
  code: z.ZodEnum<{
136
193
  "source-missing": "source-missing";
194
+ "unknown-field": "unknown-field";
195
+ "kind-mismatch": "kind-mismatch";
196
+ "not-composable": "not-composable";
137
197
  "reserved-variant": "reserved-variant";
138
198
  "unknown-capability": "unknown-capability";
139
- "not-composable": "not-composable";
140
199
  "wrong-device-type": "wrong-device-type";
141
200
  "has-commands": "has-commands";
142
- "unknown-field": "unknown-field";
143
201
  "nested-field": "nested-field";
144
202
  "missing-field": "missing-field";
145
- "kind-mismatch": "kind-mismatch";
146
203
  "may-be-null": "may-be-null";
147
204
  "source-unreadable": "source-unreadable";
148
205
  "source-capability-missing": "source-capability-missing";
@@ -150,6 +207,11 @@ export declare const CompositionValidationSchema: z.ZodObject<{
150
207
  "expression-invalid": "expression-invalid";
151
208
  cycle: "cycle";
152
209
  "duplicate-target": "duplicate-target";
210
+ "not-item-array": "not-item-array";
211
+ "item-field-reserved": "item-field-reserved";
212
+ "target-missing": "target-missing";
213
+ "target-unreadable": "target-unreadable";
214
+ "not-replaceable": "not-replaceable";
153
215
  }>;
154
216
  path: z.ZodString;
155
217
  message: z.ZodString;
@@ -157,6 +219,11 @@ export declare const CompositionValidationSchema: z.ZodObject<{
157
219
  fields: z.ZodArray<z.ZodObject<{
158
220
  cap: z.ZodString;
159
221
  path: z.ZodString;
222
+ item: z.ZodOptional<z.ZodObject<{
223
+ arrayPath: z.ZodString;
224
+ key: z.ZodString;
225
+ label: z.ZodString;
226
+ }, z.core.$strip>>;
160
227
  featureIndex: z.ZodNumber;
161
228
  kind: z.ZodEnum<{
162
229
  string: "string";
@@ -168,12 +235,15 @@ export declare const CompositionValidationSchema: z.ZodObject<{
168
235
  required: z.ZodBoolean;
169
236
  unavailable: z.ZodEnum<{
170
237
  null: "null";
238
+ unknown: "unknown";
171
239
  offline: "offline";
240
+ release: "release";
172
241
  }>;
173
242
  role: z.ZodEnum<{
174
243
  derived: "derived";
175
244
  clock: "clock";
176
245
  constant: "constant";
246
+ accumulator: "accumulator";
177
247
  }>;
178
248
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
179
249
  source: z.ZodObject<{
@@ -211,14 +281,36 @@ export declare const CompositionValidationSchema: z.ZodObject<{
211
281
  fieldPath: z.ZodString;
212
282
  }, z.core.$strip>>;
213
283
  }, z.core.$strip>>;
284
+ features: z.ZodArray<z.ZodObject<{
285
+ featureIndex: z.ZodNumber;
286
+ cap: z.ZodString;
287
+ mode: z.ZodEnum<{
288
+ new: "new";
289
+ replace: "replace";
290
+ add: "add";
291
+ }>;
292
+ }, z.core.$strip>>;
293
+ events: z.ZodArray<z.ZodObject<{
294
+ featureIndex: z.ZodNumber;
295
+ cap: z.ZodString;
296
+ eventName: z.ZodString;
297
+ category: z.ZodEnum<typeof import("../index.js").EventCategory>;
298
+ stateField: z.ZodString;
299
+ fieldKey: z.ZodString;
300
+ }, z.core.$strip>>;
214
301
  }, z.core.$strip>;
215
302
  export type CompositionValidation = z.infer<typeof CompositionValidationSchema>;
216
- /** Mirrors `CoreBlockStatus`, pinned by `core-blocks-source.spec.ts` (Task 11). */
303
+ /**
304
+ * Mirrors `CoreBlockStatus`, pinned by `core-blocks-source.spec.ts`. `degraded`:
305
+ * running, but a replaced field is released to the native provider while its
306
+ * source is unavailable (ruling S1b, D663) — the reason names each such field.
307
+ */
217
308
  export declare const CompositionRunStatusSchema: z.ZodEnum<{
218
309
  running: "running";
219
310
  failed: "failed";
220
311
  stopped: "stopped";
221
312
  starting: "starting";
313
+ degraded: "degraded";
222
314
  }>;
223
315
  export type CompositionRunStatus = z.infer<typeof CompositionRunStatusSchema>;
224
316
  export declare const CompositionFieldStateKindSchema: z.ZodEnum<{
@@ -230,6 +322,11 @@ export type CompositionFieldStateKind = z.infer<typeof CompositionFieldStateKind
230
322
  export declare const CompositionFieldStateSchema: z.ZodObject<{
231
323
  cap: z.ZodString;
232
324
  path: z.ZodString;
325
+ item: z.ZodOptional<z.ZodObject<{
326
+ arrayPath: z.ZodString;
327
+ key: z.ZodString;
328
+ label: z.ZodString;
329
+ }, z.core.$strip>>;
233
330
  state: z.ZodEnum<{
234
331
  unavailable: "unavailable";
235
332
  fresh: "fresh";
@@ -247,11 +344,17 @@ export declare const CompositionBlockStateSchema: z.ZodObject<{
247
344
  failed: "failed";
248
345
  stopped: "stopped";
249
346
  starting: "starting";
347
+ degraded: "degraded";
250
348
  }>;
251
349
  reason: z.ZodOptional<z.ZodString>;
252
350
  fields: z.ZodArray<z.ZodObject<{
253
351
  cap: z.ZodString;
254
352
  path: z.ZodString;
353
+ item: z.ZodOptional<z.ZodObject<{
354
+ arrayPath: z.ZodString;
355
+ key: z.ZodString;
356
+ label: z.ZodString;
357
+ }, z.core.$strip>>;
255
358
  state: z.ZodEnum<{
256
359
  unavailable: "unavailable";
257
360
  fresh: "fresh";
@@ -14,13 +14,19 @@
14
14
  * Later slices EXTEND these unions and do not reshape them. The variants a later
15
15
  * slice implements are already in the wire shape, and `validateComposition`
16
16
  * refuses them BY NAME until then:
17
- * target `existing` → slice 2 · feature `passthrough` → slice 3 ·
18
- * `commands` (`forward`) → slice 3 · source `code` → slice 4.
17
+ * feature `passthrough` → slice 3 · `commands` (`forward`) → slice 3 ·
18
+ * source `code` → slice 4. Target `existing` (customize a device) is slice 2 (D663).
19
19
  */
20
20
  import { z } from 'zod';
21
21
  import { DeviceRole, DeviceType } from '../device/device-type.js';
22
22
  /** The owner of every composed device: the `composer` builtin. */
23
23
  export declare const COMPOSER_ADDON_ID = "composer";
24
+ /**
25
+ * The stored name of a block that customizes an EXISTING device starts with this
26
+ * (`customizationBlockName`, `@camstack/types/node`). Never parsed to tell a
27
+ * customization apart: `composition.target.kind === 'existing'` says that (D663).
28
+ */
29
+ export declare const CUSTOMIZATION_BLOCK_NAME_PREFIX = "customize:";
24
30
  /** A composed device's stableId is this prefix plus the block id. */
25
31
  export declare const COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
26
32
  /** A device with more capabilities than this is two devices. */
@@ -153,9 +159,51 @@ export declare const CompositionCommandTargetSchema: z.ZodDiscriminatedUnion<[z.
153
159
  code: z.ZodString;
154
160
  }, z.core.$strip>], "kind">;
155
161
  export type CompositionCommandTarget = z.infer<typeof CompositionCommandTargetSchema>;
162
+ /** An item key inside an item-array cap (`consumables.items[<key>]`). */
163
+ export declare const COMPOSITION_ITEM_KEY_RE: RegExp;
164
+ export declare const MAX_COMPOSITION_ITEMS = 16;
165
+ /** The item-array path of every item-array cap that exists (`consumables.items`). */
166
+ export declare const COMPOSITION_ITEM_ARRAY_PATH = "items";
167
+ /**
168
+ * One item of an item-array cap (D663), addressed through the cap's
169
+ * `status.itemArray` descriptor. `fields` are paths INSIDE the item, nested
170
+ * allowed (`remaining.value`); the key and label come from the entry itself.
171
+ */
172
+ export declare const CompositionItemEntrySchema: z.ZodObject<{
173
+ label: z.ZodString;
174
+ fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
175
+ source: z.ZodObject<{
176
+ addonId: z.ZodString;
177
+ stableId: z.ZodString;
178
+ }, z.core.$strip>;
179
+ cap: z.ZodString;
180
+ fieldPath: z.ZodString;
181
+ kind: z.ZodLiteral<"from">;
182
+ }, z.core.$strip>, z.ZodObject<{
183
+ kind: z.ZodLiteral<"expression">;
184
+ expr: z.ZodString;
185
+ bindings: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
186
+ source: z.ZodObject<{
187
+ addonId: z.ZodString;
188
+ stableId: z.ZodString;
189
+ }, z.core.$strip>;
190
+ cap: z.ZodString;
191
+ fieldPath: z.ZodString;
192
+ kind: z.ZodLiteral<"from">;
193
+ }, z.core.$strip>, z.ZodObject<{
194
+ kind: z.ZodLiteral<"literal">;
195
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
196
+ }, z.core.$strip>], "kind">>;
197
+ }, z.core.$strip>, z.ZodObject<{
198
+ kind: z.ZodLiteral<"code">;
199
+ code: z.ZodString;
200
+ }, z.core.$strip>], "kind">>;
201
+ }, z.core.$strip>;
202
+ export type CompositionItemEntry = z.infer<typeof CompositionItemEntrySchema>;
156
203
  export declare const CompositionFieldsFeatureSchema: z.ZodObject<{
157
204
  kind: z.ZodLiteral<"fields">;
158
205
  cap: z.ZodString;
206
+ enabled: z.ZodOptional<z.ZodBoolean>;
159
207
  fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
160
208
  source: z.ZodObject<{
161
209
  addonId: z.ZodString;
@@ -183,6 +231,36 @@ export declare const CompositionFieldsFeatureSchema: z.ZodObject<{
183
231
  kind: z.ZodLiteral<"code">;
184
232
  code: z.ZodString;
185
233
  }, z.core.$strip>], "kind">>;
234
+ items: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
235
+ label: z.ZodString;
236
+ fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
237
+ source: z.ZodObject<{
238
+ addonId: z.ZodString;
239
+ stableId: z.ZodString;
240
+ }, z.core.$strip>;
241
+ cap: z.ZodString;
242
+ fieldPath: z.ZodString;
243
+ kind: z.ZodLiteral<"from">;
244
+ }, z.core.$strip>, z.ZodObject<{
245
+ kind: z.ZodLiteral<"expression">;
246
+ expr: z.ZodString;
247
+ bindings: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
248
+ source: z.ZodObject<{
249
+ addonId: z.ZodString;
250
+ stableId: z.ZodString;
251
+ }, z.core.$strip>;
252
+ cap: z.ZodString;
253
+ fieldPath: z.ZodString;
254
+ kind: z.ZodLiteral<"from">;
255
+ }, z.core.$strip>, z.ZodObject<{
256
+ kind: z.ZodLiteral<"literal">;
257
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
258
+ }, z.core.$strip>], "kind">>;
259
+ }, z.core.$strip>, z.ZodObject<{
260
+ kind: z.ZodLiteral<"code">;
261
+ code: z.ZodString;
262
+ }, z.core.$strip>], "kind">>;
263
+ }, z.core.$strip>>>;
186
264
  commands: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
187
265
  kind: z.ZodLiteral<"forward">;
188
266
  source: z.ZodObject<{
@@ -201,6 +279,7 @@ export type CompositionFieldsFeature = z.infer<typeof CompositionFieldsFeatureSc
201
279
  export declare const CompositionPassthroughFeatureSchema: z.ZodObject<{
202
280
  kind: z.ZodLiteral<"passthrough">;
203
281
  cap: z.ZodString;
282
+ enabled: z.ZodOptional<z.ZodBoolean>;
204
283
  source: z.ZodObject<{
205
284
  addonId: z.ZodString;
206
285
  stableId: z.ZodString;
@@ -210,6 +289,7 @@ export type CompositionPassthroughFeature = z.infer<typeof CompositionPassthroug
210
289
  export declare const CompositionFeatureSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
211
290
  kind: z.ZodLiteral<"fields">;
212
291
  cap: z.ZodString;
292
+ enabled: z.ZodOptional<z.ZodBoolean>;
213
293
  fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
214
294
  source: z.ZodObject<{
215
295
  addonId: z.ZodString;
@@ -237,6 +317,36 @@ export declare const CompositionFeatureSchema: z.ZodDiscriminatedUnion<[z.ZodObj
237
317
  kind: z.ZodLiteral<"code">;
238
318
  code: z.ZodString;
239
319
  }, z.core.$strip>], "kind">>;
320
+ items: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
321
+ label: z.ZodString;
322
+ fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
323
+ source: z.ZodObject<{
324
+ addonId: z.ZodString;
325
+ stableId: z.ZodString;
326
+ }, z.core.$strip>;
327
+ cap: z.ZodString;
328
+ fieldPath: z.ZodString;
329
+ kind: z.ZodLiteral<"from">;
330
+ }, z.core.$strip>, z.ZodObject<{
331
+ kind: z.ZodLiteral<"expression">;
332
+ expr: z.ZodString;
333
+ bindings: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
334
+ source: z.ZodObject<{
335
+ addonId: z.ZodString;
336
+ stableId: z.ZodString;
337
+ }, z.core.$strip>;
338
+ cap: z.ZodString;
339
+ fieldPath: z.ZodString;
340
+ kind: z.ZodLiteral<"from">;
341
+ }, z.core.$strip>, z.ZodObject<{
342
+ kind: z.ZodLiteral<"literal">;
343
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
344
+ }, z.core.$strip>], "kind">>;
345
+ }, z.core.$strip>, z.ZodObject<{
346
+ kind: z.ZodLiteral<"code">;
347
+ code: z.ZodString;
348
+ }, z.core.$strip>], "kind">>;
349
+ }, z.core.$strip>>>;
240
350
  commands: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
241
351
  kind: z.ZodLiteral<"forward">;
242
352
  source: z.ZodObject<{
@@ -252,12 +362,15 @@ export declare const CompositionFeatureSchema: z.ZodDiscriminatedUnion<[z.ZodObj
252
362
  }, z.core.$strip>, z.ZodObject<{
253
363
  kind: z.ZodLiteral<"passthrough">;
254
364
  cap: z.ZodString;
365
+ enabled: z.ZodOptional<z.ZodBoolean>;
255
366
  source: z.ZodObject<{
256
367
  addonId: z.ZodString;
257
368
  stableId: z.ZodString;
258
369
  }, z.core.$strip>;
259
370
  }, z.core.$strip>], "kind">;
260
371
  export type CompositionFeature = z.infer<typeof CompositionFeatureSchema>;
372
+ /** Only an explicit `false` disables a feature; omitted preserves the existing wire default. */
373
+ export declare function compositionFeatureEnabled(feature: CompositionFeature): boolean;
261
374
  /**
262
375
  * A NEW device. It has no `name` of its own: the block's name IS the device's
263
376
  * name (2026-08-08). A second copy here would be a second writer of one string (D62).
@@ -268,7 +381,7 @@ export declare const CompositionNewTargetSchema: z.ZodObject<{
268
381
  role: z.ZodOptional<z.ZodEnum<typeof DeviceRole>>;
269
382
  }, z.core.$strip>;
270
383
  export type CompositionNewTarget = z.infer<typeof CompositionNewTargetSchema>;
271
- /** RESERVED for slice 2: customize an existing device. */
384
+ /** Customize an EXISTING device: each feature adds a capability or replaces fields of a native one (D663). */
272
385
  export declare const CompositionExistingTargetSchema: z.ZodObject<{
273
386
  kind: z.ZodLiteral<"existing">;
274
387
  device: z.ZodObject<{
@@ -304,6 +417,7 @@ export declare const CompositionSchema: z.ZodObject<{
304
417
  features: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
305
418
  kind: z.ZodLiteral<"fields">;
306
419
  cap: z.ZodString;
420
+ enabled: z.ZodOptional<z.ZodBoolean>;
307
421
  fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
308
422
  source: z.ZodObject<{
309
423
  addonId: z.ZodString;
@@ -331,6 +445,36 @@ export declare const CompositionSchema: z.ZodObject<{
331
445
  kind: z.ZodLiteral<"code">;
332
446
  code: z.ZodString;
333
447
  }, z.core.$strip>], "kind">>;
448
+ items: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
449
+ label: z.ZodString;
450
+ fields: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
451
+ source: z.ZodObject<{
452
+ addonId: z.ZodString;
453
+ stableId: z.ZodString;
454
+ }, z.core.$strip>;
455
+ cap: z.ZodString;
456
+ fieldPath: z.ZodString;
457
+ kind: z.ZodLiteral<"from">;
458
+ }, z.core.$strip>, z.ZodObject<{
459
+ kind: z.ZodLiteral<"expression">;
460
+ expr: z.ZodString;
461
+ bindings: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
462
+ source: z.ZodObject<{
463
+ addonId: z.ZodString;
464
+ stableId: z.ZodString;
465
+ }, z.core.$strip>;
466
+ cap: z.ZodString;
467
+ fieldPath: z.ZodString;
468
+ kind: z.ZodLiteral<"from">;
469
+ }, z.core.$strip>, z.ZodObject<{
470
+ kind: z.ZodLiteral<"literal">;
471
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
472
+ }, z.core.$strip>], "kind">>;
473
+ }, z.core.$strip>, z.ZodObject<{
474
+ kind: z.ZodLiteral<"code">;
475
+ code: z.ZodString;
476
+ }, z.core.$strip>], "kind">>;
477
+ }, z.core.$strip>>>;
334
478
  commands: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
335
479
  kind: z.ZodLiteral<"forward">;
336
480
  source: z.ZodObject<{
@@ -346,6 +490,7 @@ export declare const CompositionSchema: z.ZodObject<{
346
490
  }, z.core.$strip>, z.ZodObject<{
347
491
  kind: z.ZodLiteral<"passthrough">;
348
492
  cap: z.ZodString;
493
+ enabled: z.ZodOptional<z.ZodBoolean>;
349
494
  source: z.ZodObject<{
350
495
  addonId: z.ZodString;
351
496
  stableId: z.ZodString;
@@ -360,3 +505,17 @@ export declare function composedDeviceStableId(blockId: string): string;
360
505
  export declare function composedDeviceRef(blockId: string): CompositionSourceRef;
361
506
  /** Every device field a source reads: `from` is one read, an expression is its `from` bindings. */
362
507
  export declare function fieldReads(source: CompositionFieldSource): readonly CompositionFieldRead[];
508
+ /** The ONE spelling of an item leaf as a field path: `items[desiccant].remaining.value`. */
509
+ export declare function compositionItemFieldPath(arrayPath: string, key: string, path: string): string;
510
+ export interface CompositionFeatureFieldEntry {
511
+ readonly fieldPath: string;
512
+ readonly source: CompositionFieldSource;
513
+ }
514
+ /**
515
+ * Every written field of a feature, item leaves under their bracketed path.
516
+ * `arrayPath` is `'items'` for every item-array cap that exists
517
+ * (`consumables.cap.ts`); the graph has no cap lookup, so the default stands
518
+ * and `planItems` asserts it agrees with the cap's descriptor.
519
+ */
520
+ export declare function featureFieldEntries(feature: CompositionFieldsFeature, arrayPath?: string): readonly CompositionFeatureFieldEntry[];
521
+ export declare function featureSources(feature: CompositionFieldsFeature): readonly CompositionFieldSource[];
@@ -0,0 +1,6 @@
1
+ import { type CompositionSourceRef } from './composition.js';
2
+ /**
3
+ * Derived by the SERVER on save, never sent by the client; never shown as the
4
+ * device's name. Unique per target: the plain ref when it fits, else a hash.
5
+ */
6
+ export declare function customizationBlockName(ref: CompositionSourceRef): string;
@@ -15,6 +15,14 @@
15
15
  * - an expression that fails on a value makes the field unavailable for that
16
16
  * value, and NOT fatal: the next value may compute.
17
17
  *
18
+ * `confirmed` (D663, D49): whether a NON-fatal unavailability is an ANSWER — a
19
+ * cap the provider unregistered and a re-read agreed, a field the source
20
+ * reported without, an expression that failed on a value — or only the
21
+ * absence of one (a failed read, a first or empty read, a source not tracked
22
+ * yet). Only a confirmed unavailability may hand a `release`-mode field back
23
+ * to the native provider; an unconfirmed one holds it on its last value.
24
+ * Absent means NOT confirmed. Fatal is always confirmed.
25
+ *
18
26
  * When an expression has more than one unavailable binding, a FATAL one always
19
27
  * wins the outcome, regardless of position: every binding is scanned before
20
28
  * the field is judged, so an earlier non-fatal binding (e.g. a cap that is
@@ -22,6 +30,7 @@
22
30
  * source) behind an early return.
23
31
  */
24
32
  import type { ExpressionValue } from '../expression/ast.js';
33
+ import { type StatefulExpressionMemory } from '../expression/expression-source.js';
25
34
  import { type CompositionFieldRead, type CompositionFieldSource } from './composition.js';
26
35
  export interface SourceFreshReading {
27
36
  readonly state: 'fresh';
@@ -37,6 +46,8 @@ export interface SourceUnavailableReading {
37
46
  readonly reason: string;
38
47
  /** True when the source is GONE: device or cap missing, two reads agreed. */
39
48
  readonly fatal: boolean;
49
+ /** The unavailability is an answer, not a missing one (see the header). Absent = not confirmed. */
50
+ readonly confirmed?: boolean;
40
51
  }
41
52
  export type SourceReading = SourceFreshReading | SourceStaleReading | SourceUnavailableReading;
42
53
  export type SourceReader = (read: CompositionFieldRead) => SourceReading;
@@ -53,11 +64,20 @@ export interface FieldUnavailableOutcome {
53
64
  readonly value: null;
54
65
  readonly reason: string;
55
66
  readonly fatal: boolean;
67
+ /** Fatal, or a non-fatal unavailability that is an answer (see the header). Absent = not confirmed. */
68
+ readonly confirmed?: boolean;
56
69
  }
57
70
  export type FieldOutcome = FieldValueOutcome | FieldUnavailableOutcome;
58
71
  export interface EvaluateCompositionFieldInput {
59
72
  readonly source: CompositionFieldSource;
60
73
  readonly read: SourceReader;
61
74
  readonly now: number;
75
+ readonly stateful?: {
76
+ readonly currentOutput: unknown;
77
+ readonly expressionMemory: StatefulExpressionMemory;
78
+ readonly startedAtMs: number;
79
+ /** Scope structural AST paths to their owning output field. */
80
+ readonly callPathPrefix?: string;
81
+ };
62
82
  }
63
83
  export declare function evaluateCompositionField(input: EvaluateCompositionFieldInput): FieldOutcome;
@@ -8,3 +8,36 @@ export interface RoomExampleInput {
8
8
  readonly occupancyWindowMs: number;
9
9
  }
10
10
  export declare function roomCompositionExample(input: RoomExampleInput): Composition;
11
+ /**
12
+ * The slice-2 worked customization (D663): the PetKit "Fresh Element Infinity"
13
+ * feeder as Home Assistant imports it — ONE `Container` with a child per entity
14
+ * (`<container stableId>-<entityId>`), and NO native battery (its
15
+ * `binary_sensor.*_battery` is `battery_charging`, which `isBatteryEntity` does
16
+ * not match). The customization ADDS `consumables` (the desiccant) and
17
+ * `battery`. It is the Task 14 acceptance case and the template slice 5's
18
+ * presets start from.
19
+ *
20
+ * Every read names what the HA provider REALLY registers (read 2026-09-28):
21
+ * the desiccant sensor has a unit (`d`) but no device_class, so HA hosts it as
22
+ * an `enum-sensor` whose `value` is the raw STRING state — `number(d)` reads it,
23
+ * and anything that is not a number is `null`, never 0 (D393). The battery
24
+ * status sensor is an `enum-sensor` too (`unavailable` keeps its cold `''`, so
25
+ * `percentage` is `null`). `charging` maps `battery_charging` off to
26
+ * `'unknown'`, never `'none'`: off does not prove "on battery alone" (the
27
+ * operator confirms the real semantics live).
28
+ */
29
+ export declare const FEEDER_EXAMPLE_HA_DEVICE_ID = "8dec3b512fda40cbb8cd121c7a99f890";
30
+ export declare const FEEDER_EXAMPLE_ADDON_ID = "provider-homeassistant";
31
+ /** The container and the three children the feeder customization reads, under one HA broker. */
32
+ export interface FeederExampleSources {
33
+ readonly feeder: CompositionSourceRef;
34
+ /** `sensor.freshelement_3_desiccant_days_remaining` — `enum-sensor.value`, a numeric string. */
35
+ readonly desiccantDays: CompositionSourceRef;
36
+ /** `sensor.freshelement_3_battery_status` — `enum-sensor.value`. */
37
+ readonly batteryStatus: CompositionSourceRef;
38
+ /** `binary_sensor.freshelement_3_battery` (`battery_charging`) — `binary.on`. */
39
+ readonly batteryCharging: CompositionSourceRef;
40
+ }
41
+ /** The HA container's stableId (`ha-discovery.ts`) and a child's (`<container>-<entityId>`). */
42
+ export declare function feederExampleSources(brokerId: string): FeederExampleSources;
43
+ export declare function feederCustomizationExample(sources: FeederExampleSources): Composition;
@@ -33,4 +33,5 @@ export interface InferenceFailure {
33
33
  }
34
34
  export type InferExpressionKindsResult = InferredKinds | InferenceFailure;
35
35
  export declare function kindOfValue(value: ExpressionValue): ExpressionValueKind;
36
+ export declare function expressionContainsBuiltinCall(expr: string, callee: string): boolean;
36
37
  export declare function inferExpressionKinds(input: InferExpressionKindsInput): InferExpressionKindsResult;