@camstack/addon-model-studio 1.1.308 → 1.1.310

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 (20) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{MotionZonesSettings-DkgjOPCB.mjs → MotionZonesSettings-DmT3_5uL.mjs} +2 -2
  3. package/dist/{PrivacyMaskSettings-fESQpFIS.mjs → PrivacyMaskSettings-DUvJko35.mjs} +4 -4
  4. package/dist/{SceneMonitorEditor-C9B7EixP.mjs → SceneMonitorEditor-BVMxs7LB.mjs} +3 -3
  5. package/dist/_stub.js +1700 -1728
  6. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-DHIXnmpZ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-BUDlZg-M.mjs} +3 -3
  7. package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DhQKnJ3x.mjs +26 -0
  8. package/dist/addon-model-studio.css +1 -1
  9. package/dist/{hostInit-sbd7BJLf.mjs → hostInit-DlOqhXnD.mjs} +2 -2
  10. package/dist/model-studio.addon.js +675 -75
  11. package/dist/model-studio.addon.mjs +675 -75
  12. package/dist/{player-overlays-SAR77Y-f.mjs → player-overlays-UNmRn2Lm.mjs} +1 -1
  13. package/dist/remoteEntry.js +1 -1
  14. package/dist/{responsive-DhsW4w_p.mjs → responsive-DpFvXEzP.mjs} +1 -1
  15. package/dist/{scene-monitor-copy-BYVAve5e.mjs → scene-monitor-copy-55pWpNVH.mjs} +1 -1
  16. package/dist/{square-Dy3-P6UW.mjs → square-C3qrCBUt.mjs} +1 -1
  17. package/dist/{trash-2-DScdmxQC.mjs → trash-2-g3e9eqho.mjs} +1 -1
  18. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-CqZcfvB1.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-B1TWKKP3.mjs} +1 -1
  19. package/package.json +1 -1
  20. package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BQQ1gj_P.mjs +0 -26
@@ -394,7 +394,7 @@ function buildPluginCatalogRegistryDescriptor(entry) {
394
394
  };
395
395
  }
396
396
  //#endregion
397
- //#region ../types/dist/event-category-CT-hz5Rb.mjs
397
+ //#region ../types/dist/event-category-hdMR7CTW.mjs
398
398
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
399
399
  EventCategory["SystemBoot"] = "system.boot";
400
400
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -1159,6 +1159,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
1159
1159
  */
1160
1160
  EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
1161
1161
  /**
1162
+ * An action run started or ended. Emitted by the `actions` surface.
1163
+ * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
1164
+ */
1165
+ EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
1166
+ /**
1162
1167
  * Progress update from a running model conversion job.
1163
1168
  * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
1164
1169
  * Emitted by `addon-model-studio` on the converting node.
@@ -5837,7 +5842,7 @@ var ZodIssueCode = {
5837
5842
  var ZodFirstPartyTypeKind;
5838
5843
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5839
5844
  //#endregion
5840
- //#region ../types/dist/sleep--jXS9hWo.mjs
5845
+ //#region ../types/dist/sleep-BHjNez61.mjs
5841
5846
  /**
5842
5847
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5843
5848
  * window to float samples (D455).
@@ -8967,6 +8972,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
8967
8972
  /** Every capability name, so addon code can check a name without the schema graph. */
8968
8973
  var CAP_NAMES = Object.freeze([
8969
8974
  "accessories",
8975
+ "action-source",
8976
+ "actions",
8970
8977
  "addon-pages",
8971
8978
  "addon-pages-source",
8972
8979
  "addon-routes",
@@ -10269,6 +10276,18 @@ Object.freeze({
10269
10276
  "path": "foodLevel",
10270
10277
  "valueType": "number"
10271
10278
  },
10279
+ {
10280
+ "path": "bowlFood",
10281
+ "valueType": "number"
10282
+ },
10283
+ {
10284
+ "path": "eating",
10285
+ "valueType": "boolean"
10286
+ },
10287
+ {
10288
+ "path": "supportsMarkRefilled",
10289
+ "valueType": "boolean"
10290
+ },
10272
10291
  {
10273
10292
  "path": "food1",
10274
10293
  "valueType": "number"
@@ -15954,7 +15973,23 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15954
15973
  kind: literal("schedule"),
15955
15974
  cron: string().min(1).max(120)
15956
15975
  }),
15957
- object({ kind: literal("manual") })
15976
+ object({ kind: literal("manual") }),
15977
+ object({
15978
+ kind: literal("detection"),
15979
+ /** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
15980
+ * matches every raw class that maps to it; any other name matches
15981
+ * exactly. */
15982
+ classes: array(string().min(1)).min(1),
15983
+ deviceIds: array(number().int().nonnegative()).min(1),
15984
+ /** The track must have visited at least one of these zones. */
15985
+ zones: array(string().min(1)).min(1).optional(),
15986
+ /** Best-so-far confidence the track must reach. */
15987
+ minScore: number().min(0).max(1).optional()
15988
+ }),
15989
+ object({
15990
+ kind: literal("interval"),
15991
+ minutes: number().int().min(1).max(1440)
15992
+ })
15958
15993
  ]);
15959
15994
  /**
15960
15995
  * One action step.
@@ -15974,28 +16009,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15974
16009
  * is called. The runner still receives a number and is untouched; the
15975
16010
  * resolution is the recipe's job, not the runner's.
15976
16011
  */
16012
+ var AutomationWaitStepSchema = object({
16013
+ kind: literal("wait"),
16014
+ seconds: number().min(0).max(300)
16015
+ });
16016
+ var AutomationCapStepSchema = object({
16017
+ kind: literal("cap"),
16018
+ /**
16019
+ * One device, several same-family devices (locks / climate family / …),
16020
+ * or `{ $var }` for the device that triggered the run. An array is
16021
+ * fan-out at codegen — each id gets the same cap.method call.
16022
+ */
16023
+ deviceId: union([
16024
+ number().int(),
16025
+ array(number().int()).min(1),
16026
+ object({ $var: string().min(1) })
16027
+ ]),
16028
+ cap: string().min(1),
16029
+ method: string().min(1),
16030
+ /** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
16031
+ * SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
16032
+ * the expression leaf. */
16033
+ args: record(string(), unknown()).optional()
16034
+ });
16035
+ /**
16036
+ * The steps an internal Action may contain: cap and wait, and nothing that can
16037
+ * call back into an Action — so an Action can never reach itself (no cycles).
16038
+ */
16039
+ var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
15977
16040
  var AutomationActionSchema = discriminatedUnion("kind", [
16041
+ AutomationWaitStepSchema,
16042
+ AutomationCapStepSchema,
15978
16043
  object({
15979
- kind: literal("wait"),
15980
- seconds: number().min(0).max(300)
15981
- }),
15982
- object({
15983
- kind: literal("cap"),
15984
- /**
15985
- * One device, several same-family devices (locks / climate family / …),
15986
- * or `{ $var }` for the device that triggered the run. An array is
15987
- * fan-out at codegen — each id gets the same cap.method call.
15988
- */
15989
- deviceId: union([
15990
- number().int(),
15991
- array(number().int()).min(1),
15992
- object({ $var: string().min(1) })
15993
- ]),
15994
- cap: string().min(1),
15995
- method: string().min(1),
15996
- /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
15997
- * evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
15998
- args: record(string(), unknown()).optional()
16044
+ kind: literal("action"),
16045
+ /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
16046
+ actionId: string().min(1),
16047
+ /** Values for the action's declared variables; the others take their default. */
16048
+ variables: record(string(), union([
16049
+ string(),
16050
+ number(),
16051
+ boolean()
16052
+ ])).optional()
15999
16053
  }),
16000
16054
  object({
16001
16055
  kind: literal("code"),
@@ -16004,10 +16058,356 @@ var AutomationActionSchema = discriminatedUnion("kind", [
16004
16058
  code: string().min(1).max(2e4)
16005
16059
  })
16006
16060
  ]);
16061
+ /**
16062
+ * How a trigger that arrives while the automation is busy (or cooling down) is
16063
+ * handled. One of the automation's execution modes, never a property of its
16064
+ * actions. Absent means `single`.
16065
+ *
16066
+ * - `single` — drop the trigger while a run is in progress (traced + logged).
16067
+ * - `restart` — abort the run in progress (at its next step boundary), start fresh.
16068
+ * - `queued` — queue up to `max` triggers, drop the rest (traced).
16069
+ * - `parallel` — up to `max` runs at once, drop the rest (traced).
16070
+ * - `cooldown` — `single`, and no new run until `minutes` after the last run
16071
+ * STARTED; persisted across a restart. A manual trigger bypasses only this
16072
+ * wait, never the single/queued limits.
16073
+ */
16074
+ var AutomationRunModeSchema = discriminatedUnion("mode", [
16075
+ object({ mode: literal("single") }),
16076
+ object({ mode: literal("restart") }),
16077
+ object({
16078
+ mode: literal("queued"),
16079
+ max: number().int().min(1).max(10)
16080
+ }),
16081
+ object({
16082
+ mode: literal("parallel"),
16083
+ max: number().int().min(1).max(10)
16084
+ }),
16085
+ object({
16086
+ mode: literal("cooldown"),
16087
+ minutes: number().int().min(1).max(1440)
16088
+ })
16089
+ ]);
16007
16090
  var AutomationRecipeSchema = object({
16008
16091
  triggers: array(AutomationTriggerSchema),
16009
16092
  conditions: AutomationConditionSchema.optional(),
16010
- actions: array(AutomationActionSchema)
16093
+ actions: array(AutomationActionSchema),
16094
+ runMode: AutomationRunModeSchema.optional(),
16095
+ /** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
16096
+ keepTraces: number().int().min(1).max(100).optional()
16097
+ });
16098
+ new Set([
16099
+ {
16100
+ id: "person",
16101
+ name: "Person"
16102
+ },
16103
+ {
16104
+ id: "vehicle",
16105
+ name: "Vehicle"
16106
+ },
16107
+ {
16108
+ id: "animal",
16109
+ name: "Animal"
16110
+ },
16111
+ {
16112
+ id: "package",
16113
+ name: "Package"
16114
+ }
16115
+ ].map((l) => l.id));
16116
+ var COCO_TO_MACRO = {
16117
+ mapping: {
16118
+ person: "person",
16119
+ bicycle: "vehicle",
16120
+ car: "vehicle",
16121
+ motorcycle: "vehicle",
16122
+ airplane: "vehicle",
16123
+ bus: "vehicle",
16124
+ train: "vehicle",
16125
+ truck: "vehicle",
16126
+ boat: "vehicle",
16127
+ bird: "animal",
16128
+ cat: "animal",
16129
+ dog: "animal",
16130
+ horse: "animal",
16131
+ sheep: "animal",
16132
+ cow: "animal",
16133
+ elephant: "animal",
16134
+ bear: "animal",
16135
+ zebra: "animal",
16136
+ giraffe: "animal",
16137
+ suitcase: "package",
16138
+ backpack: "package",
16139
+ handbag: "package"
16140
+ },
16141
+ preserveOriginal: false
16142
+ };
16143
+ new Set(Object.values(COCO_TO_MACRO.mapping));
16144
+ /**
16145
+ * Run traces — what an automation (or, later, an Action run) DID, node by node,
16146
+ * so the editor can paint every block green or red with its reason.
16147
+ *
16148
+ * A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
16149
+ * every condition node (containers and leaves, including the ones a
16150
+ * short-circuit never reached), the run-mode verdict and every action step —
16151
+ * each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
16152
+ * for an Action run). Skipped
16153
+ * evaluations are traced too, and identical consecutive skips collapse into a
16154
+ * repeat count so a trigger that fails every 5 minutes cannot flush real runs.
16155
+ *
16156
+ * {@link AutomationStepTraceSchema} is deliberately free of automation
16157
+ * vocabulary so an Action run records the same step shape.
16158
+ */
16159
+ /** A value a trace may show: JSON primitives and short lists, nothing deeper. */
16160
+ var TraceValueSchema = union([
16161
+ string(),
16162
+ number(),
16163
+ boolean(),
16164
+ _null(),
16165
+ array(union([string(), number()]))
16166
+ ]);
16167
+ var AutomationRunOutcomeSchema = _enum([
16168
+ "ran",
16169
+ "skipped-trigger",
16170
+ "skipped-conditions",
16171
+ "skipped-cooldown",
16172
+ "skipped-overlap",
16173
+ "failed",
16174
+ "aborted"
16175
+ ]);
16176
+ /** `not-evaluated` = a short-circuit never reached the node. */
16177
+ var TraceNodeOutcomeSchema = _enum([
16178
+ "pass",
16179
+ "fail",
16180
+ "not-evaluated"
16181
+ ]);
16182
+ var AutomationTriggerTraceSchema = object({
16183
+ kind: string().min(1),
16184
+ outcome: _enum(["pass", "fail"]),
16185
+ /** Why an event was rejected ("class person not in [dog]") or what fired. */
16186
+ reason: string(),
16187
+ /** deviceId, className, trackId, score … — only what the trigger exposes. */
16188
+ vars: record(string(), TraceValueSchema)
16189
+ });
16190
+ var AutomationConditionTraceNodeSchema = object({
16191
+ /** `conditions` for the root, `conditions.<i>` for its i-th child, … */
16192
+ path: string().min(1),
16193
+ kind: _enum([
16194
+ "all",
16195
+ "any",
16196
+ "not",
16197
+ "condition",
16198
+ "expression"
16199
+ ]),
16200
+ outcome: TraceNodeOutcomeSchema,
16201
+ reason: string(),
16202
+ deviceId: number().int().optional(),
16203
+ cap: string().optional(),
16204
+ fieldPath: string().optional(),
16205
+ operator: string().optional(),
16206
+ expected: TraceValueSchema.optional(),
16207
+ /** What the mirror held; `null` when it held nothing (unknown). */
16208
+ observed: TraceValueSchema.optional()
16209
+ });
16210
+ var AutomationRunVerdictSchema = object({
16211
+ mode: AutomationRunModeSchema,
16212
+ decision: _enum([
16213
+ "run",
16214
+ "queued",
16215
+ "restart",
16216
+ "drop",
16217
+ "cooldown",
16218
+ "bypass"
16219
+ ]),
16220
+ reason: string()
16221
+ });
16222
+ /** One executed (or not-run) step — shared by automations and Action runs. */
16223
+ var AutomationStepTraceSchema = object({
16224
+ /** `actions.<i>` */
16225
+ path: string().min(1),
16226
+ kind: string().min(1),
16227
+ cap: string().optional(),
16228
+ method: string().optional(),
16229
+ deviceId: number().int().optional(),
16230
+ startedAt: number().optional(),
16231
+ endedAt: number().optional(),
16232
+ outcome: _enum([
16233
+ "ok",
16234
+ "error",
16235
+ "not-run"
16236
+ ]),
16237
+ message: string().optional()
16238
+ });
16239
+ var AutomationRunTraceSchema = object({
16240
+ runId: string().min(1),
16241
+ startedAt: number(),
16242
+ endedAt: number(),
16243
+ trigger: AutomationTriggerTraceSchema,
16244
+ conditions: array(AutomationConditionTraceNodeSchema),
16245
+ verdict: AutomationRunVerdictSchema.optional(),
16246
+ steps: array(AutomationStepTraceSchema),
16247
+ outcome: AutomationRunOutcomeSchema,
16248
+ /** How many identical consecutive skips this trace stands for (>= 1). */
16249
+ repeat: number().int().min(1),
16250
+ /** When the latest of those repeats happened. */
16251
+ lastAt: number()
16252
+ });
16253
+ /**
16254
+ * What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
16255
+ * `action:<actionId>`): the cooldown stamp and the trace ring.
16256
+ */
16257
+ var AutomationStateDocSchema = object({
16258
+ version: literal(1),
16259
+ lastRunStartedAt: number().nullable(),
16260
+ traces: array(AutomationRunTraceSchema)
16261
+ });
16262
+ /**
16263
+ * Actions — named, runnable things an operator (or an automation) can start,
16264
+ * declared as LIST ENTRIES, never as devices.
16265
+ *
16266
+ * An entry is either **internal** (a short list of cap/wait steps kept in the
16267
+ * hub's `actions` record kind) or declared by an addon through the
16268
+ * `action-source` collection (a Home Assistant script, a scene …). The one
16269
+ * surface the UI and automations talk to is the `actions` cap; it keeps no
16270
+ * catalog of its own (D3) — every `list` asks the providers live.
16271
+ *
16272
+ * This file is the data half: the entry schema, the variables an entry may
16273
+ * declare, and the pure resolution of the values a run was given. It holds no
16274
+ * runtime.
16275
+ */
16276
+ /** What a variable's value is. `select` takes one of `options`. */
16277
+ var ActionVariableTypeSchema = _enum([
16278
+ "string",
16279
+ "number",
16280
+ "boolean",
16281
+ "select"
16282
+ ]);
16283
+ var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
16284
+ var ActionVariableValueSchema = union([
16285
+ string(),
16286
+ number(),
16287
+ boolean()
16288
+ ]);
16289
+ /**
16290
+ * One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
16291
+ * value) or `{{vars.name}}` (inside a string) in their args.
16292
+ */
16293
+ var ActionVariableSchema = object({
16294
+ name: string().regex(ACTION_VARIABLE_NAME_RE),
16295
+ label: string().min(1).max(120).optional(),
16296
+ type: ActionVariableTypeSchema,
16297
+ required: boolean().optional(),
16298
+ default: ActionVariableValueSchema.optional(),
16299
+ /** The allowed values of a `select`. */
16300
+ options: array(string().min(1)).min(1).optional()
16301
+ }).superRefine((v, ctx) => {
16302
+ if (v.type === "select" && v.options === void 0) ctx.addIssue({
16303
+ code: "custom",
16304
+ message: "a select variable needs options",
16305
+ path: ["options"]
16306
+ });
16307
+ if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
16308
+ code: "custom",
16309
+ message: variableValueError(v, v.default) ?? "invalid default",
16310
+ path: ["default"]
16311
+ });
16312
+ });
16313
+ /** Why `value` is not a legal value for the variable, or null when it is. */
16314
+ function variableValueError(variable, value) {
16315
+ switch (variable.type) {
16316
+ case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
16317
+ case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
16318
+ case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
16319
+ case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
16320
+ }
16321
+ }
16322
+ var ActionSourceKindSchema = _enum(["internal", "addon"]);
16323
+ function isInternalActionId(actionId) {
16324
+ return actionId.startsWith("internal:") && actionId.length > 9;
16325
+ }
16326
+ /** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
16327
+ function addonIdOfActionId(actionId) {
16328
+ if (isInternalActionId(actionId)) return null;
16329
+ const at = actionId.indexOf(":");
16330
+ return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
16331
+ }
16332
+ var ActionStatusSchema = object({
16333
+ isRunning: boolean(),
16334
+ /** Ms epoch the latest run STARTED; null when it never ran. */
16335
+ lastRunAt: number().nullable(),
16336
+ /** The latest run's failure; null on success or when it never ran. */
16337
+ lastError: string().nullable()
16338
+ });
16339
+ var ActionEntrySchema = object({
16340
+ /** `internal:<uuid>` or `<addonId>:<localId>`. */
16341
+ id: string().min(3),
16342
+ name: string().min(1).max(120),
16343
+ /** The addon that declared it; `core-blocks` for an internal one. */
16344
+ addonId: string().min(1),
16345
+ source: ActionSourceKindSchema,
16346
+ /** An addon-declared entry is edited where it was declared. */
16347
+ readOnly: boolean(),
16348
+ /** Internal only: cap and wait steps. No action-in-action, so no cycles. */
16349
+ steps: array(ActionStepSchema).min(1).max(50).optional(),
16350
+ variables: array(ActionVariableSchema).max(20).optional(),
16351
+ status: ActionStatusSchema
16352
+ }).superRefine((entry, ctx) => {
16353
+ if (entry.source === "internal") {
16354
+ if (!isInternalActionId(entry.id)) ctx.addIssue({
16355
+ code: "custom",
16356
+ message: "an internal action id is internal:<uuid>",
16357
+ path: ["id"]
16358
+ });
16359
+ return;
16360
+ }
16361
+ if (entry.steps !== void 0) ctx.addIssue({
16362
+ code: "custom",
16363
+ message: "only an internal action carries steps",
16364
+ path: ["steps"]
16365
+ });
16366
+ if (!entry.readOnly) ctx.addIssue({
16367
+ code: "custom",
16368
+ message: "an addon action is read-only here",
16369
+ path: ["readOnly"]
16370
+ });
16371
+ if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
16372
+ code: "custom",
16373
+ message: "an addon action id is <addonId>:<localId>",
16374
+ path: ["id"]
16375
+ });
16376
+ });
16377
+ /** What an operator writes for an internal action. */
16378
+ var ActionInputSchema = object({
16379
+ name: string().min(1).max(120),
16380
+ steps: array(ActionStepSchema).min(1).max(50),
16381
+ variables: array(ActionVariableSchema).max(20).optional()
16382
+ });
16383
+ /** Who started a run. Absent = the operator pressed it. */
16384
+ var ActionRunOriginSchema = object({
16385
+ /** The automation block whose step started it. */
16386
+ blockId: string().min(1).optional() });
16387
+ /** `started` = the caller did not ask to wait. */
16388
+ var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
16389
+ var ActionRunResultSchema = object({
16390
+ runId: string().min(1),
16391
+ outcome: ActionRunOutcomeSchema,
16392
+ /** Why it did not run, or what failed. */
16393
+ message: string().optional()
16394
+ });
16395
+ _enum([
16396
+ "not-found",
16397
+ "read-only",
16398
+ "invalid-variables",
16399
+ "invalid-steps",
16400
+ "not-linked",
16401
+ "busy"
16402
+ ]);
16403
+ object({
16404
+ actionId: string(),
16405
+ runId: string(),
16406
+ isRunning: boolean(),
16407
+ /** Set when the run ended. */
16408
+ outcome: AutomationRunOutcomeSchema.optional(),
16409
+ lastRunAt: number().nullable(),
16410
+ lastError: string().nullable()
16011
16411
  });
16012
16412
  /**
16013
16413
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
@@ -19568,7 +19968,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
19568
19968
  kind: "mutation",
19569
19969
  auth: "admin",
19570
19970
  access: "view"
19571
- });
19971
+ }), method(object({
19972
+ blockId: string().min(1),
19973
+ trace: AutomationRunTraceSchema.optional(),
19974
+ runStartedAt: number().optional(),
19975
+ keepTraces: number().int().min(1).max(100).optional()
19976
+ }), _void(), {
19977
+ kind: "mutation",
19978
+ auth: "admin"
19979
+ }), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
19980
+ traces: array(AutomationRunTraceSchema),
19981
+ lastError: string().nullable()
19982
+ }), { auth: "admin" });
19572
19983
  /**
19573
19984
  * `custom-model-registry` — collection cap exposing operator-registered
19574
19985
  * custom detection models. Each provider (today: `addon-model-studio`)
@@ -44695,51 +45106,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
44695
45106
  kind: "mutation",
44696
45107
  auth: "admin"
44697
45108
  });
44698
- new Set([
44699
- {
44700
- id: "person",
44701
- name: "Person"
44702
- },
44703
- {
44704
- id: "vehicle",
44705
- name: "Vehicle"
44706
- },
44707
- {
44708
- id: "animal",
44709
- name: "Animal"
44710
- },
44711
- {
44712
- id: "package",
44713
- name: "Package"
44714
- }
44715
- ].map((l) => l.id));
44716
- var COCO_TO_MACRO = {
44717
- mapping: {
44718
- person: "person",
44719
- bicycle: "vehicle",
44720
- car: "vehicle",
44721
- motorcycle: "vehicle",
44722
- airplane: "vehicle",
44723
- bus: "vehicle",
44724
- train: "vehicle",
44725
- truck: "vehicle",
44726
- boat: "vehicle",
44727
- bird: "animal",
44728
- cat: "animal",
44729
- dog: "animal",
44730
- horse: "animal",
44731
- sheep: "animal",
44732
- cow: "animal",
44733
- elephant: "animal",
44734
- bear: "animal",
44735
- zebra: "animal",
44736
- giraffe: "animal",
44737
- suitcase: "package",
44738
- backpack: "package",
44739
- handbag: "package"
44740
- },
44741
- preserveOriginal: false
44742
- };
44743
45109
  var AUDIO_MACRO_LABELS = [
44744
45110
  {
44745
45111
  id: "speech",
@@ -57288,6 +57654,84 @@ DeviceType.Camera, method(object({ deviceId: number() }), AudioMetricsSnapshotSc
57288
57654
  * would produce more than `maxPoints` samples. */
57289
57655
  sampleEveryMs: number().int().positive().optional()
57290
57656
  }), AudioMetricsHistorySchema);
57657
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57658
+ actionId: string().min(1),
57659
+ variables: record(string(), ActionVariableValueSchema).optional()
57660
+ }), _void(), {
57661
+ kind: "mutation",
57662
+ auth: "admin"
57663
+ }), method(object({ actionId: string().min(1) }), _void(), {
57664
+ kind: "mutation",
57665
+ auth: "admin"
57666
+ });
57667
+ /**
57668
+ * actions — the ONE surface for runnable actions, for the UI and for
57669
+ * automations. Provided by the core-blocks builtin on the hub.
57670
+ *
57671
+ * An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
57672
+ * steps, kept in the hub's `actions` record kind) or declared by an addon over
57673
+ * `action-source`. `list` asks every `action-source` provider LIVE and overlays
57674
+ * the run status from the hub's `runs` ledger; there is no catalog here to
57675
+ * drift (D3).
57676
+ *
57677
+ * **Permissions follow the camera, as linked devices do.** An action is linked
57678
+ * to cameras by the operator (`setLinks`, D356: nothing links itself). A
57679
+ * non-admin may `get` / `run` an action only through a camera they may see that
57680
+ * links it: they name the camera (`deviceId`, a top-level field so the scope
57681
+ * gate sees it) and the provider refuses an action that camera does not link.
57682
+ * An admin, and an in-process caller (an automation block), may run any action.
57683
+ * Every refusal is typed (`[not-linked] …`) and logged.
57684
+ *
57685
+ * A second `run` of an action that is already running is REFUSED — traced and
57686
+ * logged — never queued.
57687
+ */
57688
+ var ActionIdInput = object({ actionId: string().min(1) });
57689
+ var ActionLinksSchema = object({
57690
+ deviceId: number().int().nonnegative(),
57691
+ actionIds: array(string().min(1)).max(100)
57692
+ });
57693
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57694
+ actionId: string().min(1),
57695
+ deviceId: number().int().nonnegative().optional()
57696
+ }), object({ action: ActionEntrySchema.nullable() }), {
57697
+ role: "viewer",
57698
+ auth: "protected",
57699
+ kind: "query",
57700
+ caller: "required"
57701
+ }), method(object({
57702
+ actionId: string().min(1),
57703
+ variables: record(string(), ActionVariableValueSchema).optional(),
57704
+ wait: boolean().optional(),
57705
+ origin: ActionRunOriginSchema.optional(),
57706
+ deviceId: number().int().nonnegative().optional()
57707
+ }), ActionRunResultSchema, {
57708
+ role: "viewer",
57709
+ auth: "protected",
57710
+ kind: "mutation",
57711
+ caller: "required"
57712
+ }), method(ActionIdInput, _void(), {
57713
+ kind: "mutation",
57714
+ auth: "admin"
57715
+ }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
57716
+ kind: "mutation",
57717
+ auth: "admin"
57718
+ }), method(object({
57719
+ actionId: string().min(1),
57720
+ action: ActionInputSchema.partial()
57721
+ }), object({ action: ActionEntrySchema }), {
57722
+ kind: "mutation",
57723
+ auth: "admin"
57724
+ }), method(ActionIdInput, _void(), {
57725
+ kind: "mutation",
57726
+ auth: "admin"
57727
+ }), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
57728
+ role: "viewer",
57729
+ auth: "protected",
57730
+ kind: "query"
57731
+ }), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
57732
+ kind: "mutation",
57733
+ auth: "admin"
57734
+ });
57291
57735
  object({
57292
57736
  /** Whether the automation is currently enabled. Disabled automations
57293
57737
  * ignore their trigger block — manual `trigger` still works. */
@@ -61533,10 +61977,20 @@ var PetFeederDeviceStatusSchema = _enum([
61533
61977
  ]);
61534
61978
  var gramsPortion = number().int().min(4).max(200);
61535
61979
  object({
61536
- /** Food currently in the bowl (grams). Null when the device has not
61537
- * reported a reading yet. On dual-hopper models this is the combined
61538
- * bowl reading; per-hopper levels live in `food1`/`food2`. */
61980
+ /** Food in the TANK (hopper), as the feeder's own sensor reports it
61981
+ * (`state.food`). A coarse level code, not grams — `0` is empty. The
61982
+ * amount in the bowl is `bowlFood`. On dual-hopper models this is the
61983
+ * combined reading; per-hopper levels live in `food1`/`food2`. Null when
61984
+ * the device has not reported yet. */
61539
61985
  foodLevel: number().nullable().meta(readingMeta("none")),
61986
+ /** Food in the BOWL as the feeder reports it (`state.bowl`), in the
61987
+ * feeder's own units. Null when the model reports none. */
61988
+ bowlFood: number().nullable().meta(readingMeta("none")),
61989
+ /** True while the pet is eating (`state.eating`). */
61990
+ eating: boolean(),
61991
+ /** Whether `markFoodReplenished` does anything on this model. When false
61992
+ * the client must not offer it. */
61993
+ supportsMarkRefilled: boolean(),
61540
61994
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
61541
61995
  * single-hopper models. */
61542
61996
  food1: number().nullable().meta(readingMeta("none")),
@@ -61544,8 +61998,8 @@ object({
61544
61998
  * single-hopper models. */
61545
61999
  food2: number().nullable().meta(readingMeta("none")),
61546
62000
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
61547
- * (`device_class: problem`, on = low). True when the bowl is empty /
61548
- * below the feeder's low threshold. */
62001
+ * (`device_class: problem`, on = low). True when the tank reports empty,
62002
+ * or, on a dual-hopper model, when EITHER hopper is empty. */
61549
62003
  lowFood: boolean(),
61550
62004
  /** Battery charge 0..100 (%). Null on mains-powered models or when the
61551
62005
  * device has no battery reading. */
@@ -66391,6 +66845,104 @@ Object.freeze({
66391
66845
  access: "create",
66392
66846
  role: "admin"
66393
66847
  },
66848
+ "actions.create": {
66849
+ capName: "actions",
66850
+ capScope: "system",
66851
+ addonId: null,
66852
+ access: "create",
66853
+ role: "admin"
66854
+ },
66855
+ "actions.delete": {
66856
+ capName: "actions",
66857
+ capScope: "system",
66858
+ addonId: null,
66859
+ access: "delete",
66860
+ role: "admin"
66861
+ },
66862
+ "actions.get": {
66863
+ capName: "actions",
66864
+ capScope: "system",
66865
+ addonId: null,
66866
+ access: "view",
66867
+ role: "viewer"
66868
+ },
66869
+ "actions.getLinks": {
66870
+ capName: "actions",
66871
+ capScope: "system",
66872
+ addonId: null,
66873
+ access: "view",
66874
+ role: "admin"
66875
+ },
66876
+ "actions.getTraces": {
66877
+ capName: "actions",
66878
+ capScope: "system",
66879
+ addonId: null,
66880
+ access: "view",
66881
+ role: "admin"
66882
+ },
66883
+ "actions.list": {
66884
+ capName: "actions",
66885
+ capScope: "system",
66886
+ addonId: null,
66887
+ access: "view",
66888
+ role: "admin"
66889
+ },
66890
+ "actions.listForCamera": {
66891
+ capName: "actions",
66892
+ capScope: "system",
66893
+ addonId: null,
66894
+ access: "view",
66895
+ role: "viewer"
66896
+ },
66897
+ "actions.run": {
66898
+ capName: "actions",
66899
+ capScope: "system",
66900
+ addonId: null,
66901
+ access: "create",
66902
+ role: "viewer"
66903
+ },
66904
+ "actions.setLinks": {
66905
+ capName: "actions",
66906
+ capScope: "system",
66907
+ addonId: null,
66908
+ access: "create",
66909
+ role: "admin"
66910
+ },
66911
+ "actions.stop": {
66912
+ capName: "actions",
66913
+ capScope: "system",
66914
+ addonId: null,
66915
+ access: "create",
66916
+ role: "admin"
66917
+ },
66918
+ "actions.update": {
66919
+ capName: "actions",
66920
+ capScope: "system",
66921
+ addonId: null,
66922
+ access: "create",
66923
+ role: "admin"
66924
+ },
66925
+ "actionSource.listActions": {
66926
+ capName: "action-source",
66927
+ capScope: "system",
66928
+ addonId: null,
66929
+ access: "view",
66930
+ role: "admin"
66931
+ },
66932
+ "actionSource.runAction": {
66933
+ capName: "action-source",
66934
+ capScope: "system",
66935
+ addonId: null,
66936
+ access: "create",
66937
+ role: "admin"
66938
+ },
66939
+ "actionSource.stopAction": {
66940
+ capName: "action-source",
66941
+ capScope: "system",
66942
+ addonId: null,
66943
+ access: "create",
66944
+ role: "admin"
66945
+ },
66394
66946
  "addonPages.listPages": {
66395
66947
  capName: "addon-pages",
66396
66948
  capScope: "system",
@@ -67672,6 +68224,13 @@ Object.freeze({
67672
68224
  access: "view",
67673
68225
  role: "admin"
67674
68226
  },
68227
+ "coreBlocks.getAutomationRunState": {
68228
+ capName: "core-blocks",
68229
+ capScope: "system",
68230
+ addonId: null,
68231
+ access: "view",
68232
+ role: "admin"
68233
+ },
67675
68234
  "coreBlocks.getBlockSettings": {
67676
68235
  capName: "core-blocks",
67677
68236
  capScope: "system",
@@ -67693,6 +68252,13 @@ Object.freeze({
67693
68252
  access: "view",
67694
68253
  role: "admin"
67695
68254
  },
68255
+ "coreBlocks.getTraces": {
68256
+ capName: "core-blocks",
68257
+ capScope: "system",
68258
+ addonId: null,
68259
+ access: "view",
68260
+ role: "admin"
68261
+ },
67696
68262
  "coreBlocks.getTypeDefs": {
67697
68263
  capName: "core-blocks",
67698
68264
  capScope: "system",
@@ -67728,6 +68294,13 @@ Object.freeze({
67728
68294
  access: "create",
67729
68295
  role: "admin"
67730
68296
  },
68297
+ "coreBlocks.reportAutomationRun": {
68298
+ capName: "core-blocks",
68299
+ capScope: "system",
68300
+ addonId: null,
68301
+ access: "create",
68302
+ role: "admin"
68303
+ },
67731
68304
  "coreBlocks.restart": {
67732
68305
  capName: "core-blocks",
67733
68306
  capScope: "system",
@@ -79882,6 +80455,8 @@ var ML = "model and training machinery — no device action";
79882
80455
  var INTERNAL = "internal plumbing between addons — never operator-facing";
79883
80456
  /** Every system-scoped cap, with why it is not a device's vocabulary. */
79884
80457
  var SYSTEM_CAP_VOCABULARY = {
80458
+ "action-source": system(INTERNAL),
80459
+ actions: system("declared actions — run from the Actions page and from the cameras that link them"),
79885
80460
  "addon-pages": system(UI_PLUMBING),
79886
80461
  "addon-pages-source": system(UI_PLUMBING),
79887
80462
  "addon-routes": system(UI_PLUMBING),
@@ -80078,6 +80653,31 @@ Object.freeze({
80078
80653
  form: "single",
80079
80654
  optional: false
80080
80655
  }],
80656
+ "actions.get": [{
80657
+ name: "deviceId",
80658
+ form: "single",
80659
+ optional: true
80660
+ }],
80661
+ "actions.getLinks": [{
80662
+ name: "deviceId",
80663
+ form: "single",
80664
+ optional: false
80665
+ }],
80666
+ "actions.listForCamera": [{
80667
+ name: "deviceId",
80668
+ form: "single",
80669
+ optional: false
80670
+ }],
80671
+ "actions.run": [{
80672
+ name: "deviceId",
80673
+ form: "single",
80674
+ optional: true
80675
+ }],
80676
+ "actions.setLinks": [{
80677
+ name: "deviceId",
80678
+ form: "single",
80679
+ optional: false
80680
+ }],
80081
80681
  "addonSettings.getDeviceSettings": [{
80082
80682
  name: "deviceId",
80083
80683
  form: "single",