@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
@@ -1,5 +1,5 @@
1
1
  import "node:crypto";
2
- //#region ../types/dist/event-category-CT-hz5Rb.mjs
2
+ //#region ../types/dist/event-category-hdMR7CTW.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -764,6 +764,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
764
764
  */
765
765
  EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
766
766
  /**
767
+ * An action run started or ended. Emitted by the `actions` surface.
768
+ * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
769
+ */
770
+ EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
771
+ /**
767
772
  * Progress update from a running model conversion job.
768
773
  * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
769
774
  * Emitted by `addon-model-studio` on the converting node.
@@ -5575,7 +5580,7 @@ var ZodIssueCode = {
5575
5580
  var ZodFirstPartyTypeKind;
5576
5581
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5577
5582
  //#endregion
5578
- //#region ../types/dist/sleep--jXS9hWo.mjs
5583
+ //#region ../types/dist/sleep-BHjNez61.mjs
5579
5584
  /**
5580
5585
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5581
5586
  * window to float samples (D455).
@@ -8872,6 +8877,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
8872
8877
  /** Every capability name, so addon code can check a name without the schema graph. */
8873
8878
  var CAP_NAMES = Object.freeze([
8874
8879
  "accessories",
8880
+ "action-source",
8881
+ "actions",
8875
8882
  "addon-pages",
8876
8883
  "addon-pages-source",
8877
8884
  "addon-routes",
@@ -10174,6 +10181,18 @@ Object.freeze({
10174
10181
  "path": "foodLevel",
10175
10182
  "valueType": "number"
10176
10183
  },
10184
+ {
10185
+ "path": "bowlFood",
10186
+ "valueType": "number"
10187
+ },
10188
+ {
10189
+ "path": "eating",
10190
+ "valueType": "boolean"
10191
+ },
10192
+ {
10193
+ "path": "supportsMarkRefilled",
10194
+ "valueType": "boolean"
10195
+ },
10177
10196
  {
10178
10197
  "path": "food1",
10179
10198
  "valueType": "number"
@@ -15738,7 +15757,23 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15738
15757
  kind: literal("schedule"),
15739
15758
  cron: string().min(1).max(120)
15740
15759
  }),
15741
- object({ kind: literal("manual") })
15760
+ object({ kind: literal("manual") }),
15761
+ object({
15762
+ kind: literal("detection"),
15763
+ /** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
15764
+ * matches every raw class that maps to it; any other name matches
15765
+ * exactly. */
15766
+ classes: array(string().min(1)).min(1),
15767
+ deviceIds: array(number().int().nonnegative()).min(1),
15768
+ /** The track must have visited at least one of these zones. */
15769
+ zones: array(string().min(1)).min(1).optional(),
15770
+ /** Best-so-far confidence the track must reach. */
15771
+ minScore: number().min(0).max(1).optional()
15772
+ }),
15773
+ object({
15774
+ kind: literal("interval"),
15775
+ minutes: number().int().min(1).max(1440)
15776
+ })
15742
15777
  ]);
15743
15778
  /**
15744
15779
  * One action step.
@@ -15758,28 +15793,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15758
15793
  * is called. The runner still receives a number and is untouched; the
15759
15794
  * resolution is the recipe's job, not the runner's.
15760
15795
  */
15796
+ var AutomationWaitStepSchema = object({
15797
+ kind: literal("wait"),
15798
+ seconds: number().min(0).max(300)
15799
+ });
15800
+ var AutomationCapStepSchema = object({
15801
+ kind: literal("cap"),
15802
+ /**
15803
+ * One device, several same-family devices (locks / climate family / …),
15804
+ * or `{ $var }` for the device that triggered the run. An array is
15805
+ * fan-out at codegen — each id gets the same cap.method call.
15806
+ */
15807
+ deviceId: union([
15808
+ number().int(),
15809
+ array(number().int()).min(1),
15810
+ object({ $var: string().min(1) })
15811
+ ]),
15812
+ cap: string().min(1),
15813
+ method: string().min(1),
15814
+ /** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
15815
+ * SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
15816
+ * the expression leaf. */
15817
+ args: record(string(), unknown()).optional()
15818
+ });
15819
+ /**
15820
+ * The steps an internal Action may contain: cap and wait, and nothing that can
15821
+ * call back into an Action — so an Action can never reach itself (no cycles).
15822
+ */
15823
+ var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
15761
15824
  var AutomationActionSchema = discriminatedUnion("kind", [
15825
+ AutomationWaitStepSchema,
15826
+ AutomationCapStepSchema,
15762
15827
  object({
15763
- kind: literal("wait"),
15764
- seconds: number().min(0).max(300)
15765
- }),
15766
- object({
15767
- kind: literal("cap"),
15768
- /**
15769
- * One device, several same-family devices (locks / climate family / …),
15770
- * or `{ $var }` for the device that triggered the run. An array is
15771
- * fan-out at codegen — each id gets the same cap.method call.
15772
- */
15773
- deviceId: union([
15774
- number().int(),
15775
- array(number().int()).min(1),
15776
- object({ $var: string().min(1) })
15777
- ]),
15778
- cap: string().min(1),
15779
- method: string().min(1),
15780
- /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
15781
- * evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
15782
- args: record(string(), unknown()).optional()
15828
+ kind: literal("action"),
15829
+ /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
15830
+ actionId: string().min(1),
15831
+ /** Values for the action's declared variables; the others take their default. */
15832
+ variables: record(string(), union([
15833
+ string(),
15834
+ number(),
15835
+ boolean()
15836
+ ])).optional()
15783
15837
  }),
15784
15838
  object({
15785
15839
  kind: literal("code"),
@@ -15788,10 +15842,356 @@ var AutomationActionSchema = discriminatedUnion("kind", [
15788
15842
  code: string().min(1).max(2e4)
15789
15843
  })
15790
15844
  ]);
15845
+ /**
15846
+ * How a trigger that arrives while the automation is busy (or cooling down) is
15847
+ * handled. One of the automation's execution modes, never a property of its
15848
+ * actions. Absent means `single`.
15849
+ *
15850
+ * - `single` — drop the trigger while a run is in progress (traced + logged).
15851
+ * - `restart` — abort the run in progress (at its next step boundary), start fresh.
15852
+ * - `queued` — queue up to `max` triggers, drop the rest (traced).
15853
+ * - `parallel` — up to `max` runs at once, drop the rest (traced).
15854
+ * - `cooldown` — `single`, and no new run until `minutes` after the last run
15855
+ * STARTED; persisted across a restart. A manual trigger bypasses only this
15856
+ * wait, never the single/queued limits.
15857
+ */
15858
+ var AutomationRunModeSchema = discriminatedUnion("mode", [
15859
+ object({ mode: literal("single") }),
15860
+ object({ mode: literal("restart") }),
15861
+ object({
15862
+ mode: literal("queued"),
15863
+ max: number().int().min(1).max(10)
15864
+ }),
15865
+ object({
15866
+ mode: literal("parallel"),
15867
+ max: number().int().min(1).max(10)
15868
+ }),
15869
+ object({
15870
+ mode: literal("cooldown"),
15871
+ minutes: number().int().min(1).max(1440)
15872
+ })
15873
+ ]);
15791
15874
  var AutomationRecipeSchema = object({
15792
15875
  triggers: array(AutomationTriggerSchema),
15793
15876
  conditions: AutomationConditionSchema.optional(),
15794
- actions: array(AutomationActionSchema)
15877
+ actions: array(AutomationActionSchema),
15878
+ runMode: AutomationRunModeSchema.optional(),
15879
+ /** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
15880
+ keepTraces: number().int().min(1).max(100).optional()
15881
+ });
15882
+ new Set([
15883
+ {
15884
+ id: "person",
15885
+ name: "Person"
15886
+ },
15887
+ {
15888
+ id: "vehicle",
15889
+ name: "Vehicle"
15890
+ },
15891
+ {
15892
+ id: "animal",
15893
+ name: "Animal"
15894
+ },
15895
+ {
15896
+ id: "package",
15897
+ name: "Package"
15898
+ }
15899
+ ].map((l) => l.id));
15900
+ var COCO_TO_MACRO = {
15901
+ mapping: {
15902
+ person: "person",
15903
+ bicycle: "vehicle",
15904
+ car: "vehicle",
15905
+ motorcycle: "vehicle",
15906
+ airplane: "vehicle",
15907
+ bus: "vehicle",
15908
+ train: "vehicle",
15909
+ truck: "vehicle",
15910
+ boat: "vehicle",
15911
+ bird: "animal",
15912
+ cat: "animal",
15913
+ dog: "animal",
15914
+ horse: "animal",
15915
+ sheep: "animal",
15916
+ cow: "animal",
15917
+ elephant: "animal",
15918
+ bear: "animal",
15919
+ zebra: "animal",
15920
+ giraffe: "animal",
15921
+ suitcase: "package",
15922
+ backpack: "package",
15923
+ handbag: "package"
15924
+ },
15925
+ preserveOriginal: false
15926
+ };
15927
+ new Set(Object.values(COCO_TO_MACRO.mapping));
15928
+ /**
15929
+ * Run traces — what an automation (or, later, an Action run) DID, node by node,
15930
+ * so the editor can paint every block green or red with its reason.
15931
+ *
15932
+ * A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
15933
+ * every condition node (containers and leaves, including the ones a
15934
+ * short-circuit never reached), the run-mode verdict and every action step —
15935
+ * each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
15936
+ * for an Action run). Skipped
15937
+ * evaluations are traced too, and identical consecutive skips collapse into a
15938
+ * repeat count so a trigger that fails every 5 minutes cannot flush real runs.
15939
+ *
15940
+ * {@link AutomationStepTraceSchema} is deliberately free of automation
15941
+ * vocabulary so an Action run records the same step shape.
15942
+ */
15943
+ /** A value a trace may show: JSON primitives and short lists, nothing deeper. */
15944
+ var TraceValueSchema = union([
15945
+ string(),
15946
+ number(),
15947
+ boolean(),
15948
+ _null(),
15949
+ array(union([string(), number()]))
15950
+ ]);
15951
+ var AutomationRunOutcomeSchema = _enum([
15952
+ "ran",
15953
+ "skipped-trigger",
15954
+ "skipped-conditions",
15955
+ "skipped-cooldown",
15956
+ "skipped-overlap",
15957
+ "failed",
15958
+ "aborted"
15959
+ ]);
15960
+ /** `not-evaluated` = a short-circuit never reached the node. */
15961
+ var TraceNodeOutcomeSchema = _enum([
15962
+ "pass",
15963
+ "fail",
15964
+ "not-evaluated"
15965
+ ]);
15966
+ var AutomationTriggerTraceSchema = object({
15967
+ kind: string().min(1),
15968
+ outcome: _enum(["pass", "fail"]),
15969
+ /** Why an event was rejected ("class person not in [dog]") or what fired. */
15970
+ reason: string(),
15971
+ /** deviceId, className, trackId, score … — only what the trigger exposes. */
15972
+ vars: record(string(), TraceValueSchema)
15973
+ });
15974
+ var AutomationConditionTraceNodeSchema = object({
15975
+ /** `conditions` for the root, `conditions.<i>` for its i-th child, … */
15976
+ path: string().min(1),
15977
+ kind: _enum([
15978
+ "all",
15979
+ "any",
15980
+ "not",
15981
+ "condition",
15982
+ "expression"
15983
+ ]),
15984
+ outcome: TraceNodeOutcomeSchema,
15985
+ reason: string(),
15986
+ deviceId: number().int().optional(),
15987
+ cap: string().optional(),
15988
+ fieldPath: string().optional(),
15989
+ operator: string().optional(),
15990
+ expected: TraceValueSchema.optional(),
15991
+ /** What the mirror held; `null` when it held nothing (unknown). */
15992
+ observed: TraceValueSchema.optional()
15993
+ });
15994
+ var AutomationRunVerdictSchema = object({
15995
+ mode: AutomationRunModeSchema,
15996
+ decision: _enum([
15997
+ "run",
15998
+ "queued",
15999
+ "restart",
16000
+ "drop",
16001
+ "cooldown",
16002
+ "bypass"
16003
+ ]),
16004
+ reason: string()
16005
+ });
16006
+ /** One executed (or not-run) step — shared by automations and Action runs. */
16007
+ var AutomationStepTraceSchema = object({
16008
+ /** `actions.<i>` */
16009
+ path: string().min(1),
16010
+ kind: string().min(1),
16011
+ cap: string().optional(),
16012
+ method: string().optional(),
16013
+ deviceId: number().int().optional(),
16014
+ startedAt: number().optional(),
16015
+ endedAt: number().optional(),
16016
+ outcome: _enum([
16017
+ "ok",
16018
+ "error",
16019
+ "not-run"
16020
+ ]),
16021
+ message: string().optional()
16022
+ });
16023
+ var AutomationRunTraceSchema = object({
16024
+ runId: string().min(1),
16025
+ startedAt: number(),
16026
+ endedAt: number(),
16027
+ trigger: AutomationTriggerTraceSchema,
16028
+ conditions: array(AutomationConditionTraceNodeSchema),
16029
+ verdict: AutomationRunVerdictSchema.optional(),
16030
+ steps: array(AutomationStepTraceSchema),
16031
+ outcome: AutomationRunOutcomeSchema,
16032
+ /** How many identical consecutive skips this trace stands for (>= 1). */
16033
+ repeat: number().int().min(1),
16034
+ /** When the latest of those repeats happened. */
16035
+ lastAt: number()
16036
+ });
16037
+ /**
16038
+ * What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
16039
+ * `action:<actionId>`): the cooldown stamp and the trace ring.
16040
+ */
16041
+ var AutomationStateDocSchema = object({
16042
+ version: literal(1),
16043
+ lastRunStartedAt: number().nullable(),
16044
+ traces: array(AutomationRunTraceSchema)
16045
+ });
16046
+ /**
16047
+ * Actions — named, runnable things an operator (or an automation) can start,
16048
+ * declared as LIST ENTRIES, never as devices.
16049
+ *
16050
+ * An entry is either **internal** (a short list of cap/wait steps kept in the
16051
+ * hub's `actions` record kind) or declared by an addon through the
16052
+ * `action-source` collection (a Home Assistant script, a scene …). The one
16053
+ * surface the UI and automations talk to is the `actions` cap; it keeps no
16054
+ * catalog of its own (D3) — every `list` asks the providers live.
16055
+ *
16056
+ * This file is the data half: the entry schema, the variables an entry may
16057
+ * declare, and the pure resolution of the values a run was given. It holds no
16058
+ * runtime.
16059
+ */
16060
+ /** What a variable's value is. `select` takes one of `options`. */
16061
+ var ActionVariableTypeSchema = _enum([
16062
+ "string",
16063
+ "number",
16064
+ "boolean",
16065
+ "select"
16066
+ ]);
16067
+ var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
16068
+ var ActionVariableValueSchema = union([
16069
+ string(),
16070
+ number(),
16071
+ boolean()
16072
+ ]);
16073
+ /**
16074
+ * One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
16075
+ * value) or `{{vars.name}}` (inside a string) in their args.
16076
+ */
16077
+ var ActionVariableSchema = object({
16078
+ name: string().regex(ACTION_VARIABLE_NAME_RE),
16079
+ label: string().min(1).max(120).optional(),
16080
+ type: ActionVariableTypeSchema,
16081
+ required: boolean().optional(),
16082
+ default: ActionVariableValueSchema.optional(),
16083
+ /** The allowed values of a `select`. */
16084
+ options: array(string().min(1)).min(1).optional()
16085
+ }).superRefine((v, ctx) => {
16086
+ if (v.type === "select" && v.options === void 0) ctx.addIssue({
16087
+ code: "custom",
16088
+ message: "a select variable needs options",
16089
+ path: ["options"]
16090
+ });
16091
+ if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
16092
+ code: "custom",
16093
+ message: variableValueError(v, v.default) ?? "invalid default",
16094
+ path: ["default"]
16095
+ });
16096
+ });
16097
+ /** Why `value` is not a legal value for the variable, or null when it is. */
16098
+ function variableValueError(variable, value) {
16099
+ switch (variable.type) {
16100
+ case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
16101
+ case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
16102
+ case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
16103
+ case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
16104
+ }
16105
+ }
16106
+ var ActionSourceKindSchema = _enum(["internal", "addon"]);
16107
+ function isInternalActionId(actionId) {
16108
+ return actionId.startsWith("internal:") && actionId.length > 9;
16109
+ }
16110
+ /** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
16111
+ function addonIdOfActionId(actionId) {
16112
+ if (isInternalActionId(actionId)) return null;
16113
+ const at = actionId.indexOf(":");
16114
+ return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
16115
+ }
16116
+ var ActionStatusSchema = object({
16117
+ isRunning: boolean(),
16118
+ /** Ms epoch the latest run STARTED; null when it never ran. */
16119
+ lastRunAt: number().nullable(),
16120
+ /** The latest run's failure; null on success or when it never ran. */
16121
+ lastError: string().nullable()
16122
+ });
16123
+ var ActionEntrySchema = object({
16124
+ /** `internal:<uuid>` or `<addonId>:<localId>`. */
16125
+ id: string().min(3),
16126
+ name: string().min(1).max(120),
16127
+ /** The addon that declared it; `core-blocks` for an internal one. */
16128
+ addonId: string().min(1),
16129
+ source: ActionSourceKindSchema,
16130
+ /** An addon-declared entry is edited where it was declared. */
16131
+ readOnly: boolean(),
16132
+ /** Internal only: cap and wait steps. No action-in-action, so no cycles. */
16133
+ steps: array(ActionStepSchema).min(1).max(50).optional(),
16134
+ variables: array(ActionVariableSchema).max(20).optional(),
16135
+ status: ActionStatusSchema
16136
+ }).superRefine((entry, ctx) => {
16137
+ if (entry.source === "internal") {
16138
+ if (!isInternalActionId(entry.id)) ctx.addIssue({
16139
+ code: "custom",
16140
+ message: "an internal action id is internal:<uuid>",
16141
+ path: ["id"]
16142
+ });
16143
+ return;
16144
+ }
16145
+ if (entry.steps !== void 0) ctx.addIssue({
16146
+ code: "custom",
16147
+ message: "only an internal action carries steps",
16148
+ path: ["steps"]
16149
+ });
16150
+ if (!entry.readOnly) ctx.addIssue({
16151
+ code: "custom",
16152
+ message: "an addon action is read-only here",
16153
+ path: ["readOnly"]
16154
+ });
16155
+ if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
16156
+ code: "custom",
16157
+ message: "an addon action id is <addonId>:<localId>",
16158
+ path: ["id"]
16159
+ });
16160
+ });
16161
+ /** What an operator writes for an internal action. */
16162
+ var ActionInputSchema = object({
16163
+ name: string().min(1).max(120),
16164
+ steps: array(ActionStepSchema).min(1).max(50),
16165
+ variables: array(ActionVariableSchema).max(20).optional()
16166
+ });
16167
+ /** Who started a run. Absent = the operator pressed it. */
16168
+ var ActionRunOriginSchema = object({
16169
+ /** The automation block whose step started it. */
16170
+ blockId: string().min(1).optional() });
16171
+ /** `started` = the caller did not ask to wait. */
16172
+ var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
16173
+ var ActionRunResultSchema = object({
16174
+ runId: string().min(1),
16175
+ outcome: ActionRunOutcomeSchema,
16176
+ /** Why it did not run, or what failed. */
16177
+ message: string().optional()
16178
+ });
16179
+ _enum([
16180
+ "not-found",
16181
+ "read-only",
16182
+ "invalid-variables",
16183
+ "invalid-steps",
16184
+ "not-linked",
16185
+ "busy"
16186
+ ]);
16187
+ object({
16188
+ actionId: string(),
16189
+ runId: string(),
16190
+ isRunning: boolean(),
16191
+ /** Set when the run ended. */
16192
+ outcome: AutomationRunOutcomeSchema.optional(),
16193
+ lastRunAt: number().nullable(),
16194
+ lastError: string().nullable()
15795
16195
  });
15796
16196
  /**
15797
16197
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
@@ -19352,7 +19752,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
19352
19752
  kind: "mutation",
19353
19753
  auth: "admin",
19354
19754
  access: "view"
19355
- });
19755
+ }), method(object({
19756
+ blockId: string().min(1),
19757
+ trace: AutomationRunTraceSchema.optional(),
19758
+ runStartedAt: number().optional(),
19759
+ keepTraces: number().int().min(1).max(100).optional()
19760
+ }), _void(), {
19761
+ kind: "mutation",
19762
+ auth: "admin"
19763
+ }), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
19764
+ traces: array(AutomationRunTraceSchema),
19765
+ lastError: string().nullable()
19766
+ }), { auth: "admin" });
19356
19767
  /**
19357
19768
  * `custom-model-registry` — collection cap exposing operator-registered
19358
19769
  * custom detection models. Each provider (today: `addon-model-studio`)
@@ -44445,51 +44856,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
44445
44856
  kind: "mutation",
44446
44857
  auth: "admin"
44447
44858
  });
44448
- new Set([
44449
- {
44450
- id: "person",
44451
- name: "Person"
44452
- },
44453
- {
44454
- id: "vehicle",
44455
- name: "Vehicle"
44456
- },
44457
- {
44458
- id: "animal",
44459
- name: "Animal"
44460
- },
44461
- {
44462
- id: "package",
44463
- name: "Package"
44464
- }
44465
- ].map((l) => l.id));
44466
- var COCO_TO_MACRO = {
44467
- mapping: {
44468
- person: "person",
44469
- bicycle: "vehicle",
44470
- car: "vehicle",
44471
- motorcycle: "vehicle",
44472
- airplane: "vehicle",
44473
- bus: "vehicle",
44474
- train: "vehicle",
44475
- truck: "vehicle",
44476
- boat: "vehicle",
44477
- bird: "animal",
44478
- cat: "animal",
44479
- dog: "animal",
44480
- horse: "animal",
44481
- sheep: "animal",
44482
- cow: "animal",
44483
- elephant: "animal",
44484
- bear: "animal",
44485
- zebra: "animal",
44486
- giraffe: "animal",
44487
- suitcase: "package",
44488
- backpack: "package",
44489
- handbag: "package"
44490
- },
44491
- preserveOriginal: false
44492
- };
44493
44859
  var AUDIO_MACRO_LABELS = [
44494
44860
  {
44495
44861
  id: "speech",
@@ -57038,6 +57404,84 @@ DeviceType.Camera, method(object({ deviceId: number() }), AudioMetricsSnapshotSc
57038
57404
  * would produce more than `maxPoints` samples. */
57039
57405
  sampleEveryMs: number().int().positive().optional()
57040
57406
  }), AudioMetricsHistorySchema);
57407
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57408
+ actionId: string().min(1),
57409
+ variables: record(string(), ActionVariableValueSchema).optional()
57410
+ }), _void(), {
57411
+ kind: "mutation",
57412
+ auth: "admin"
57413
+ }), method(object({ actionId: string().min(1) }), _void(), {
57414
+ kind: "mutation",
57415
+ auth: "admin"
57416
+ });
57417
+ /**
57418
+ * actions — the ONE surface for runnable actions, for the UI and for
57419
+ * automations. Provided by the core-blocks builtin on the hub.
57420
+ *
57421
+ * An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
57422
+ * steps, kept in the hub's `actions` record kind) or declared by an addon over
57423
+ * `action-source`. `list` asks every `action-source` provider LIVE and overlays
57424
+ * the run status from the hub's `runs` ledger; there is no catalog here to
57425
+ * drift (D3).
57426
+ *
57427
+ * **Permissions follow the camera, as linked devices do.** An action is linked
57428
+ * to cameras by the operator (`setLinks`, D356: nothing links itself). A
57429
+ * non-admin may `get` / `run` an action only through a camera they may see that
57430
+ * links it: they name the camera (`deviceId`, a top-level field so the scope
57431
+ * gate sees it) and the provider refuses an action that camera does not link.
57432
+ * An admin, and an in-process caller (an automation block), may run any action.
57433
+ * Every refusal is typed (`[not-linked] …`) and logged.
57434
+ *
57435
+ * A second `run` of an action that is already running is REFUSED — traced and
57436
+ * logged — never queued.
57437
+ */
57438
+ var ActionIdInput = object({ actionId: string().min(1) });
57439
+ var ActionLinksSchema = object({
57440
+ deviceId: number().int().nonnegative(),
57441
+ actionIds: array(string().min(1)).max(100)
57442
+ });
57443
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57444
+ actionId: string().min(1),
57445
+ deviceId: number().int().nonnegative().optional()
57446
+ }), object({ action: ActionEntrySchema.nullable() }), {
57447
+ role: "viewer",
57448
+ auth: "protected",
57449
+ kind: "query",
57450
+ caller: "required"
57451
+ }), method(object({
57452
+ actionId: string().min(1),
57453
+ variables: record(string(), ActionVariableValueSchema).optional(),
57454
+ wait: boolean().optional(),
57455
+ origin: ActionRunOriginSchema.optional(),
57456
+ deviceId: number().int().nonnegative().optional()
57457
+ }), ActionRunResultSchema, {
57458
+ role: "viewer",
57459
+ auth: "protected",
57460
+ kind: "mutation",
57461
+ caller: "required"
57462
+ }), method(ActionIdInput, _void(), {
57463
+ kind: "mutation",
57464
+ auth: "admin"
57465
+ }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
57466
+ kind: "mutation",
57467
+ auth: "admin"
57468
+ }), method(object({
57469
+ actionId: string().min(1),
57470
+ action: ActionInputSchema.partial()
57471
+ }), object({ action: ActionEntrySchema }), {
57472
+ kind: "mutation",
57473
+ auth: "admin"
57474
+ }), method(ActionIdInput, _void(), {
57475
+ kind: "mutation",
57476
+ auth: "admin"
57477
+ }), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
57478
+ role: "viewer",
57479
+ auth: "protected",
57480
+ kind: "query"
57481
+ }), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
57482
+ kind: "mutation",
57483
+ auth: "admin"
57484
+ });
57041
57485
  object({
57042
57486
  /** Whether the automation is currently enabled. Disabled automations
57043
57487
  * ignore their trigger block — manual `trigger` still works. */
@@ -61283,10 +61727,20 @@ var PetFeederDeviceStatusSchema = _enum([
61283
61727
  ]);
61284
61728
  var gramsPortion = number().int().min(4).max(200);
61285
61729
  object({
61286
- /** Food currently in the bowl (grams). Null when the device has not
61287
- * reported a reading yet. On dual-hopper models this is the combined
61288
- * bowl reading; per-hopper levels live in `food1`/`food2`. */
61730
+ /** Food in the TANK (hopper), as the feeder's own sensor reports it
61731
+ * (`state.food`). A coarse level code, not grams — `0` is empty. The
61732
+ * amount in the bowl is `bowlFood`. On dual-hopper models this is the
61733
+ * combined reading; per-hopper levels live in `food1`/`food2`. Null when
61734
+ * the device has not reported yet. */
61289
61735
  foodLevel: number().nullable().meta(readingMeta("none")),
61736
+ /** Food in the BOWL as the feeder reports it (`state.bowl`), in the
61737
+ * feeder's own units. Null when the model reports none. */
61738
+ bowlFood: number().nullable().meta(readingMeta("none")),
61739
+ /** True while the pet is eating (`state.eating`). */
61740
+ eating: boolean(),
61741
+ /** Whether `markFoodReplenished` does anything on this model. When false
61742
+ * the client must not offer it. */
61743
+ supportsMarkRefilled: boolean(),
61290
61744
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
61291
61745
  * single-hopper models. */
61292
61746
  food1: number().nullable().meta(readingMeta("none")),
@@ -61294,8 +61748,8 @@ object({
61294
61748
  * single-hopper models. */
61295
61749
  food2: number().nullable().meta(readingMeta("none")),
61296
61750
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
61297
- * (`device_class: problem`, on = low). True when the bowl is empty /
61298
- * below the feeder's low threshold. */
61751
+ * (`device_class: problem`, on = low). True when the tank reports empty,
61752
+ * or, on a dual-hopper model, when EITHER hopper is empty. */
61299
61753
  lowFood: boolean(),
61300
61754
  /** Battery charge 0..100 (%). Null on mains-powered models or when the
61301
61755
  * device has no battery reading. */
@@ -66145,6 +66599,104 @@ Object.freeze({
66145
66599
  access: "create",
66146
66600
  role: "admin"
66147
66601
  },
66602
+ "actions.create": {
66603
+ capName: "actions",
66604
+ capScope: "system",
66605
+ addonId: null,
66606
+ access: "create",
66607
+ role: "admin"
66608
+ },
66609
+ "actions.delete": {
66610
+ capName: "actions",
66611
+ capScope: "system",
66612
+ addonId: null,
66613
+ access: "delete",
66614
+ role: "admin"
66615
+ },
66616
+ "actions.get": {
66617
+ capName: "actions",
66618
+ capScope: "system",
66619
+ addonId: null,
66620
+ access: "view",
66621
+ role: "viewer"
66622
+ },
66623
+ "actions.getLinks": {
66624
+ capName: "actions",
66625
+ capScope: "system",
66626
+ addonId: null,
66627
+ access: "view",
66628
+ role: "admin"
66629
+ },
66630
+ "actions.getTraces": {
66631
+ capName: "actions",
66632
+ capScope: "system",
66633
+ addonId: null,
66634
+ access: "view",
66635
+ role: "admin"
66636
+ },
66637
+ "actions.list": {
66638
+ capName: "actions",
66639
+ capScope: "system",
66640
+ addonId: null,
66641
+ access: "view",
66642
+ role: "admin"
66643
+ },
66644
+ "actions.listForCamera": {
66645
+ capName: "actions",
66646
+ capScope: "system",
66647
+ addonId: null,
66648
+ access: "view",
66649
+ role: "viewer"
66650
+ },
66651
+ "actions.run": {
66652
+ capName: "actions",
66653
+ capScope: "system",
66654
+ addonId: null,
66655
+ access: "create",
66656
+ role: "viewer"
66657
+ },
66658
+ "actions.setLinks": {
66659
+ capName: "actions",
66660
+ capScope: "system",
66661
+ addonId: null,
66662
+ access: "create",
66663
+ role: "admin"
66664
+ },
66665
+ "actions.stop": {
66666
+ capName: "actions",
66667
+ capScope: "system",
66668
+ addonId: null,
66669
+ access: "create",
66670
+ role: "admin"
66671
+ },
66672
+ "actions.update": {
66673
+ capName: "actions",
66674
+ capScope: "system",
66675
+ addonId: null,
66676
+ access: "create",
66677
+ role: "admin"
66678
+ },
66679
+ "actionSource.listActions": {
66680
+ capName: "action-source",
66681
+ capScope: "system",
66682
+ addonId: null,
66683
+ access: "view",
66684
+ role: "admin"
66685
+ },
66686
+ "actionSource.runAction": {
66687
+ capName: "action-source",
66688
+ capScope: "system",
66689
+ addonId: null,
66690
+ access: "create",
66691
+ role: "admin"
66692
+ },
66693
+ "actionSource.stopAction": {
66694
+ capName: "action-source",
66695
+ capScope: "system",
66696
+ addonId: null,
66697
+ access: "create",
66698
+ role: "admin"
66699
+ },
66148
66700
  "addonPages.listPages": {
66149
66701
  capName: "addon-pages",
66150
66702
  capScope: "system",
@@ -67426,6 +67978,13 @@ Object.freeze({
67426
67978
  access: "view",
67427
67979
  role: "admin"
67428
67980
  },
67981
+ "coreBlocks.getAutomationRunState": {
67982
+ capName: "core-blocks",
67983
+ capScope: "system",
67984
+ addonId: null,
67985
+ access: "view",
67986
+ role: "admin"
67987
+ },
67429
67988
  "coreBlocks.getBlockSettings": {
67430
67989
  capName: "core-blocks",
67431
67990
  capScope: "system",
@@ -67447,6 +68006,13 @@ Object.freeze({
67447
68006
  access: "view",
67448
68007
  role: "admin"
67449
68008
  },
68009
+ "coreBlocks.getTraces": {
68010
+ capName: "core-blocks",
68011
+ capScope: "system",
68012
+ addonId: null,
68013
+ access: "view",
68014
+ role: "admin"
68015
+ },
67450
68016
  "coreBlocks.getTypeDefs": {
67451
68017
  capName: "core-blocks",
67452
68018
  capScope: "system",
@@ -67482,6 +68048,13 @@ Object.freeze({
67482
68048
  access: "create",
67483
68049
  role: "admin"
67484
68050
  },
68051
+ "coreBlocks.reportAutomationRun": {
68052
+ capName: "core-blocks",
68053
+ capScope: "system",
68054
+ addonId: null,
68055
+ access: "create",
68056
+ role: "admin"
68057
+ },
67485
68058
  "coreBlocks.restart": {
67486
68059
  capName: "core-blocks",
67487
68060
  capScope: "system",
@@ -79636,6 +80209,8 @@ var ML = "model and training machinery — no device action";
79636
80209
  var INTERNAL = "internal plumbing between addons — never operator-facing";
79637
80210
  /** Every system-scoped cap, with why it is not a device's vocabulary. */
79638
80211
  var SYSTEM_CAP_VOCABULARY = {
80212
+ "action-source": system(INTERNAL),
80213
+ actions: system("declared actions — run from the Actions page and from the cameras that link them"),
79639
80214
  "addon-pages": system(UI_PLUMBING),
79640
80215
  "addon-pages-source": system(UI_PLUMBING),
79641
80216
  "addon-routes": system(UI_PLUMBING),
@@ -79832,6 +80407,31 @@ Object.freeze({
79832
80407
  form: "single",
79833
80408
  optional: false
79834
80409
  }],
80410
+ "actions.get": [{
80411
+ name: "deviceId",
80412
+ form: "single",
80413
+ optional: true
80414
+ }],
80415
+ "actions.getLinks": [{
80416
+ name: "deviceId",
80417
+ form: "single",
80418
+ optional: false
80419
+ }],
80420
+ "actions.listForCamera": [{
80421
+ name: "deviceId",
80422
+ form: "single",
80423
+ optional: false
80424
+ }],
80425
+ "actions.run": [{
80426
+ name: "deviceId",
80427
+ form: "single",
80428
+ optional: true
80429
+ }],
80430
+ "actions.setLinks": [{
80431
+ name: "deviceId",
80432
+ form: "single",
80433
+ optional: false
80434
+ }],
79835
80435
  "addonSettings.getDeviceSettings": [{
79836
80436
  name: "deviceId",
79837
80437
  form: "single",