@camstack/addon-training 0.1.94 → 0.1.96

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 (23) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{MotionZonesSettings-BDIz0ADl.mjs → MotionZonesSettings-BxBSFLUa.mjs} +2 -2
  3. package/dist/{PrivacyMaskSettings-Cz_1itEY.mjs → PrivacyMaskSettings-CCC_kZYM.mjs} +2 -2
  4. package/dist/{SceneMonitorEditor-DxdQN6e5.mjs → SceneMonitorEditor-D_mTxAAt.mjs} +2 -2
  5. package/dist/_stub.js +3851 -3879
  6. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-DcGxW0BQ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-CczXdTQA.mjs} +3 -3
  7. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CXwzSk5U.mjs +26 -0
  8. package/dist/addon-training.css +1 -1
  9. package/dist/{dist-mC0XNhcx.mjs → dist-B2b-EFJw.mjs} +675 -75
  10. package/dist/{dist-C_f7s2st.js → dist-B8UTiACQ.js} +675 -75
  11. package/dist/{hostInit-DPLOK7Fx.mjs → hostInit-8_axXcGH.mjs} +2 -2
  12. package/dist/index.js +1 -1
  13. package/dist/orchestrator/training.addon.js +1 -1
  14. package/dist/orchestrator/training.addon.mjs +1 -1
  15. package/dist/{player-overlays-ClwLHxNP.mjs → player-overlays-ByaGTAjq.mjs} +1 -1
  16. package/dist/providers/modal/training-modal.addon.js +1 -1
  17. package/dist/providers/modal/training-modal.addon.mjs +1 -1
  18. package/dist/remoteEntry.js +1 -1
  19. package/dist/{responsive-Cx4quvGq.mjs → responsive-DxbPefhp.mjs} +1 -1
  20. package/dist/{scene-monitor-copy-DIJUg8Ro.mjs → scene-monitor-copy-ZSU8qdvS.mjs} +1 -1
  21. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-Ch6HQCmx.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-GYT7Xl1I.mjs} +1 -1
  22. package/package.json +1 -1
  23. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B6wwfPOo.mjs +0 -26
@@ -32,7 +32,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
32
  }) : target, mod));
33
33
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
34
34
  require("node:crypto");
35
- //#region ../types/dist/event-category-CT-hz5Rb.mjs
35
+ //#region ../types/dist/event-category-hdMR7CTW.mjs
36
36
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
37
37
  EventCategory["SystemBoot"] = "system.boot";
38
38
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -797,6 +797,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
797
797
  */
798
798
  EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
799
799
  /**
800
+ * An action run started or ended. Emitted by the `actions` surface.
801
+ * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
802
+ */
803
+ EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
804
+ /**
800
805
  * Progress update from a running model conversion job.
801
806
  * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
802
807
  * Emitted by `addon-model-studio` on the converting node.
@@ -5608,7 +5613,7 @@ var ZodIssueCode = {
5608
5613
  var ZodFirstPartyTypeKind;
5609
5614
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5610
5615
  //#endregion
5611
- //#region ../types/dist/sleep--jXS9hWo.mjs
5616
+ //#region ../types/dist/sleep-BHjNez61.mjs
5612
5617
  /**
5613
5618
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5614
5619
  * window to float samples (D455).
@@ -8905,6 +8910,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
8905
8910
  /** Every capability name, so addon code can check a name without the schema graph. */
8906
8911
  var CAP_NAMES = Object.freeze([
8907
8912
  "accessories",
8913
+ "action-source",
8914
+ "actions",
8908
8915
  "addon-pages",
8909
8916
  "addon-pages-source",
8910
8917
  "addon-routes",
@@ -10207,6 +10214,18 @@ Object.freeze({
10207
10214
  "path": "foodLevel",
10208
10215
  "valueType": "number"
10209
10216
  },
10217
+ {
10218
+ "path": "bowlFood",
10219
+ "valueType": "number"
10220
+ },
10221
+ {
10222
+ "path": "eating",
10223
+ "valueType": "boolean"
10224
+ },
10225
+ {
10226
+ "path": "supportsMarkRefilled",
10227
+ "valueType": "boolean"
10228
+ },
10210
10229
  {
10211
10230
  "path": "food1",
10212
10231
  "valueType": "number"
@@ -15771,7 +15790,23 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15771
15790
  kind: literal("schedule"),
15772
15791
  cron: string().min(1).max(120)
15773
15792
  }),
15774
- object({ kind: literal("manual") })
15793
+ object({ kind: literal("manual") }),
15794
+ object({
15795
+ kind: literal("detection"),
15796
+ /** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
15797
+ * matches every raw class that maps to it; any other name matches
15798
+ * exactly. */
15799
+ classes: array(string().min(1)).min(1),
15800
+ deviceIds: array(number().int().nonnegative()).min(1),
15801
+ /** The track must have visited at least one of these zones. */
15802
+ zones: array(string().min(1)).min(1).optional(),
15803
+ /** Best-so-far confidence the track must reach. */
15804
+ minScore: number().min(0).max(1).optional()
15805
+ }),
15806
+ object({
15807
+ kind: literal("interval"),
15808
+ minutes: number().int().min(1).max(1440)
15809
+ })
15775
15810
  ]);
15776
15811
  /**
15777
15812
  * One action step.
@@ -15791,28 +15826,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15791
15826
  * is called. The runner still receives a number and is untouched; the
15792
15827
  * resolution is the recipe's job, not the runner's.
15793
15828
  */
15829
+ var AutomationWaitStepSchema = object({
15830
+ kind: literal("wait"),
15831
+ seconds: number().min(0).max(300)
15832
+ });
15833
+ var AutomationCapStepSchema = object({
15834
+ kind: literal("cap"),
15835
+ /**
15836
+ * One device, several same-family devices (locks / climate family / …),
15837
+ * or `{ $var }` for the device that triggered the run. An array is
15838
+ * fan-out at codegen — each id gets the same cap.method call.
15839
+ */
15840
+ deviceId: union([
15841
+ number().int(),
15842
+ array(number().int()).min(1),
15843
+ object({ $var: string().min(1) })
15844
+ ]),
15845
+ cap: string().min(1),
15846
+ method: string().min(1),
15847
+ /** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
15848
+ * SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
15849
+ * the expression leaf. */
15850
+ args: record(string(), unknown()).optional()
15851
+ });
15852
+ /**
15853
+ * The steps an internal Action may contain: cap and wait, and nothing that can
15854
+ * call back into an Action — so an Action can never reach itself (no cycles).
15855
+ */
15856
+ var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
15794
15857
  var AutomationActionSchema = discriminatedUnion("kind", [
15858
+ AutomationWaitStepSchema,
15859
+ AutomationCapStepSchema,
15795
15860
  object({
15796
- kind: literal("wait"),
15797
- seconds: number().min(0).max(300)
15798
- }),
15799
- object({
15800
- kind: literal("cap"),
15801
- /**
15802
- * One device, several same-family devices (locks / climate family / …),
15803
- * or `{ $var }` for the device that triggered the run. An array is
15804
- * fan-out at codegen — each id gets the same cap.method call.
15805
- */
15806
- deviceId: union([
15807
- number().int(),
15808
- array(number().int()).min(1),
15809
- object({ $var: string().min(1) })
15810
- ]),
15811
- cap: string().min(1),
15812
- method: string().min(1),
15813
- /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
15814
- * evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
15815
- args: record(string(), unknown()).optional()
15861
+ kind: literal("action"),
15862
+ /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
15863
+ actionId: string().min(1),
15864
+ /** Values for the action's declared variables; the others take their default. */
15865
+ variables: record(string(), union([
15866
+ string(),
15867
+ number(),
15868
+ boolean()
15869
+ ])).optional()
15816
15870
  }),
15817
15871
  object({
15818
15872
  kind: literal("code"),
@@ -15821,10 +15875,356 @@ var AutomationActionSchema = discriminatedUnion("kind", [
15821
15875
  code: string().min(1).max(2e4)
15822
15876
  })
15823
15877
  ]);
15878
+ /**
15879
+ * How a trigger that arrives while the automation is busy (or cooling down) is
15880
+ * handled. One of the automation's execution modes, never a property of its
15881
+ * actions. Absent means `single`.
15882
+ *
15883
+ * - `single` — drop the trigger while a run is in progress (traced + logged).
15884
+ * - `restart` — abort the run in progress (at its next step boundary), start fresh.
15885
+ * - `queued` — queue up to `max` triggers, drop the rest (traced).
15886
+ * - `parallel` — up to `max` runs at once, drop the rest (traced).
15887
+ * - `cooldown` — `single`, and no new run until `minutes` after the last run
15888
+ * STARTED; persisted across a restart. A manual trigger bypasses only this
15889
+ * wait, never the single/queued limits.
15890
+ */
15891
+ var AutomationRunModeSchema = discriminatedUnion("mode", [
15892
+ object({ mode: literal("single") }),
15893
+ object({ mode: literal("restart") }),
15894
+ object({
15895
+ mode: literal("queued"),
15896
+ max: number().int().min(1).max(10)
15897
+ }),
15898
+ object({
15899
+ mode: literal("parallel"),
15900
+ max: number().int().min(1).max(10)
15901
+ }),
15902
+ object({
15903
+ mode: literal("cooldown"),
15904
+ minutes: number().int().min(1).max(1440)
15905
+ })
15906
+ ]);
15824
15907
  var AutomationRecipeSchema = object({
15825
15908
  triggers: array(AutomationTriggerSchema),
15826
15909
  conditions: AutomationConditionSchema.optional(),
15827
- actions: array(AutomationActionSchema)
15910
+ actions: array(AutomationActionSchema),
15911
+ runMode: AutomationRunModeSchema.optional(),
15912
+ /** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
15913
+ keepTraces: number().int().min(1).max(100).optional()
15914
+ });
15915
+ new Set([
15916
+ {
15917
+ id: "person",
15918
+ name: "Person"
15919
+ },
15920
+ {
15921
+ id: "vehicle",
15922
+ name: "Vehicle"
15923
+ },
15924
+ {
15925
+ id: "animal",
15926
+ name: "Animal"
15927
+ },
15928
+ {
15929
+ id: "package",
15930
+ name: "Package"
15931
+ }
15932
+ ].map((l) => l.id));
15933
+ var COCO_TO_MACRO = {
15934
+ mapping: {
15935
+ person: "person",
15936
+ bicycle: "vehicle",
15937
+ car: "vehicle",
15938
+ motorcycle: "vehicle",
15939
+ airplane: "vehicle",
15940
+ bus: "vehicle",
15941
+ train: "vehicle",
15942
+ truck: "vehicle",
15943
+ boat: "vehicle",
15944
+ bird: "animal",
15945
+ cat: "animal",
15946
+ dog: "animal",
15947
+ horse: "animal",
15948
+ sheep: "animal",
15949
+ cow: "animal",
15950
+ elephant: "animal",
15951
+ bear: "animal",
15952
+ zebra: "animal",
15953
+ giraffe: "animal",
15954
+ suitcase: "package",
15955
+ backpack: "package",
15956
+ handbag: "package"
15957
+ },
15958
+ preserveOriginal: false
15959
+ };
15960
+ new Set(Object.values(COCO_TO_MACRO.mapping));
15961
+ /**
15962
+ * Run traces — what an automation (or, later, an Action run) DID, node by node,
15963
+ * so the editor can paint every block green or red with its reason.
15964
+ *
15965
+ * A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
15966
+ * every condition node (containers and leaves, including the ones a
15967
+ * short-circuit never reached), the run-mode verdict and every action step —
15968
+ * each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
15969
+ * for an Action run). Skipped
15970
+ * evaluations are traced too, and identical consecutive skips collapse into a
15971
+ * repeat count so a trigger that fails every 5 minutes cannot flush real runs.
15972
+ *
15973
+ * {@link AutomationStepTraceSchema} is deliberately free of automation
15974
+ * vocabulary so an Action run records the same step shape.
15975
+ */
15976
+ /** A value a trace may show: JSON primitives and short lists, nothing deeper. */
15977
+ var TraceValueSchema = union([
15978
+ string(),
15979
+ number(),
15980
+ boolean(),
15981
+ _null(),
15982
+ array(union([string(), number()]))
15983
+ ]);
15984
+ var AutomationRunOutcomeSchema = _enum([
15985
+ "ran",
15986
+ "skipped-trigger",
15987
+ "skipped-conditions",
15988
+ "skipped-cooldown",
15989
+ "skipped-overlap",
15990
+ "failed",
15991
+ "aborted"
15992
+ ]);
15993
+ /** `not-evaluated` = a short-circuit never reached the node. */
15994
+ var TraceNodeOutcomeSchema = _enum([
15995
+ "pass",
15996
+ "fail",
15997
+ "not-evaluated"
15998
+ ]);
15999
+ var AutomationTriggerTraceSchema = object({
16000
+ kind: string().min(1),
16001
+ outcome: _enum(["pass", "fail"]),
16002
+ /** Why an event was rejected ("class person not in [dog]") or what fired. */
16003
+ reason: string(),
16004
+ /** deviceId, className, trackId, score … — only what the trigger exposes. */
16005
+ vars: record(string(), TraceValueSchema)
16006
+ });
16007
+ var AutomationConditionTraceNodeSchema = object({
16008
+ /** `conditions` for the root, `conditions.<i>` for its i-th child, … */
16009
+ path: string().min(1),
16010
+ kind: _enum([
16011
+ "all",
16012
+ "any",
16013
+ "not",
16014
+ "condition",
16015
+ "expression"
16016
+ ]),
16017
+ outcome: TraceNodeOutcomeSchema,
16018
+ reason: string(),
16019
+ deviceId: number().int().optional(),
16020
+ cap: string().optional(),
16021
+ fieldPath: string().optional(),
16022
+ operator: string().optional(),
16023
+ expected: TraceValueSchema.optional(),
16024
+ /** What the mirror held; `null` when it held nothing (unknown). */
16025
+ observed: TraceValueSchema.optional()
16026
+ });
16027
+ var AutomationRunVerdictSchema = object({
16028
+ mode: AutomationRunModeSchema,
16029
+ decision: _enum([
16030
+ "run",
16031
+ "queued",
16032
+ "restart",
16033
+ "drop",
16034
+ "cooldown",
16035
+ "bypass"
16036
+ ]),
16037
+ reason: string()
16038
+ });
16039
+ /** One executed (or not-run) step — shared by automations and Action runs. */
16040
+ var AutomationStepTraceSchema = object({
16041
+ /** `actions.<i>` */
16042
+ path: string().min(1),
16043
+ kind: string().min(1),
16044
+ cap: string().optional(),
16045
+ method: string().optional(),
16046
+ deviceId: number().int().optional(),
16047
+ startedAt: number().optional(),
16048
+ endedAt: number().optional(),
16049
+ outcome: _enum([
16050
+ "ok",
16051
+ "error",
16052
+ "not-run"
16053
+ ]),
16054
+ message: string().optional()
16055
+ });
16056
+ var AutomationRunTraceSchema = object({
16057
+ runId: string().min(1),
16058
+ startedAt: number(),
16059
+ endedAt: number(),
16060
+ trigger: AutomationTriggerTraceSchema,
16061
+ conditions: array(AutomationConditionTraceNodeSchema),
16062
+ verdict: AutomationRunVerdictSchema.optional(),
16063
+ steps: array(AutomationStepTraceSchema),
16064
+ outcome: AutomationRunOutcomeSchema,
16065
+ /** How many identical consecutive skips this trace stands for (>= 1). */
16066
+ repeat: number().int().min(1),
16067
+ /** When the latest of those repeats happened. */
16068
+ lastAt: number()
16069
+ });
16070
+ /**
16071
+ * What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
16072
+ * `action:<actionId>`): the cooldown stamp and the trace ring.
16073
+ */
16074
+ var AutomationStateDocSchema = object({
16075
+ version: literal(1),
16076
+ lastRunStartedAt: number().nullable(),
16077
+ traces: array(AutomationRunTraceSchema)
16078
+ });
16079
+ /**
16080
+ * Actions — named, runnable things an operator (or an automation) can start,
16081
+ * declared as LIST ENTRIES, never as devices.
16082
+ *
16083
+ * An entry is either **internal** (a short list of cap/wait steps kept in the
16084
+ * hub's `actions` record kind) or declared by an addon through the
16085
+ * `action-source` collection (a Home Assistant script, a scene …). The one
16086
+ * surface the UI and automations talk to is the `actions` cap; it keeps no
16087
+ * catalog of its own (D3) — every `list` asks the providers live.
16088
+ *
16089
+ * This file is the data half: the entry schema, the variables an entry may
16090
+ * declare, and the pure resolution of the values a run was given. It holds no
16091
+ * runtime.
16092
+ */
16093
+ /** What a variable's value is. `select` takes one of `options`. */
16094
+ var ActionVariableTypeSchema = _enum([
16095
+ "string",
16096
+ "number",
16097
+ "boolean",
16098
+ "select"
16099
+ ]);
16100
+ var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
16101
+ var ActionVariableValueSchema = union([
16102
+ string(),
16103
+ number(),
16104
+ boolean()
16105
+ ]);
16106
+ /**
16107
+ * One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
16108
+ * value) or `{{vars.name}}` (inside a string) in their args.
16109
+ */
16110
+ var ActionVariableSchema = object({
16111
+ name: string().regex(ACTION_VARIABLE_NAME_RE),
16112
+ label: string().min(1).max(120).optional(),
16113
+ type: ActionVariableTypeSchema,
16114
+ required: boolean().optional(),
16115
+ default: ActionVariableValueSchema.optional(),
16116
+ /** The allowed values of a `select`. */
16117
+ options: array(string().min(1)).min(1).optional()
16118
+ }).superRefine((v, ctx) => {
16119
+ if (v.type === "select" && v.options === void 0) ctx.addIssue({
16120
+ code: "custom",
16121
+ message: "a select variable needs options",
16122
+ path: ["options"]
16123
+ });
16124
+ if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
16125
+ code: "custom",
16126
+ message: variableValueError(v, v.default) ?? "invalid default",
16127
+ path: ["default"]
16128
+ });
16129
+ });
16130
+ /** Why `value` is not a legal value for the variable, or null when it is. */
16131
+ function variableValueError(variable, value) {
16132
+ switch (variable.type) {
16133
+ case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
16134
+ case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
16135
+ case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
16136
+ case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
16137
+ }
16138
+ }
16139
+ var ActionSourceKindSchema = _enum(["internal", "addon"]);
16140
+ function isInternalActionId(actionId) {
16141
+ return actionId.startsWith("internal:") && actionId.length > 9;
16142
+ }
16143
+ /** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
16144
+ function addonIdOfActionId(actionId) {
16145
+ if (isInternalActionId(actionId)) return null;
16146
+ const at = actionId.indexOf(":");
16147
+ return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
16148
+ }
16149
+ var ActionStatusSchema = object({
16150
+ isRunning: boolean(),
16151
+ /** Ms epoch the latest run STARTED; null when it never ran. */
16152
+ lastRunAt: number().nullable(),
16153
+ /** The latest run's failure; null on success or when it never ran. */
16154
+ lastError: string().nullable()
16155
+ });
16156
+ var ActionEntrySchema = object({
16157
+ /** `internal:<uuid>` or `<addonId>:<localId>`. */
16158
+ id: string().min(3),
16159
+ name: string().min(1).max(120),
16160
+ /** The addon that declared it; `core-blocks` for an internal one. */
16161
+ addonId: string().min(1),
16162
+ source: ActionSourceKindSchema,
16163
+ /** An addon-declared entry is edited where it was declared. */
16164
+ readOnly: boolean(),
16165
+ /** Internal only: cap and wait steps. No action-in-action, so no cycles. */
16166
+ steps: array(ActionStepSchema).min(1).max(50).optional(),
16167
+ variables: array(ActionVariableSchema).max(20).optional(),
16168
+ status: ActionStatusSchema
16169
+ }).superRefine((entry, ctx) => {
16170
+ if (entry.source === "internal") {
16171
+ if (!isInternalActionId(entry.id)) ctx.addIssue({
16172
+ code: "custom",
16173
+ message: "an internal action id is internal:<uuid>",
16174
+ path: ["id"]
16175
+ });
16176
+ return;
16177
+ }
16178
+ if (entry.steps !== void 0) ctx.addIssue({
16179
+ code: "custom",
16180
+ message: "only an internal action carries steps",
16181
+ path: ["steps"]
16182
+ });
16183
+ if (!entry.readOnly) ctx.addIssue({
16184
+ code: "custom",
16185
+ message: "an addon action is read-only here",
16186
+ path: ["readOnly"]
16187
+ });
16188
+ if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
16189
+ code: "custom",
16190
+ message: "an addon action id is <addonId>:<localId>",
16191
+ path: ["id"]
16192
+ });
16193
+ });
16194
+ /** What an operator writes for an internal action. */
16195
+ var ActionInputSchema = object({
16196
+ name: string().min(1).max(120),
16197
+ steps: array(ActionStepSchema).min(1).max(50),
16198
+ variables: array(ActionVariableSchema).max(20).optional()
16199
+ });
16200
+ /** Who started a run. Absent = the operator pressed it. */
16201
+ var ActionRunOriginSchema = object({
16202
+ /** The automation block whose step started it. */
16203
+ blockId: string().min(1).optional() });
16204
+ /** `started` = the caller did not ask to wait. */
16205
+ var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
16206
+ var ActionRunResultSchema = object({
16207
+ runId: string().min(1),
16208
+ outcome: ActionRunOutcomeSchema,
16209
+ /** Why it did not run, or what failed. */
16210
+ message: string().optional()
16211
+ });
16212
+ _enum([
16213
+ "not-found",
16214
+ "read-only",
16215
+ "invalid-variables",
16216
+ "invalid-steps",
16217
+ "not-linked",
16218
+ "busy"
16219
+ ]);
16220
+ object({
16221
+ actionId: string(),
16222
+ runId: string(),
16223
+ isRunning: boolean(),
16224
+ /** Set when the run ended. */
16225
+ outcome: AutomationRunOutcomeSchema.optional(),
16226
+ lastRunAt: number().nullable(),
16227
+ lastError: string().nullable()
15828
16228
  });
15829
16229
  /**
15830
16230
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
@@ -19385,7 +19785,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
19385
19785
  kind: "mutation",
19386
19786
  auth: "admin",
19387
19787
  access: "view"
19388
- });
19788
+ }), method(object({
19789
+ blockId: string().min(1),
19790
+ trace: AutomationRunTraceSchema.optional(),
19791
+ runStartedAt: number().optional(),
19792
+ keepTraces: number().int().min(1).max(100).optional()
19793
+ }), _void(), {
19794
+ kind: "mutation",
19795
+ auth: "admin"
19796
+ }), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
19797
+ traces: array(AutomationRunTraceSchema),
19798
+ lastError: string().nullable()
19799
+ }), { auth: "admin" });
19389
19800
  /**
19390
19801
  * `custom-model-registry` — collection cap exposing operator-registered
19391
19802
  * custom detection models. Each provider (today: `addon-model-studio`)
@@ -44478,51 +44889,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
44478
44889
  kind: "mutation",
44479
44890
  auth: "admin"
44480
44891
  });
44481
- new Set([
44482
- {
44483
- id: "person",
44484
- name: "Person"
44485
- },
44486
- {
44487
- id: "vehicle",
44488
- name: "Vehicle"
44489
- },
44490
- {
44491
- id: "animal",
44492
- name: "Animal"
44493
- },
44494
- {
44495
- id: "package",
44496
- name: "Package"
44497
- }
44498
- ].map((l) => l.id));
44499
- var COCO_TO_MACRO = {
44500
- mapping: {
44501
- person: "person",
44502
- bicycle: "vehicle",
44503
- car: "vehicle",
44504
- motorcycle: "vehicle",
44505
- airplane: "vehicle",
44506
- bus: "vehicle",
44507
- train: "vehicle",
44508
- truck: "vehicle",
44509
- boat: "vehicle",
44510
- bird: "animal",
44511
- cat: "animal",
44512
- dog: "animal",
44513
- horse: "animal",
44514
- sheep: "animal",
44515
- cow: "animal",
44516
- elephant: "animal",
44517
- bear: "animal",
44518
- zebra: "animal",
44519
- giraffe: "animal",
44520
- suitcase: "package",
44521
- backpack: "package",
44522
- handbag: "package"
44523
- },
44524
- preserveOriginal: false
44525
- };
44526
44892
  var AUDIO_MACRO_LABELS = [
44527
44893
  {
44528
44894
  id: "speech",
@@ -57071,6 +57437,84 @@ DeviceType.Camera, method(object({ deviceId: number() }), AudioMetricsSnapshotSc
57071
57437
  * would produce more than `maxPoints` samples. */
57072
57438
  sampleEveryMs: number().int().positive().optional()
57073
57439
  }), AudioMetricsHistorySchema);
57440
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57441
+ actionId: string().min(1),
57442
+ variables: record(string(), ActionVariableValueSchema).optional()
57443
+ }), _void(), {
57444
+ kind: "mutation",
57445
+ auth: "admin"
57446
+ }), method(object({ actionId: string().min(1) }), _void(), {
57447
+ kind: "mutation",
57448
+ auth: "admin"
57449
+ });
57450
+ /**
57451
+ * actions — the ONE surface for runnable actions, for the UI and for
57452
+ * automations. Provided by the core-blocks builtin on the hub.
57453
+ *
57454
+ * An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
57455
+ * steps, kept in the hub's `actions` record kind) or declared by an addon over
57456
+ * `action-source`. `list` asks every `action-source` provider LIVE and overlays
57457
+ * the run status from the hub's `runs` ledger; there is no catalog here to
57458
+ * drift (D3).
57459
+ *
57460
+ * **Permissions follow the camera, as linked devices do.** An action is linked
57461
+ * to cameras by the operator (`setLinks`, D356: nothing links itself). A
57462
+ * non-admin may `get` / `run` an action only through a camera they may see that
57463
+ * links it: they name the camera (`deviceId`, a top-level field so the scope
57464
+ * gate sees it) and the provider refuses an action that camera does not link.
57465
+ * An admin, and an in-process caller (an automation block), may run any action.
57466
+ * Every refusal is typed (`[not-linked] …`) and logged.
57467
+ *
57468
+ * A second `run` of an action that is already running is REFUSED — traced and
57469
+ * logged — never queued.
57470
+ */
57471
+ var ActionIdInput = object({ actionId: string().min(1) });
57472
+ var ActionLinksSchema = object({
57473
+ deviceId: number().int().nonnegative(),
57474
+ actionIds: array(string().min(1)).max(100)
57475
+ });
57476
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57477
+ actionId: string().min(1),
57478
+ deviceId: number().int().nonnegative().optional()
57479
+ }), object({ action: ActionEntrySchema.nullable() }), {
57480
+ role: "viewer",
57481
+ auth: "protected",
57482
+ kind: "query",
57483
+ caller: "required"
57484
+ }), method(object({
57485
+ actionId: string().min(1),
57486
+ variables: record(string(), ActionVariableValueSchema).optional(),
57487
+ wait: boolean().optional(),
57488
+ origin: ActionRunOriginSchema.optional(),
57489
+ deviceId: number().int().nonnegative().optional()
57490
+ }), ActionRunResultSchema, {
57491
+ role: "viewer",
57492
+ auth: "protected",
57493
+ kind: "mutation",
57494
+ caller: "required"
57495
+ }), method(ActionIdInput, _void(), {
57496
+ kind: "mutation",
57497
+ auth: "admin"
57498
+ }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
57499
+ kind: "mutation",
57500
+ auth: "admin"
57501
+ }), method(object({
57502
+ actionId: string().min(1),
57503
+ action: ActionInputSchema.partial()
57504
+ }), object({ action: ActionEntrySchema }), {
57505
+ kind: "mutation",
57506
+ auth: "admin"
57507
+ }), method(ActionIdInput, _void(), {
57508
+ kind: "mutation",
57509
+ auth: "admin"
57510
+ }), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
57511
+ role: "viewer",
57512
+ auth: "protected",
57513
+ kind: "query"
57514
+ }), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
57515
+ kind: "mutation",
57516
+ auth: "admin"
57517
+ });
57074
57518
  object({
57075
57519
  /** Whether the automation is currently enabled. Disabled automations
57076
57520
  * ignore their trigger block — manual `trigger` still works. */
@@ -61316,10 +61760,20 @@ var PetFeederDeviceStatusSchema = _enum([
61316
61760
  ]);
61317
61761
  var gramsPortion = number().int().min(4).max(200);
61318
61762
  object({
61319
- /** Food currently in the bowl (grams). Null when the device has not
61320
- * reported a reading yet. On dual-hopper models this is the combined
61321
- * bowl reading; per-hopper levels live in `food1`/`food2`. */
61763
+ /** Food in the TANK (hopper), as the feeder's own sensor reports it
61764
+ * (`state.food`). A coarse level code, not grams — `0` is empty. The
61765
+ * amount in the bowl is `bowlFood`. On dual-hopper models this is the
61766
+ * combined reading; per-hopper levels live in `food1`/`food2`. Null when
61767
+ * the device has not reported yet. */
61322
61768
  foodLevel: number().nullable().meta(readingMeta("none")),
61769
+ /** Food in the BOWL as the feeder reports it (`state.bowl`), in the
61770
+ * feeder's own units. Null when the model reports none. */
61771
+ bowlFood: number().nullable().meta(readingMeta("none")),
61772
+ /** True while the pet is eating (`state.eating`). */
61773
+ eating: boolean(),
61774
+ /** Whether `markFoodReplenished` does anything on this model. When false
61775
+ * the client must not offer it. */
61776
+ supportsMarkRefilled: boolean(),
61323
61777
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
61324
61778
  * single-hopper models. */
61325
61779
  food1: number().nullable().meta(readingMeta("none")),
@@ -61327,8 +61781,8 @@ object({
61327
61781
  * single-hopper models. */
61328
61782
  food2: number().nullable().meta(readingMeta("none")),
61329
61783
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
61330
- * (`device_class: problem`, on = low). True when the bowl is empty /
61331
- * below the feeder's low threshold. */
61784
+ * (`device_class: problem`, on = low). True when the tank reports empty,
61785
+ * or, on a dual-hopper model, when EITHER hopper is empty. */
61332
61786
  lowFood: boolean(),
61333
61787
  /** Battery charge 0..100 (%). Null on mains-powered models or when the
61334
61788
  * device has no battery reading. */
@@ -66178,6 +66632,104 @@ Object.freeze({
66178
66632
  access: "create",
66179
66633
  role: "admin"
66180
66634
  },
66635
+ "actions.create": {
66636
+ capName: "actions",
66637
+ capScope: "system",
66638
+ addonId: null,
66639
+ access: "create",
66640
+ role: "admin"
66641
+ },
66642
+ "actions.delete": {
66643
+ capName: "actions",
66644
+ capScope: "system",
66645
+ addonId: null,
66646
+ access: "delete",
66647
+ role: "admin"
66648
+ },
66649
+ "actions.get": {
66650
+ capName: "actions",
66651
+ capScope: "system",
66652
+ addonId: null,
66653
+ access: "view",
66654
+ role: "viewer"
66655
+ },
66656
+ "actions.getLinks": {
66657
+ capName: "actions",
66658
+ capScope: "system",
66659
+ addonId: null,
66660
+ access: "view",
66661
+ role: "admin"
66662
+ },
66663
+ "actions.getTraces": {
66664
+ capName: "actions",
66665
+ capScope: "system",
66666
+ addonId: null,
66667
+ access: "view",
66668
+ role: "admin"
66669
+ },
66670
+ "actions.list": {
66671
+ capName: "actions",
66672
+ capScope: "system",
66673
+ addonId: null,
66674
+ access: "view",
66675
+ role: "admin"
66676
+ },
66677
+ "actions.listForCamera": {
66678
+ capName: "actions",
66679
+ capScope: "system",
66680
+ addonId: null,
66681
+ access: "view",
66682
+ role: "viewer"
66683
+ },
66684
+ "actions.run": {
66685
+ capName: "actions",
66686
+ capScope: "system",
66687
+ addonId: null,
66688
+ access: "create",
66689
+ role: "viewer"
66690
+ },
66691
+ "actions.setLinks": {
66692
+ capName: "actions",
66693
+ capScope: "system",
66694
+ addonId: null,
66695
+ access: "create",
66696
+ role: "admin"
66697
+ },
66698
+ "actions.stop": {
66699
+ capName: "actions",
66700
+ capScope: "system",
66701
+ addonId: null,
66702
+ access: "create",
66703
+ role: "admin"
66704
+ },
66705
+ "actions.update": {
66706
+ capName: "actions",
66707
+ capScope: "system",
66708
+ addonId: null,
66709
+ access: "create",
66710
+ role: "admin"
66711
+ },
66712
+ "actionSource.listActions": {
66713
+ capName: "action-source",
66714
+ capScope: "system",
66715
+ addonId: null,
66716
+ access: "view",
66717
+ role: "admin"
66718
+ },
66719
+ "actionSource.runAction": {
66720
+ capName: "action-source",
66721
+ capScope: "system",
66722
+ addonId: null,
66723
+ access: "create",
66724
+ role: "admin"
66725
+ },
66726
+ "actionSource.stopAction": {
66727
+ capName: "action-source",
66728
+ capScope: "system",
66729
+ addonId: null,
66730
+ access: "create",
66731
+ role: "admin"
66732
+ },
66181
66733
  "addonPages.listPages": {
66182
66734
  capName: "addon-pages",
66183
66735
  capScope: "system",
@@ -67459,6 +68011,13 @@ Object.freeze({
67459
68011
  access: "view",
67460
68012
  role: "admin"
67461
68013
  },
68014
+ "coreBlocks.getAutomationRunState": {
68015
+ capName: "core-blocks",
68016
+ capScope: "system",
68017
+ addonId: null,
68018
+ access: "view",
68019
+ role: "admin"
68020
+ },
67462
68021
  "coreBlocks.getBlockSettings": {
67463
68022
  capName: "core-blocks",
67464
68023
  capScope: "system",
@@ -67480,6 +68039,13 @@ Object.freeze({
67480
68039
  access: "view",
67481
68040
  role: "admin"
67482
68041
  },
68042
+ "coreBlocks.getTraces": {
68043
+ capName: "core-blocks",
68044
+ capScope: "system",
68045
+ addonId: null,
68046
+ access: "view",
68047
+ role: "admin"
68048
+ },
67483
68049
  "coreBlocks.getTypeDefs": {
67484
68050
  capName: "core-blocks",
67485
68051
  capScope: "system",
@@ -67515,6 +68081,13 @@ Object.freeze({
67515
68081
  access: "create",
67516
68082
  role: "admin"
67517
68083
  },
68084
+ "coreBlocks.reportAutomationRun": {
68085
+ capName: "core-blocks",
68086
+ capScope: "system",
68087
+ addonId: null,
68088
+ access: "create",
68089
+ role: "admin"
68090
+ },
67518
68091
  "coreBlocks.restart": {
67519
68092
  capName: "core-blocks",
67520
68093
  capScope: "system",
@@ -79669,6 +80242,8 @@ var ML = "model and training machinery — no device action";
79669
80242
  var INTERNAL = "internal plumbing between addons — never operator-facing";
79670
80243
  /** Every system-scoped cap, with why it is not a device's vocabulary. */
79671
80244
  var SYSTEM_CAP_VOCABULARY = {
80245
+ "action-source": system(INTERNAL),
80246
+ actions: system("declared actions — run from the Actions page and from the cameras that link them"),
79672
80247
  "addon-pages": system(UI_PLUMBING),
79673
80248
  "addon-pages-source": system(UI_PLUMBING),
79674
80249
  "addon-routes": system(UI_PLUMBING),
@@ -79865,6 +80440,31 @@ Object.freeze({
79865
80440
  form: "single",
79866
80441
  optional: false
79867
80442
  }],
80443
+ "actions.get": [{
80444
+ name: "deviceId",
80445
+ form: "single",
80446
+ optional: true
80447
+ }],
80448
+ "actions.getLinks": [{
80449
+ name: "deviceId",
80450
+ form: "single",
80451
+ optional: false
80452
+ }],
80453
+ "actions.listForCamera": [{
80454
+ name: "deviceId",
80455
+ form: "single",
80456
+ optional: false
80457
+ }],
80458
+ "actions.run": [{
80459
+ name: "deviceId",
80460
+ form: "single",
80461
+ optional: true
80462
+ }],
80463
+ "actions.setLinks": [{
80464
+ name: "deviceId",
80465
+ form: "single",
80466
+ optional: false
80467
+ }],
79868
80468
  "addonSettings.getDeviceSettings": [{
79869
80469
  name: "deviceId",
79870
80470
  form: "single",