@camstack/ui-library 1.2.244 → 1.2.245

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.
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { ThemeProvider, createTheme, darkColors, defaultTheme, lightColors, themeToCss, useThemeMode } from "./theme/index.js";
2
2
  import * as __mfHostReact from "react";
3
- import React, { Fragment, Suspense, createContext, createElement, forwardRef, lazy, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
3
+ import React, { Fragment, Suspense, createContext, createElement, forwardRef, lazy, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
4
4
  import * as __mfHostTrpcReactQuery from "@trpc/react-query";
5
5
  import { createTRPCReact } from "@trpc/react-query";
6
6
  import * as __mfHostReactJsxRuntime from "react/jsx-runtime";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import * as __mfHostReactDOM from "react-dom";
9
9
  import { createPortal } from "react-dom";
10
- import { ALL_CAPABILITY_DEFINITIONS, CAM_PROFILE_ORDER, CLIP_STILL_DISPOSITION_HEADER, CLIP_STILL_REASON_CODE_HEADER, CLIP_STILL_REASON_HEADER, CONTAINER_CHILD_PRIORITY, DEFAULT_EVENTS_BAND_BUFFER_SEC, DEFAULT_EVENT_COLOR, DEVICE_TYPE_CONTROL_KIND, DISPLAY_ICON_GROUPS, DeviceExportStatusSchema, DeviceFeature, DeviceRole, DeviceType, EVENT_TAXONOMY, EXTENSION_SLOTS, EXTENSION_SLOT_IDS, EventCategory, ExposedDeviceSchema, FIRST_LEVEL_MACRO_CLASSES, KNOWN_CAP_NAMES, MAX_SENSOR_TRIGGER_DEVICES, MODEL_PROVIDER_IDS, NAVIGATION_LIGHT_LEVEL_MAX, NAVIGATION_LIGHT_LEVEL_MIN, PET_FEEDER_MANUAL_FEED_MAX, PET_FEEDER_MANUAL_FEED_MIN, RECORDING_AUDIO_TRIGGER_OFFERED_DBFS, RECORDING_SOURCE_CAMSTACK_ADDON, RecordingConfigSchema, RecordingStatusSchema, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, TIMEZONES, USE_ROOT_MODEL_SETTING_KEY, buildModelVariantGroups, canConvertUnit, clearModelBoundOverrides, clearModelBoundSetting, clusterStepSettingFieldsFor, createDeviceProxy, createLazyTrpcSource, createSliceHandle, deriveRecordingMode, describeModelVariant, findTimezone, formatParkedFor, hasModelBoundOverrides, isRootSuppliableStepId, normalizeUnit, publicEventCategories, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveModelBoundSetting, resolveRecordingProfiles, resolveRootSupply, resolveVariantModelId, resolveViewableDeviceIds, searchDisplayIcons, selectAssignedProfileSlots, tryConvertUnit, unitsForDimension, writeModelBoundSetting } from "@camstack/types";
10
+ import { ALL_CAPABILITY_DEFINITIONS, CAM_PROFILE_ORDER, CLIP_STILL_DISPOSITION_HEADER, CLIP_STILL_REASON_CODE_HEADER, CLIP_STILL_REASON_HEADER, CONTAINER_CHILD_PRIORITY, DEFAULT_EVENTS_BAND_BUFFER_SEC, DEFAULT_EVENT_COLOR, DEVICE_TYPE_CONTROL_KIND, DISPLAY_ICON_GROUPS, DeviceExportStatusSchema, DeviceFeature, DeviceRole, DeviceType, EVENT_TAXONOMY, EXTENSION_SLOTS, EXTENSION_SLOT_IDS, EventCategory, ExposedDeviceSchema, FIRST_LEVEL_MACRO_CLASSES, KNOWN_CAP_NAMES, MAX_SENSOR_TRIGGER_DEVICES, MODEL_PROVIDER_IDS, NAVIGATION_LIGHT_LEVEL_MAX, NAVIGATION_LIGHT_LEVEL_MIN, PET_FEEDER_MANUAL_FEED_MAX, PET_FEEDER_MANUAL_FEED_MIN, RECORDING_AUDIO_TRIGGER_OFFERED_DBFS, RECORDING_SOURCE_CAMSTACK_ADDON, RecordingConfigSchema, RecordingStatusSchema, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, TIMEZONES, USE_ROOT_MODEL_SETTING_KEY, buildModelVariantGroups, canConvertUnit, clearModelBoundOverrides, clearModelBoundSetting, clusterStepSettingFieldsFor, collectModelBoundKeys, createDeviceProxy, createLazyTrpcSource, createSliceHandle, deriveRecordingMode, describeModelVariant, effectiveStepSettings, findTimezone, formatParkedFor, hasModelBoundOverrides, isRootSuppliableStepId, modelBindingKey, normalizeUnit, publicEventCategories, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveModelBoundSetting, resolveRecordingProfiles, resolveRootSupply, resolveVariantModelId, resolveViewableDeviceIds, searchDisplayIcons, selectAssignedProfileSlots, stepSettingSource, tryConvertUnit, unitsForDimension, withFieldFrom, withoutField, writeModelBoundSetting } from "@camstack/types";
11
11
  import * as __mfHostTanstackQuery from "@tanstack/react-query";
12
12
  import { QueryClient, QueryClientProvider, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
13
13
  import * as __mfHostReactDOMClient from "react-dom/client";
@@ -28722,32 +28722,6 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
28722
28722
  });
28723
28723
  }
28724
28724
  //#endregion
28725
- //#region src/primitives/collapsible-card.tsx
28726
- function CollapsibleCard({ expanded, onExpandedChange, header, children, dimmed = false, hideChevron = false, className }) {
28727
- return /* @__PURE__ */ jsxs("div", {
28728
- className: cn("rounded-lg border border-border bg-surface overflow-hidden", dimmed && "opacity-[0.45]", className),
28729
- children: [/* @__PURE__ */ jsxs("div", {
28730
- role: "button",
28731
- tabIndex: 0,
28732
- className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none",
28733
- onClick: () => onExpandedChange(!expanded),
28734
- onKeyDown: (e) => {
28735
- if (e.key === "Enter" || e.key === " ") {
28736
- e.preventDefault();
28737
- onExpandedChange(!expanded);
28738
- }
28739
- },
28740
- children: [!hideChevron && /* @__PURE__ */ jsx("span", {
28741
- className: "text-foreground-subtle shrink-0",
28742
- children: expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
28743
- }), header]
28744
- }), expanded && children && /* @__PURE__ */ jsx("div", {
28745
- className: "border-t border-border px-3 py-3",
28746
- children
28747
- })]
28748
- });
28749
- }
28750
- //#endregion
28751
28725
  //#region src/composites/grouped-model-selector.tsx
28752
28726
  /**
28753
28727
  * GroupedModelSelector — the shared Family → Tier → Variant model picker.
@@ -29028,6 +29002,257 @@ function ModelPicker({ models, value, onChange, disabled, defaultModelId }) {
29028
29002
  });
29029
29003
  }
29030
29004
  //#endregion
29005
+ //#region src/composites/resolve-step-default-model.ts
29006
+ function resolveStepDefaultModel(catalog, format) {
29007
+ const hasFormatBuild = (modelId) => catalog.models.find((m) => m.id === modelId)?.formats[format] !== void 0;
29008
+ const declared = catalog.defaultModelIdByFormat?.[format];
29009
+ if (declared !== void 0 && hasFormatBuild(declared)) return declared;
29010
+ if (hasFormatBuild(catalog.defaultModelId)) return catalog.defaultModelId;
29011
+ const available = catalog.models.filter((m) => m.formats[format] !== void 0 && m.legacy !== true);
29012
+ if (available.length === 0) return catalog.defaultModelId;
29013
+ return [...available].toSorted((a, b) => (a.formats[format]?.sizeMB ?? Infinity) - (b.formats[format]?.sizeMB ?? Infinity))[0].id;
29014
+ }
29015
+ /**
29016
+ * The model a matrix CELL shows as this step's effective default on `device`.
29017
+ *
29018
+ * The device's ELECTED model (`device.defaultModelId`, the per-device
29019
+ * object-detection election) applies ONLY when this step's catalog actually
29020
+ * contains it — `slot === 'detector'` alone is too wide, because
29021
+ * package-detection shares the detector slot with the root step. Bit live
29022
+ * 2026-08-08: rfdetr-package became the package step's default and every
29023
+ * matrix cell still showed the device's yolo as the "selected" model, because
29024
+ * the election was applied slot-wide. Membership is the principled gate: an
29025
+ * elected model this step cannot run is never displayed for it.
29026
+ */
29027
+ function resolveEffectiveDefaultModel(catalog, device) {
29028
+ const format = device?.format;
29029
+ if (format === void 0) return void 0;
29030
+ const elected = device?.defaultModelId;
29031
+ return catalog.slot === "detector" && elected !== void 0 && catalog.models.some((m) => m.id === elected) ? elected : resolveStepDefaultModel(catalog, format);
29032
+ }
29033
+ /**
29034
+ * The models a step may run on an engine `format` — the ONE derivation of the
29035
+ * option list. An unknown format yields NOTHING rather than everything: a
29036
+ * picker that offered a model with no build for the device would write a pin
29037
+ * the runner cannot honour.
29038
+ */
29039
+ function stepModelOptions(models, format) {
29040
+ if (format === void 0) return [];
29041
+ return models.filter((m) => m.formats[format] !== void 0);
29042
+ }
29043
+ /** Can this step run on `format` at all? (`false` ⇒ the caller renders "⚠ skip"/"—".) */
29044
+ function stepHasModelForFormat(models, format) {
29045
+ return stepModelOptions(models, format).length > 0;
29046
+ }
29047
+ /**
29048
+ * The model a step ACTUALLY runs for a (device, camera) — the whole effective
29049
+ * chain in one place: per-camera override → per-(node,device) base → the
29050
+ * resolved default (`resolveEffectiveDefaultModel`).
29051
+ *
29052
+ * Every surface calls this: the matrix cell, and the drawer's picker seed. They
29053
+ * are the same number, and the only way to keep them the same number is to have
29054
+ * one function produce it. A surface that owns fewer layers omits them (the node
29055
+ * matrix passes no `override`) — it does NOT get its own resolver.
29056
+ */
29057
+ function resolveEffectiveStepModel(input) {
29058
+ return input.override ?? input.base ?? resolveEffectiveDefaultModel(input.catalog, input.device);
29059
+ }
29060
+ //#endregion
29061
+ //#region src/composites/root-model-source.tsx
29062
+ /**
29063
+ * "Use the root model" — the step editor's control for a step the camera's
29064
+ * ROOT detection model can supply (D730).
29065
+ *
29066
+ * The flag (`useRootModel`, in the step's own settings) is an operator INTENT
29067
+ * kept beside the step's model: checking it never changes the model, and a
29068
+ * root that cannot supply the step leaves the step running its own model while
29069
+ * the flag waits, inactive, for a root that can. Whether it is in force is
29070
+ * `resolveRootSupply` — the same function the runner decides with.
29071
+ */
29072
+ /** The editor's view of the flag for one step, or `null` for a step no root can supply. */
29073
+ function rootSourceState(stepId, settings, rootModel) {
29074
+ if (!isRootSuppliableStepId(stepId)) return null;
29075
+ return resolveRootSupply(stepId, settings, rootModel?.supplies);
29076
+ }
29077
+ /** The settings bag with the flag set — every other key untouched. */
29078
+ function withUseRootModel(settings, value) {
29079
+ return {
29080
+ ...settings,
29081
+ [USE_ROOT_MODEL_SETTING_KEY]: value
29082
+ };
29083
+ }
29084
+ /** What the operator must know about a supply, beyond "it is on". */
29085
+ function supplyNotes(supply) {
29086
+ if (supply.kind === "label") {
29087
+ const notes = supply.uncovered.length > 0 ? [`Not produced by this model: ${supply.uncovered.join(", ")}.`] : [];
29088
+ if (supply.stepId === "package-detection") return [...notes, "The root model's own package boxes become the package result at this step's threshold; this step's zone-crop view is not used, so small parcels the full-frame model misses stay missed."];
29089
+ return [...notes, "This step's class list decides which of the root's labels become the fine class; a switched-off class stays at its macro."];
29090
+ }
29091
+ if (supply.kind === "mask") return ["Masks come from the root model: each detection carries the root's own instance mask, so this step's model does not run. A root mask follows the model's mask grid (a quarter of its input), coarser than this step's own per-crop mask."];
29092
+ if (supply.stepId === "face-detection") return ["Face boxes come from the root model. Each is re-found by this step's face detector in a square around it before recognition, so only a face it finds is recognised; a box with no face in it is dropped."];
29093
+ return ["Plate boxes come from the root model and the plate reader reads them. The crop margin around a root plate box has not been measured for this model yet."];
29094
+ }
29095
+ /** The reason an intended supply is not in force, in the operator's words. */
29096
+ function inactiveText(state, rootModel) {
29097
+ switch (state.inactiveReason) {
29098
+ case "root-input-too-small": return `the current root model (${rootModel.name}) sees the frame too small to find faces reliably (it needs an input of 640 px or more).`;
29099
+ case "root-does-not-declare":
29100
+ case void 0: return `the current root model (${rootModel.name}) cannot supply this.`;
29101
+ }
29102
+ }
29103
+ function RootModelSourceControl({ stepId, settings, rootModel, disabled, onChange }) {
29104
+ if (rootModel === void 0) return null;
29105
+ const state = rootSourceState(stepId, settings, rootModel);
29106
+ if (state === null) return null;
29107
+ const inactiveNote = state.inactive ? /* @__PURE__ */ jsxs("div", {
29108
+ className: "rounded bg-muted/40 px-3 py-2 text-[11px] text-foreground-subtle",
29109
+ "data-testid": "root-model-inactive",
29110
+ children: [
29111
+ "Use the root model: inactive — ",
29112
+ inactiveText(state, rootModel),
29113
+ " The step runs its own model."
29114
+ ]
29115
+ }) : null;
29116
+ if (state.supply === void 0) return inactiveNote;
29117
+ const checked = state.intent;
29118
+ return /* @__PURE__ */ jsxs("div", {
29119
+ className: "space-y-1",
29120
+ "data-testid": "root-model-source",
29121
+ children: [
29122
+ /* @__PURE__ */ jsxs("label", {
29123
+ className: "flex items-center gap-2 text-xs text-foreground",
29124
+ children: [
29125
+ /* @__PURE__ */ jsx("input", {
29126
+ type: "checkbox",
29127
+ checked,
29128
+ disabled,
29129
+ onChange: (e) => onChange(e.target.checked)
29130
+ }),
29131
+ "Use the root model (",
29132
+ rootModel.name,
29133
+ ")"
29134
+ ]
29135
+ }),
29136
+ inactiveNote,
29137
+ state.effective && supplyNotes(state.supply).map((note) => /* @__PURE__ */ jsx("p", {
29138
+ className: "text-[10px] leading-snug text-foreground-subtle",
29139
+ children: note
29140
+ }, note))
29141
+ ]
29142
+ });
29143
+ }
29144
+ //#endregion
29145
+ //#region src/lib/responsive.ts
29146
+ /**
29147
+ * Responsive design tokens — three-tier system.
29148
+ *
29149
+ * The admin-ui targets three width tiers; every component should pick
29150
+ * the right token from this file instead of hand-coding breakpoints.
29151
+ * Adopting the tokens uniformly is what makes the app feel consistent
29152
+ * across operator devices (mobile / tablet / desktop) and what unlocks
29153
+ * targeted tuning (e.g. shrink every label by 1px in one place).
29154
+ *
29155
+ * Tier definitions (Tailwind breakpoints):
29156
+ *
29157
+ * • **L1 — Compact** (`< 640px`, default = mobile portrait)
29158
+ * Single column, tight padding, smallest text, icon-only buttons
29159
+ * where labels can be inferred. The operator can still see every
29160
+ * stat / action — no horizontal scroll, no clipped text. The user
29161
+ * directive: "molta informazione in poco spazio quando la width è
29162
+ * bassa." [a lot of information in little space when the width is low.]
29163
+ *
29164
+ * • **L2 — Standard** (`sm` — `640–1023px`, tablet + small laptop)
29165
+ * 2-column grids, side panels become visible, button labels return.
29166
+ * Targets ~768px–1024px viewports — the most common operator sizes.
29167
+ *
29168
+ * • **L3 — Spacious** (`lg+` — `≥ 1024px`, desktop)
29169
+ * 4-column grids, generous padding, full-width header text,
29170
+ * side-by-side composite layouts. The operator has elbow room.
29171
+ *
29172
+ * Conventions:
29173
+ * - **Always start from L1** — the bare class is always the compact
29174
+ * variant, then `sm:` adds room at 640px, `lg:` at 1024px. No
29175
+ * desktop-first breakpoints; no max-width queries.
29176
+ * - **Token strings are static** — kept as `as const` so callers can
29177
+ * compose them via `cn()` / template literals without running a
29178
+ * class generator at runtime.
29179
+ * - **Pair the token with a comment** — the comment in the file
29180
+ * names every breakpoint it crosses, so a reader can predict the
29181
+ * layout without going to Tailwind docs.
29182
+ */
29183
+ /** Container padding for a card-style section (header + body). */
29184
+ var SECTION_CARD = "rounded-lg border border-border bg-surface overflow-hidden";
29185
+ /** Header strip inside a card (between border-b lines). */
29186
+ var SECTION_HEADER = "border-b border-border px-3 sm:px-4 py-1.5 sm:py-2";
29187
+ /** Body padding for a card-style section. */
29188
+ var SECTION_BODY = "p-2 sm:p-3 lg:p-4";
29189
+ /** Gap between cards in a vertical stack. */
29190
+ var STACK_GAP = "space-y-3 sm:space-y-4";
29191
+ /** Gap between cards in a grid (4 cells / row at lg). */
29192
+ var GRID_GAP = "gap-2 sm:gap-3";
29193
+ /** Row padding inside a divided list (e.g. InfoRow). */
29194
+ var LIST_ROW = "px-3 sm:px-4 py-1.5 sm:py-2";
29195
+ /** 1-up at L1, 2-up at L2, 4-up at L3 — quick-stat row. */
29196
+ var GRID_QUICK_STATS = "grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-4";
29197
+ /** 1-up at L1, 2-up at L2+ — paired panels (motion + detection rules). */
29198
+ var GRID_PAIRED = "grid grid-cols-1 lg:grid-cols-2";
29199
+ /** Side-by-side layout that stacks below md (canvas + side panel). */
29200
+ var SPLIT_PANEL_OUTER = "flex flex-col-reverse md:flex-row";
29201
+ /** Sidebar narrow lane in a SPLIT_PANEL_OUTER layout. */
29202
+ var SPLIT_PANEL_SIDE = "w-full md:w-44 lg:w-52 md:flex-shrink-0 border-b md:border-b-0 md:border-l border-border";
29203
+ /**
29204
+ * The tier boundary at which a settings label/value row stops stacking.
29205
+ *
29206
+ * Below it (L1 — compact) the row is ONE column: label on its own line, value
29207
+ * on the next at full width. Above it the row is label-left / value-right as
29208
+ * before. The two-column form needs `SETTING_ROW_LABEL`'s lane plus a readable
29209
+ * value beside it; a phone has neither, and the failure mode is not "cramped"
29210
+ * but "the value is the part that gets cut" — the one thing the operator
29211
+ * opened the page to read.
29212
+ */
29213
+ var SETTING_ROW_STACK_BREAKPOINT = "sm";
29214
+ /** Outer row: single column at L1, label/value columns from `sm` up. */
29215
+ var SETTING_ROW = "flex min-w-0 flex-col gap-0.5 py-1.5 sm:flex-row sm:items-center";
29216
+ /** Label lane. Full width (and free to wrap) at L1; a fixed lane from `sm` up. */
29217
+ var SETTING_ROW_LABEL = "min-w-0 text-[11px] leading-tight text-foreground-subtle sm:w-32 sm:shrink-0 sm:pr-2";
29218
+ /**
29219
+ * Value lane — the value text plus its trailing affordances (copy / reveal).
29220
+ * `w-full` at L1 so the value owns the whole row once the label is above it;
29221
+ * `sm:flex-1` makes it share the row again from `sm` up.
29222
+ */
29223
+ var SETTING_ROW_VALUE = "flex w-full min-w-0 items-center gap-1 sm:flex-1";
29224
+ /**
29225
+ * The value text itself. `break-all` lets an opaque token (a key, a URL) wrap
29226
+ * at L1 instead of being cut mid-word; `sm:truncate` restores the single-line
29227
+ * desktop form, where the row is wide enough for truncation to be a choice
29228
+ * rather than data loss.
29229
+ */
29230
+ var SETTING_ROW_VALUE_TEXT = "min-w-0 break-all text-xs text-foreground sm:truncate";
29231
+ /** Section header label (uppercase tracking-wider). */
29232
+ var TEXT_SECTION_LABEL = "text-[10px] sm:text-[11px] font-semibold text-foreground uppercase tracking-wider";
29233
+ /** Field label inside a row. */
29234
+ var TEXT_FIELD_LABEL = "text-[11px] sm:text-xs text-foreground";
29235
+ /** Sub-label / hint text. */
29236
+ var TEXT_HINT = "text-[10px] text-foreground-subtle";
29237
+ /** Primary value (a metric, badge, …). */
29238
+ var TEXT_VALUE = "text-[11px] sm:text-xs font-medium text-foreground";
29239
+ /** Big metric value (StatCard). */
29240
+ var TEXT_METRIC = "text-base sm:text-lg font-semibold leading-tight text-foreground";
29241
+ /** Default compact button. */
29242
+ var BTN_COMPACT = "inline-flex items-center justify-center gap-1 rounded border border-border bg-surface px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-foreground hover:bg-surface-hover transition-colors disabled:opacity-40";
29243
+ /** Primary compact button. */
29244
+ var BTN_COMPACT_PRIMARY = "inline-flex items-center justify-center gap-1 rounded border border-primary/40 bg-primary/15 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-primary hover:bg-primary/25 transition-colors disabled:opacity-40";
29245
+ /** Danger compact button. */
29246
+ var BTN_COMPACT_DANGER = "inline-flex items-center justify-center gap-1 rounded border border-danger/40 bg-danger/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40";
29247
+ /** Warning compact button (e.g. cancel-drawing). */
29248
+ var BTN_COMPACT_WARNING = "inline-flex items-center justify-center gap-1 rounded border border-warning/40 bg-warning/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-warning hover:bg-warning/20 transition-colors disabled:opacity-40";
29249
+ /** Compact text/select/number input. */
29250
+ var INPUT_COMPACT = "w-full rounded border border-border bg-background px-1.5 py-0.5 sm:px-2 sm:py-1 text-[11px] sm:text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none";
29251
+ /** Chip-style toggle (zone / class selectors in ZoneRulesEditor). */
29252
+ var CHIP_BASE = "inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors";
29253
+ var CHIP_ACTIVE = "border-primary/50 bg-primary/15 text-primary";
29254
+ var CHIP_INACTIVE = "border-border bg-surface text-foreground-subtle hover:bg-surface-hover";
29255
+ //#endregion
29031
29256
  //#region src/composites/model-bound-slider.tsx
29032
29257
  var SOURCE_LABEL = {
29033
29258
  override: "Override for this model",
@@ -29037,7 +29262,7 @@ var SOURCE_LABEL = {
29037
29262
  function formatNumber(value, scale) {
29038
29263
  return (scale !== void 0 ? value / scale : value).toFixed(2).replace(/\.?0+$/, "");
29039
29264
  }
29040
- function ModelBoundSlider({ field, modelId, settings, disabled, onChangeSettings }) {
29265
+ function ModelBoundSlider({ field, modelId, settings, disabled, onChangeSettings, hideSourceRow = false }) {
29041
29266
  const modelDefault = field.modelApplicability?.defaultByModel?.[modelId];
29042
29267
  const state = resolveModelBoundSetting(settings, field.key, modelId.length > 0 ? modelId : void 0, modelDefault, field.default);
29043
29268
  const fallback = typeof field.default === "number" ? field.default : field.min ?? 0;
@@ -29077,7 +29302,7 @@ function ModelBoundSlider({ field, modelId, settings, disabled, onChangeSettings
29077
29302
  onChange: (e) => handleChange(Number(e.target.value)),
29078
29303
  className: "w-full accent-primary h-1.5"
29079
29304
  }),
29080
- /* @__PURE__ */ jsxs("div", {
29305
+ !hideSourceRow && /* @__PURE__ */ jsxs("div", {
29081
29306
  className: "mt-1 flex items-center justify-between gap-2 text-[10px]",
29082
29307
  children: [/* @__PURE__ */ jsx("span", {
29083
29308
  "data-testid": "model-bound-source",
@@ -29128,6 +29353,32 @@ function ResetModelDefaultsButton({ fields, modelId, settings, disabled, onReset
29128
29353
  });
29129
29354
  }
29130
29355
  //#endregion
29356
+ //#region src/primitives/collapsible-card.tsx
29357
+ function CollapsibleCard({ expanded, onExpandedChange, header, children, dimmed = false, hideChevron = false, className }) {
29358
+ return /* @__PURE__ */ jsxs("div", {
29359
+ className: cn("rounded-lg border border-border bg-surface overflow-hidden", dimmed && "opacity-[0.45]", className),
29360
+ children: [/* @__PURE__ */ jsxs("div", {
29361
+ role: "button",
29362
+ tabIndex: 0,
29363
+ className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none",
29364
+ onClick: () => onExpandedChange(!expanded),
29365
+ onKeyDown: (e) => {
29366
+ if (e.key === "Enter" || e.key === " ") {
29367
+ e.preventDefault();
29368
+ onExpandedChange(!expanded);
29369
+ }
29370
+ },
29371
+ children: [!hideChevron && /* @__PURE__ */ jsx("span", {
29372
+ className: "text-foreground-subtle shrink-0",
29373
+ children: expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
29374
+ }), header]
29375
+ }), expanded && children && /* @__PURE__ */ jsx("div", {
29376
+ className: "border-t border-border px-3 py-3",
29377
+ children
29378
+ })]
29379
+ });
29380
+ }
29381
+ //#endregion
29131
29382
  //#region src/composites/pipeline-step.tsx
29132
29383
  /**
29133
29384
  * PipelineStep — single step card in the pipeline builder.
@@ -29139,124 +29390,77 @@ function ResetModelDefaultsButton({ fields, modelId, settings, disabled, onReset
29139
29390
  function modelsForStep(schema) {
29140
29391
  return schema?.models ?? [];
29141
29392
  }
29142
- function PipelineStep({ step, schema, allSchemas: _allSchemas, depth: _depth = 0, onChange, onDelete: _onDelete, readOnly = false, toggleMode = "simple", overrideState = null, onOverrideChange, inheritedEnabled, hideModelAndSettings = false, allowAutoModel = false }) {
29393
+ function PipelineStep({ step, schema, allSchemas: _allSchemas, depth: _depth = 0, onChange, onDelete: _onDelete, readOnly = false }) {
29143
29394
  const [expanded, setExpanded] = useState(false);
29144
29395
  const models = modelsForStep(schema);
29145
- const isAutoSentinel = allowAutoModel && step.modelId === "";
29146
- if (models.length > 0 && !isAutoSentinel && !models.some((m) => m.id === step.modelId) && !readOnly) {
29396
+ if (models.length > 0 && !models.some((m) => m.id === step.modelId) && !readOnly) {
29147
29397
  const fallback = (schema?.defaultModelId ? models.find((m) => m.id === schema.defaultModelId) : null) ?? models[0];
29148
29398
  if (fallback && fallback.id !== step.modelId) queueMicrotask(() => onChange({
29149
29399
  ...step,
29150
29400
  modelId: fallback.id
29151
29401
  }));
29152
29402
  }
29153
- const header = /* @__PURE__ */ jsxs(Fragment$1, { children: [
29154
- /* @__PURE__ */ jsxs("div", {
29155
- className: "flex-1 min-w-0",
29156
- children: [
29157
- /* @__PURE__ */ jsx("span", {
29158
- className: "text-[10px] uppercase tracking-wider font-medium text-foreground-subtle/60 block leading-none",
29159
- children: step.slot
29160
- }),
29161
- /* @__PURE__ */ jsx("span", {
29162
- className: "text-sm font-semibold text-foreground truncate block leading-tight",
29163
- children: step.addonName
29164
- }),
29165
- /* @__PURE__ */ jsxs("div", {
29166
- className: "flex items-center gap-1 mt-0.5 flex-wrap",
29167
- children: [
29168
- step.inputClasses.map((c) => /* @__PURE__ */ jsx("span", {
29169
- className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/12 text-blue-400",
29170
- children: c
29171
- }, c)),
29172
- step.inputClasses.length > 0 && step.outputClasses.length > 0 && /* @__PURE__ */ jsx("span", {
29173
- className: "text-foreground-subtle/40 text-[10px]",
29174
- children: "→"
29175
- }),
29176
- step.outputClasses.map((c) => /* @__PURE__ */ jsx("span", {
29177
- className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/12 text-green-400",
29178
- children: c
29179
- }, c))
29180
- ]
29181
- })
29182
- ]
29183
- }),
29184
- !readOnly && toggleMode === "simple" && /* @__PURE__ */ jsx("button", {
29185
- onClick: (e) => {
29186
- e.stopPropagation();
29187
- onChange({
29188
- ...step,
29189
- enabled: !step.enabled
29190
- });
29191
- },
29192
- className: cn("relative inline-flex h-6 w-11 shrink-0 items-center rounded-full transition-colors", step.enabled ? "bg-success" : "bg-foreground-subtle/30"),
29193
- children: /* @__PURE__ */ jsx("span", { className: cn("inline-block h-4 w-4 rounded-full bg-white shadow transition-transform", step.enabled ? "translate-x-6" : "translate-x-1") })
29194
- }),
29195
- !readOnly && toggleMode === "threeState" && onOverrideChange && /* @__PURE__ */ jsxs("div", {
29196
- className: "flex items-center gap-0.5 rounded-md border border-border p-0.5",
29197
- onClick: (e) => e.stopPropagation(),
29198
- children: [
29199
- /* @__PURE__ */ jsx(ThreeStateButton, {
29200
- label: "Inherit",
29201
- active: overrideState === null,
29202
- variant: "inherit",
29203
- subtext: inheritedEnabled === void 0 ? void 0 : inheritedEnabled ? "on" : "off",
29204
- onClick: () => onOverrideChange(null)
29205
- }),
29206
- /* @__PURE__ */ jsx(ThreeStateButton, {
29207
- label: "On",
29208
- active: overrideState === true,
29209
- variant: "on",
29210
- onClick: () => onOverrideChange(true)
29211
- }),
29212
- /* @__PURE__ */ jsx(ThreeStateButton, {
29213
- label: "Off",
29214
- active: overrideState === false,
29215
- variant: "off",
29216
- onClick: () => onOverrideChange(false)
29217
- })
29218
- ]
29219
- })
29220
- ] });
29403
+ const header = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
29404
+ className: "flex-1 min-w-0",
29405
+ children: [
29406
+ /* @__PURE__ */ jsx("span", {
29407
+ className: "text-[10px] uppercase tracking-wider font-medium text-foreground-subtle/60 block leading-none",
29408
+ children: step.slot
29409
+ }),
29410
+ /* @__PURE__ */ jsx("span", {
29411
+ className: "text-sm font-semibold text-foreground truncate block leading-tight",
29412
+ children: step.addonName
29413
+ }),
29414
+ /* @__PURE__ */ jsxs("div", {
29415
+ className: "flex items-center gap-1 mt-0.5 flex-wrap",
29416
+ children: [
29417
+ step.inputClasses.map((c) => /* @__PURE__ */ jsx("span", {
29418
+ className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/12 text-blue-400",
29419
+ children: c
29420
+ }, c)),
29421
+ step.inputClasses.length > 0 && step.outputClasses.length > 0 && /* @__PURE__ */ jsx("span", {
29422
+ className: "text-foreground-subtle/40 text-[10px]",
29423
+ children: "→"
29424
+ }),
29425
+ step.outputClasses.map((c) => /* @__PURE__ */ jsx("span", {
29426
+ className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/12 text-green-400",
29427
+ children: c
29428
+ }, c))
29429
+ ]
29430
+ })
29431
+ ]
29432
+ }), !readOnly && /* @__PURE__ */ jsx("button", {
29433
+ onClick: (e) => {
29434
+ e.stopPropagation();
29435
+ onChange({
29436
+ ...step,
29437
+ enabled: !step.enabled
29438
+ });
29439
+ },
29440
+ className: cn("relative inline-flex h-6 w-11 shrink-0 items-center rounded-full transition-colors", step.enabled ? "bg-success" : "bg-foreground-subtle/30"),
29441
+ children: /* @__PURE__ */ jsx("span", { className: cn("inline-block h-4 w-4 rounded-full bg-white shadow transition-transform", step.enabled ? "translate-x-6" : "translate-x-1") })
29442
+ })] });
29221
29443
  return /* @__PURE__ */ jsx(CollapsibleCard, {
29222
29444
  expanded,
29223
29445
  onExpandedChange: setExpanded,
29224
29446
  dimmed: !step.enabled,
29225
29447
  header,
29226
- children: hideModelAndSettings ? /* @__PURE__ */ jsx("p", {
29227
- className: "text-[11px] text-foreground-subtle",
29228
- children: "Model and detection settings are managed per agent — open the Pipeline page for this camera's agent to edit them."
29229
- }) : /* @__PURE__ */ jsxs("div", {
29448
+ children: /* @__PURE__ */ jsxs("div", {
29230
29449
  className: "space-y-3",
29231
29450
  children: [/* @__PURE__ */ jsxs("div", {
29232
29451
  className: "space-y-2",
29233
- children: [
29234
- /* @__PURE__ */ jsx("label", {
29235
- className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide",
29236
- children: "Model"
29237
- }),
29238
- allowAutoModel && /* @__PURE__ */ jsxs("label", {
29239
- className: "flex items-center gap-2 text-[11px] text-foreground-subtle",
29240
- children: [/* @__PURE__ */ jsx("input", {
29241
- type: "checkbox",
29242
- checked: isAutoSentinel,
29243
- disabled: readOnly,
29244
- onChange: (e) => onChange({
29245
- ...step,
29246
- modelId: e.target.checked ? "" : schema?.defaultModelId ?? models[0]?.id ?? ""
29247
- })
29248
- }), "Auto (node default)"]
29249
- }),
29250
- !isAutoSentinel && /* @__PURE__ */ jsx(ModelPicker, {
29251
- models,
29252
- value: step.modelId,
29253
- disabled: readOnly,
29254
- onChange: (id) => onChange({
29255
- ...step,
29256
- modelId: id
29257
- })
29452
+ children: [/* @__PURE__ */ jsx("label", {
29453
+ className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide",
29454
+ children: "Model"
29455
+ }), /* @__PURE__ */ jsx(ModelPicker, {
29456
+ models,
29457
+ value: step.modelId,
29458
+ disabled: readOnly,
29459
+ onChange: (id) => onChange({
29460
+ ...step,
29461
+ modelId: id
29258
29462
  })
29259
- ]
29463
+ })]
29260
29464
  }), schema?.configSchema?.map((field) => /* @__PURE__ */ jsx(ConfigSchemaField, {
29261
29465
  field,
29262
29466
  allFields: schema.configSchema ?? [],
@@ -29323,7 +29527,7 @@ function resolveSettingValue(key, step, allFields) {
29323
29527
  const sibling = allFields.find((f) => "key" in f && f.key === key);
29324
29528
  return sibling && "default" in sibling ? sibling.default : void 0;
29325
29529
  }
29326
- function ConfigSchemaField({ field, allFields, step, disabled, onChange }) {
29530
+ function ConfigSchemaField({ field, allFields, step, disabled, onChange, hideModelBoundSourceRow }) {
29327
29531
  const applicability = "modelApplicability" in field ? field.modelApplicability : void 0;
29328
29532
  const inapplicableReason = applicability?.inapplicable?.[step.modelId];
29329
29533
  const control = /* @__PURE__ */ jsx(ConfigSchemaFieldControl, {
@@ -29332,7 +29536,8 @@ function ConfigSchemaField({ field, allFields, step, disabled, onChange }) {
29332
29536
  step,
29333
29537
  disabled: disabled || inapplicableReason !== void 0,
29334
29538
  modelScopedOptions: applicability?.optionsByModel?.[step.modelId],
29335
- onChange
29539
+ onChange,
29540
+ hideModelBoundSourceRow: hideModelBoundSourceRow === true
29336
29541
  });
29337
29542
  if (inapplicableReason === void 0) return control;
29338
29543
  return /* @__PURE__ */ jsxs("div", {
@@ -29343,7 +29548,7 @@ function ConfigSchemaField({ field, allFields, step, disabled, onChange }) {
29343
29548
  })]
29344
29549
  });
29345
29550
  }
29346
- function ConfigSchemaFieldControl({ field, allFields, step, disabled, modelScopedOptions, onChange }) {
29551
+ function ConfigSchemaFieldControl({ field, allFields, step, disabled, modelScopedOptions, onChange, hideModelBoundSourceRow }) {
29347
29552
  const showWhen = field.type !== "separator" && field.type !== "info" ? field.showWhen : void 0;
29348
29553
  if (showWhen) {
29349
29554
  const { field: condField, equals, notEquals, in: inList, notIn } = showWhen;
@@ -29393,7 +29598,8 @@ function ConfigSchemaFieldControl({ field, allFields, step, disabled, modelScope
29393
29598
  onChangeSettings: (settings) => onChange({
29394
29599
  ...step,
29395
29600
  settings
29396
- })
29601
+ }),
29602
+ hideSourceRow: hideModelBoundSourceRow
29397
29603
  });
29398
29604
  if (field.type === "slider" || field.type === "number") {
29399
29605
  const raw = step.settings?.[field.key];
@@ -29479,204 +29685,247 @@ function ConfigSchemaFieldControl({ field, allFields, step, disabled, modelScope
29479
29685
  });
29480
29686
  return null;
29481
29687
  }
29482
- function ThreeStateButton({ label, active, variant, subtext, onClick }) {
29483
- return /* @__PURE__ */ jsxs("button", {
29484
- type: "button",
29485
- onClick,
29486
- className: cn("px-2 py-1 text-[10px] font-medium rounded transition-colors", active ? variant === "on" ? "bg-green-500/20 text-green-400" : variant === "off" ? "bg-red-500/20 text-red-400" : "bg-primary/20 text-primary" : "text-foreground-subtle hover:bg-surface-hover"),
29487
- children: [label, subtext && active && /* @__PURE__ */ jsxs("span", {
29488
- className: "ml-1 opacity-60",
29489
- children: [
29490
- "(",
29491
- subtext,
29492
- ")"
29493
- ]
29494
- })]
29495
- });
29496
- }
29497
29688
  //#endregion
29498
- //#region src/composites/resolve-step-default-model.ts
29499
- function resolveStepDefaultModel(catalog, format) {
29500
- const hasFormatBuild = (modelId) => catalog.models.find((m) => m.id === modelId)?.formats[format] !== void 0;
29501
- const declared = catalog.defaultModelIdByFormat?.[format];
29502
- if (declared !== void 0 && hasFormatBuild(declared)) return declared;
29503
- if (hasFormatBuild(catalog.defaultModelId)) return catalog.defaultModelId;
29504
- const available = catalog.models.filter((m) => m.formats[format] !== void 0 && m.legacy !== true);
29505
- if (available.length === 0) return catalog.defaultModelId;
29506
- return [...available].toSorted((a, b) => (a.formats[format]?.sizeMB ?? Infinity) - (b.formats[format]?.sizeMB ?? Infinity))[0].id;
29689
+ //#region src/composites/step-inspector/setting-values.ts
29690
+ function isValueField(field) {
29691
+ return field.type !== "separator" && field.type !== "info" && field.type !== "group";
29507
29692
  }
29508
- /**
29509
- * The model a matrix CELL shows as this step's effective default on `device`.
29510
- *
29511
- * The device's ELECTED model (`device.defaultModelId`, the per-device
29512
- * object-detection election) applies ONLY when this step's catalog actually
29513
- * contains it — `slot === 'detector'` alone is too wide, because
29514
- * package-detection shares the detector slot with the root step. Bit live
29515
- * 2026-08-08: rfdetr-package became the package step's default and every
29516
- * matrix cell still showed the device's yolo as the "selected" model, because
29517
- * the election was applied slot-wide. Membership is the principled gate: an
29518
- * elected model this step cannot run is never displayed for it.
29519
- */
29520
- function resolveEffectiveDefaultModel(catalog, device) {
29521
- const format = device?.format;
29522
- if (format === void 0) return void 0;
29523
- const elected = device?.defaultModelId;
29524
- return catalog.slot === "detector" && elected !== void 0 && catalog.models.some((m) => m.id === elected) ? elected : resolveStepDefaultModel(catalog, format);
29693
+ /** True for a D738 field whose value is stored with the model it was made for. */
29694
+ function bindsToModel(field) {
29695
+ return (field.type === "slider" || field.type === "number") && field.bindsToModel === true;
29525
29696
  }
29526
29697
  /**
29527
- * The models a step may run on an engine `format` — the ONE derivation of the
29528
- * option list. An unknown format yields NOTHING rather than everything: a
29529
- * picker that offered a model with no build for the device would write a pin
29530
- * the runner cannot honour.
29698
+ * What runs when no layer stores the field: the running model's default for a
29699
+ * model-bound field that the model declares one for (D738), else the field's
29700
+ * own default. `fromModel` says which.
29531
29701
  */
29532
- function stepModelOptions(models, format) {
29533
- if (format === void 0) return [];
29534
- return models.filter((m) => m.formats[format] !== void 0);
29702
+ function defaultOfField(field, modelId) {
29703
+ const byModel = "modelApplicability" in field ? field.modelApplicability?.defaultByModel?.[modelId] : void 0;
29704
+ if (byModel !== void 0) return {
29705
+ value: byModel,
29706
+ fromModel: true
29707
+ };
29708
+ return {
29709
+ value: "default" in field ? field.default : void 0,
29710
+ fromModel: false
29711
+ };
29535
29712
  }
29536
- /** Can this step run on `format` at all? (`false` ⇒ the caller renders "⚠ skip"/"—".) */
29537
- function stepHasModelForFormat(models, format) {
29538
- return stepModelOptions(models, format).length > 0;
29713
+ function trimNumber(n) {
29714
+ return n.toFixed(2).replace(/\.?0+$/, "");
29539
29715
  }
29540
- /**
29541
- * The model a step ACTUALLY runs for a (device, camera) — the whole effective
29542
- * chain in one place: per-camera override → per-(node,device) base → the
29543
- * resolved default (`resolveEffectiveDefaultModel`).
29544
- *
29545
- * Every surface calls this: the matrix cell, and the drawer's picker seed. They
29546
- * are the same number, and the only way to keep them the same number is to have
29547
- * one function produce it. A surface that owns fewer layers omits them (the node
29548
- * matrix passes no `override`) — it does NOT get its own resolver.
29549
- */
29550
- function resolveEffectiveStepModel(input) {
29551
- return input.override ?? input.base ?? resolveEffectiveDefaultModel(input.catalog, input.device);
29716
+ /** One stored value as the operator reads it (`0.65`, `on`, `Person, Vehicle`, `—`). */
29717
+ function formatSettingValue(field, value) {
29718
+ if (value === void 0 || value === null) return "—";
29719
+ if (typeof value === "boolean") return value ? "on" : "off";
29720
+ if (typeof value === "number") {
29721
+ const scale = field.type === "slider" ? field.displayScale : void 0;
29722
+ const unit = "unit" in field && typeof field.unit === "string" ? ` ${field.unit}` : "";
29723
+ return `${trimNumber(scale !== void 0 ? value / scale : value)}${unit}`;
29724
+ }
29725
+ const options = "options" in field && Array.isArray(field.options) ? field.options : [];
29726
+ const labelOf = (v) => {
29727
+ const hit = options.find((o) => o.value === v);
29728
+ return hit ? hit.label : String(v);
29729
+ };
29730
+ if (Array.isArray(value)) return value.length === 0 ? "none" : value.map(labelOf).join(", ");
29731
+ if (typeof value === "string") return labelOf(value);
29732
+ return JSON.stringify(value);
29552
29733
  }
29553
29734
  //#endregion
29554
- //#region src/composites/root-model-source.tsx
29555
- /**
29556
- * "Use the root model" — the step editor's control for a step the camera's
29557
- * ROOT detection model can supply (D730).
29558
- *
29559
- * The flag (`useRootModel`, in the step's own settings) is an operator INTENT
29560
- * kept beside the step's model: checking it never changes the model, and a
29561
- * root that cannot supply the step leaves the step running its own model while
29562
- * the flag waits, inactive, for a root that can. Whether it is in force is
29563
- * `resolveRootSupply` — the same function the runner decides with.
29564
- */
29565
- /** The editor's view of the flag for one step, or `null` for a step no root can supply. */
29566
- function rootSourceState(stepId, settings, rootModel) {
29567
- if (!isRootSuppliableStepId(stepId)) return null;
29568
- return resolveRootSupply(stepId, settings, rootModel?.supplies);
29735
+ //#region src/composites/step-inspector/layered-settings-form.tsx
29736
+ var SOURCE_TONE$1 = {
29737
+ accelerator: "border-amber-500/40 bg-amber-500/10 text-amber-500",
29738
+ camera: "border-primary/40 bg-primary/10 text-primary",
29739
+ node: "border-border bg-muted/40 text-foreground",
29740
+ default: "border-border/60 text-foreground-subtle"
29741
+ };
29742
+ /** DOM id of a field's box — the target of a search hit. */
29743
+ function stepFieldDomId(key) {
29744
+ return `step-field-${key}`;
29569
29745
  }
29570
- /** The settings bag with the flag set — every other key untouched. */
29571
- function withUseRootModel(settings, value) {
29746
+ function displayStep(addon, modelId, settings) {
29572
29747
  return {
29573
- ...settings,
29574
- [USE_ROOT_MODEL_SETTING_KEY]: value
29748
+ addonId: addon.id,
29749
+ addonName: addon.name,
29750
+ slot: addon.slot,
29751
+ inputClasses: [...addon.inputClasses],
29752
+ outputClasses: [...addon.outputClasses],
29753
+ enabled: true,
29754
+ modelId,
29755
+ children: [],
29756
+ settings: { ...settings }
29575
29757
  };
29576
29758
  }
29577
- /** What the operator must know about a supply, beyond "it is on". */
29578
- function supplyNotes(supply) {
29579
- if (supply.kind === "label") {
29580
- const notes = supply.uncovered.length > 0 ? [`Not produced by this model: ${supply.uncovered.join(", ")}.`] : [];
29581
- if (supply.stepId === "package-detection") return [...notes, "The root model's own package boxes become the package result at this step's threshold; this step's zone-crop view is not used, so small parcels the full-frame model misses stay missed."];
29582
- return [...notes, "This step's class list decides which of the root's labels become the fine class; a switched-off class stays at its macro."];
29583
- }
29584
- if (supply.kind === "mask") return ["Masks come from the root model: each detection carries the root's own instance mask, so this step's model does not run. A root mask follows the model's mask grid (a quarter of its input), coarser than this step's own per-crop mask."];
29585
- if (supply.stepId === "face-detection") return ["Face boxes come from the root model. Each is re-found by this step's face detector in a square around it before recognition, so only a face it finds is recognised; a box with no face in it is dropped."];
29586
- return ["Plate boxes come from the root model and the plate reader reads them. The crop margin around a root plate box has not been measured for this model yet."];
29587
- }
29588
- /** The reason an intended supply is not in force, in the operator's words. */
29589
- function inactiveText(state, rootModel) {
29590
- switch (state.inactiveReason) {
29591
- case "root-input-too-small": return `the current root model (${rootModel.name}) sees the frame too small to find faces reliably (it needs an input of 640 px or more).`;
29592
- case "root-does-not-declare":
29593
- case void 0: return `the current root model (${rootModel.name}) cannot supply this.`;
29594
- }
29595
- }
29596
- function RootModelSourceControl({ stepId, settings, rootModel, disabled, onChange }) {
29597
- if (rootModel === void 0) return null;
29598
- const state = rootSourceState(stepId, settings, rootModel);
29599
- if (state === null) return null;
29600
- const inactiveNote = state.inactive ? /* @__PURE__ */ jsxs("div", {
29601
- className: "rounded bg-muted/40 px-3 py-2 text-[11px] text-foreground-subtle",
29602
- "data-testid": "root-model-inactive",
29759
+ var LAYER_IDS = [
29760
+ "accelerator",
29761
+ "camera",
29762
+ "node"
29763
+ ];
29764
+ /** "Camera · node 0.65 · model default 0.78 · [Reset to node]" under one field. */
29765
+ function SettingProvenance({ field, layers, target, labels, boundKeys, modelId, pinned, disabled, onReset, action }) {
29766
+ const effective = effectiveStepSettings(layers);
29767
+ const fallback = defaultOfField(field, modelId);
29768
+ const defaultLabel = fallback.fromModel ? "model default" : "default";
29769
+ const stored = stepSettingSource(layers, field.key, boundKeys);
29770
+ const bound = bindsToModel(field);
29771
+ const state = bound ? resolveModelBoundSetting(effective, field.key, modelId, fallback.value, fallback.value) : null;
29772
+ const source = state === null || state.source === "override" ? stored : "default";
29773
+ const sourceText = source === "default" ? defaultLabel : labels[source] ?? source;
29774
+ const levels = LAYER_IDS.filter((id) => id !== source && labels[id] !== void 0).filter((id) => layers[id]?.[field.key] !== void 0).map((id) => {
29775
+ const binding = bound ? layers[id]?.[modelBindingKey(field.key)] : void 0;
29776
+ const forOther = typeof binding === "string" && binding !== modelId ? ` (for ${binding})` : "";
29777
+ return `${labels[id]} ${formatSettingValue(field, layers[id]?.[field.key])}${forOther}`;
29778
+ });
29779
+ const withDefault = source === "default" ? levels : [...levels, `${defaultLabel} ${formatSettingValue(field, fallback.value)}`];
29780
+ const targetStores = stepSettingSource({ [target]: layers[target] }, field.key, boundKeys) !== "default";
29781
+ const below = LAYER_IDS.slice(LAYER_IDS.indexOf(target) + 1).find((id) => labels[id] !== void 0 && layers[id]?.[field.key] !== void 0);
29782
+ const resetTo = below !== void 0 ? labels[below] ?? below : defaultLabel;
29783
+ const belowSource = stored === "default" ? "default" : stepSettingSource({
29784
+ ...layers,
29785
+ [stored]: void 0
29786
+ }, field.key, boundKeys);
29787
+ const pinnedAt = belowSource === "default" ? defaultLabel : labels[belowSource] ?? belowSource;
29788
+ return /* @__PURE__ */ jsxs("div", {
29789
+ className: "mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-[10px]",
29603
29790
  children: [
29604
- "Use the root model: inactive — ",
29605
- inactiveText(state, rootModel),
29606
- " The step runs its own model."
29791
+ /* @__PURE__ */ jsx("span", {
29792
+ "data-testid": "setting-source",
29793
+ className: cn("rounded border px-1.5 py-px font-medium", SOURCE_TONE$1[source]),
29794
+ children: sourceText
29795
+ }),
29796
+ withDefault.length > 0 && /* @__PURE__ */ jsx("span", {
29797
+ "data-testid": "setting-levels",
29798
+ className: "text-foreground-subtle",
29799
+ children: withDefault.join(" · ")
29800
+ }),
29801
+ pinned && /* @__PURE__ */ jsxs("span", {
29802
+ className: "rounded border border-amber-500/40 px-1.5 py-px text-amber-500",
29803
+ title: "Stored by an older editor as a copy of the value below. It changes nothing today, but it stops later changes below from reaching this camera.",
29804
+ children: [
29805
+ "pinned at the ",
29806
+ pinnedAt.toLowerCase(),
29807
+ " value"
29808
+ ]
29809
+ }),
29810
+ /* @__PURE__ */ jsxs("span", {
29811
+ className: "ml-auto flex items-center gap-2",
29812
+ children: [action, targetStores && /* @__PURE__ */ jsxs("button", {
29813
+ type: "button",
29814
+ disabled,
29815
+ onClick: onReset,
29816
+ className: "rounded px-1 text-foreground-subtle hover:bg-muted hover:text-foreground disabled:opacity-50",
29817
+ children: ["Reset to ", resetTo.toLowerCase()]
29818
+ })]
29819
+ })
29607
29820
  ]
29608
- }) : null;
29609
- if (state.supply === void 0) return inactiveNote;
29610
- const checked = state.intent;
29821
+ });
29822
+ }
29823
+ function LayeredSettingsForm({ addon, fields, layers, target, labels, modelId, onChangeLayer, rootModel, pinnedKeys = [], fieldActions, headerActions, highlightKey = null, disabled = false }) {
29824
+ const boundKeys = collectModelBoundKeys(fields);
29825
+ const effective = effectiveStepSettings(layers);
29826
+ const targetLayer = layers[target];
29827
+ const step = displayStep(addon, modelId, effective);
29828
+ const rootState = rootSourceState(addon.id, effective, rootModel);
29611
29829
  return /* @__PURE__ */ jsxs("div", {
29612
- className: "space-y-1",
29613
- "data-testid": "root-model-source",
29830
+ className: "space-y-2 text-xs",
29614
29831
  children: [
29615
- /* @__PURE__ */ jsxs("label", {
29616
- className: "flex items-center gap-2 text-xs text-foreground",
29832
+ /* @__PURE__ */ jsxs("div", {
29833
+ className: "flex flex-wrap items-center gap-2",
29617
29834
  children: [
29618
- /* @__PURE__ */ jsx("input", {
29619
- type: "checkbox",
29620
- checked,
29621
- disabled,
29622
- onChange: (e) => onChange(e.target.checked)
29835
+ /* @__PURE__ */ jsx("h3", {
29836
+ className: TEXT_SECTION_LABEL,
29837
+ children: "Settings"
29623
29838
  }),
29624
- "Use the root model (",
29625
- rootModel.name,
29626
- ")"
29839
+ /* @__PURE__ */ jsxs("span", {
29840
+ className: TEXT_HINT,
29841
+ children: ["editing: ", labels[target] ?? target]
29842
+ }),
29843
+ /* @__PURE__ */ jsxs("span", {
29844
+ className: "ml-auto flex flex-wrap items-center gap-3",
29845
+ children: [headerActions, /* @__PURE__ */ jsx(ResetModelDefaultsButton, {
29846
+ fields,
29847
+ modelId,
29848
+ settings: targetLayer,
29849
+ disabled,
29850
+ onReset: (next) => onChangeLayer(next)
29851
+ })]
29852
+ })
29627
29853
  ]
29628
29854
  }),
29629
- inactiveNote,
29630
- state.effective && supplyNotes(state.supply).map((note) => /* @__PURE__ */ jsx("p", {
29631
- className: "text-[10px] leading-snug text-foreground-subtle",
29632
- children: note
29633
- }, note))
29855
+ rootState !== null && /* @__PURE__ */ jsx(RootModelSourceControl, {
29856
+ stepId: addon.id,
29857
+ settings: effective,
29858
+ rootModel,
29859
+ disabled,
29860
+ onChange: (v) => onChangeLayer(withFieldFrom(targetLayer, USE_ROOT_MODEL_SETTING_KEY, withUseRootModel(effective, v), []))
29861
+ }),
29862
+ fields.map((field) => {
29863
+ if (!isValueField(field)) return /* @__PURE__ */ jsx(ConfigSchemaField, {
29864
+ field,
29865
+ allFields: fields,
29866
+ step,
29867
+ disabled,
29868
+ onChange: () => {}
29869
+ }, field.key);
29870
+ const highlighted = highlightKey === field.key;
29871
+ return /* @__PURE__ */ jsxs("div", {
29872
+ id: stepFieldDomId(field.key),
29873
+ "data-field-key": field.key,
29874
+ className: cn("rounded-md border border-transparent px-2 py-1 -mx-2", highlighted && "border-primary/50 bg-primary/5"),
29875
+ children: [/* @__PURE__ */ jsx(ConfigSchemaField, {
29876
+ field,
29877
+ allFields: fields,
29878
+ step,
29879
+ disabled,
29880
+ hideModelBoundSourceRow: true,
29881
+ onChange: (next) => onChangeLayer(withFieldFrom(targetLayer, field.key, next.settings ?? {}, boundKeys))
29882
+ }), /* @__PURE__ */ jsx(SettingProvenance, {
29883
+ field,
29884
+ layers,
29885
+ target,
29886
+ labels,
29887
+ boundKeys,
29888
+ modelId,
29889
+ pinned: pinnedKeys.includes(field.key),
29890
+ disabled,
29891
+ onReset: () => onChangeLayer(withoutField(targetLayer, field.key, boundKeys)),
29892
+ action: fieldActions?.(field.key, stepSettingSource(layers, field.key, boundKeys))
29893
+ })]
29894
+ }, field.key);
29895
+ })
29634
29896
  ]
29635
29897
  });
29636
29898
  }
29637
29899
  //#endregion
29638
29900
  //#region src/composites/agent-step-editor.tsx
29639
29901
  /**
29640
- * Per-(node,device) and per-camera editors must not surface knobs that the
29641
- * cluster already owns. Those fields still exist on the step's catalog
29642
- * schema so the runner can hydrate `child.settings`, but writing them here
29902
+ * A step's node-local fields: the catalog schema minus the knobs the CLUSTER
29903
+ * owns (`clusterStepSettingFieldsFor`). Those still exist on the schema so the
29904
+ * runner can hydrate `child.settings`, but writing them per node or per camera
29643
29905
  * would be a second store the overlay silently ignores.
29644
29906
  */
29645
- function nodeLocalConfigSchema(addon) {
29907
+ function stepLocalFields(addon) {
29646
29908
  const clusterKeys = new Set(clusterStepSettingFieldsFor(addon.id).map((field) => field.key));
29647
29909
  return (addon.configSchema ?? []).filter((field) => !clusterKeys.has(field.key));
29648
29910
  }
29649
- function ClusterSettingsHint({ addonId }) {
29650
- if (clusterStepSettingFieldsFor(addonId).length === 0) return null;
29651
- return /* @__PURE__ */ jsx("p", {
29652
- className: "text-[10px] leading-snug text-foreground-subtle",
29653
- children: "Admission knobs for this step live in Pipeline → Cluster → Settings → Enrichment models. They apply to every camera — a per-device copy would fill the shared index from two policies."
29654
- });
29655
- }
29656
29911
  /**
29657
- * The model the step's settings are read and written for — what a model-bound
29912
+ * The model a step's settings are read and written for — what a model-bound
29658
29913
  * field (D738) binds to. While the ROOT supplies the step's fine label (D741),
29659
29914
  * that is the root model: the step's threshold then gates the root's label, on
29660
29915
  * the root's score scale. Otherwise the step's own model: its pin, else the
29661
29916
  * model the row really runs (`effectiveModelId` — the device's hardware-aware
29662
29917
  * default when unpinned), else the step's flat catalog default.
29663
29918
  */
29664
- function settingsModelIdFor(addon, cfg, effectiveModelId, rootModel) {
29665
- if (rootModel !== void 0 && rootSourceState(addon.id, cfg.settings, rootModel)?.effective) return rootModel.modelId;
29666
- return cfg.modelId ?? effectiveModelId ?? addon.defaultModelId;
29919
+ function settingsModelIdFor(addon, modelId, settings, rootModel) {
29920
+ if (rootModel !== void 0 && rootSourceState(addon.id, settings, rootModel)?.effective) return rootModel.modelId;
29921
+ return modelId ?? addon.defaultModelId;
29667
29922
  }
29668
- function buildDisplayStep(addon, cfg, modelId) {
29669
- return {
29670
- addonId: addon.id,
29671
- addonName: addon.name,
29672
- slot: addon.slot,
29673
- inputClasses: [...addon.inputClasses],
29674
- outputClasses: [...addon.outputClasses],
29675
- enabled: cfg.enabled,
29676
- modelId,
29677
- children: [],
29678
- settings: { ...cfg.settings }
29679
- };
29923
+ function ClusterSettingsHint({ addonId }) {
29924
+ if (clusterStepSettingFieldsFor(addonId).length === 0) return null;
29925
+ return /* @__PURE__ */ jsx("p", {
29926
+ className: "text-[10px] leading-snug text-foreground-subtle",
29927
+ children: "Admission knobs for this step live in Pipeline → Cluster → Settings → Enrichment models. They apply to every camera — a per-device copy would fill the shared index from two policies."
29928
+ });
29680
29929
  }
29681
29930
  /**
29682
29931
  * Shown in place of the model picker while the root model supplies the step:
@@ -29697,233 +29946,57 @@ function RootSuppliedModelNote({ rootModel, stepModelId }) {
29697
29946
  ]
29698
29947
  });
29699
29948
  }
29700
- function computeEffective(mode, agentDefault, patch) {
29701
- if (mode !== "device" || !patch) return agentDefault;
29702
- return {
29703
- enabled: agentDefault.enabled,
29704
- modelId: patch.modelId ?? agentDefault.modelId,
29705
- settings: patch.settings ?? agentDefault.settings
29706
- };
29707
- }
29708
- function AgentModeEditor({ addon, agentDefault, modelsForFormat, engineFormat, effectiveModelId, rootModel, onChangeAgentConfig }) {
29949
+ /**
29950
+ * AgentStepEditor — one step on ONE accelerator: its model and its settings,
29951
+ * as a single node-level layer. Model Studio's "settings for this installed
29952
+ * model" dialog uses it. The pipeline pages use the step inspector, which lays
29953
+ * the same parts out across accelerators and layers (D754/D756); the settings
29954
+ * form here is that inspector's `LayeredSettingsForm` with one layer.
29955
+ */
29956
+ function AgentStepEditor({ addon, agentDefault, onChangeAgentConfig, engineFormat, effectiveModelId, rootModel }) {
29957
+ const modelsForFormat = useMemo(() => stepModelOptions(addon.models, engineFormat), [addon.models, engineFormat]);
29709
29958
  const update = (patch) => {
29710
29959
  onChangeAgentConfig?.({
29711
29960
  ...agentDefault,
29712
29961
  ...patch
29713
29962
  });
29714
29963
  };
29715
- const localSchema = nodeLocalConfigSchema(addon);
29964
+ const fields = stepLocalFields(addon);
29716
29965
  const formatDefault = addon.defaultModelIdByFormat?.[engineFormat] ?? addon.defaultModelId;
29717
29966
  const rootSupplied = rootSourceState(addon.id, agentDefault.settings, rootModel)?.effective === true;
29967
+ const runningModel = agentDefault.modelId ?? effectiveModelId;
29718
29968
  return /* @__PURE__ */ jsxs("div", {
29719
29969
  className: "space-y-4 text-xs",
29720
29970
  children: [
29721
- /* @__PURE__ */ jsx(RootModelSourceControl, {
29722
- stepId: addon.id,
29723
- settings: agentDefault.settings,
29724
- rootModel,
29725
- onChange: (v) => update({ settings: withUseRootModel(agentDefault.settings, v) })
29726
- }),
29727
29971
  rootSupplied && rootModel !== void 0 ? /* @__PURE__ */ jsx(RootSuppliedModelNote, {
29728
29972
  rootModel,
29729
- stepModelId: agentDefault.modelId ?? effectiveModelId
29973
+ stepModelId: runningModel
29730
29974
  }) : /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
29731
29975
  className: "text-[10px] uppercase tracking-widest text-foreground-subtle mb-1",
29732
29976
  children: "Model"
29733
29977
  }), /* @__PURE__ */ jsx(ModelPicker, {
29734
29978
  models: modelsForFormat,
29735
- value: agentDefault.modelId ?? effectiveModelId ?? "",
29979
+ value: runningModel ?? "",
29736
29980
  defaultModelId: formatDefault,
29737
29981
  onChange: (modelId) => update({ modelId })
29738
29982
  })] }),
29739
- localSchema.length > 0 && /* @__PURE__ */ jsxs("div", {
29740
- className: "pt-2 border-t border-border/50 space-y-3",
29741
- children: [/* @__PURE__ */ jsxs("div", {
29742
- className: "flex items-center justify-between",
29743
- children: [/* @__PURE__ */ jsx("div", {
29744
- className: "text-[10px] uppercase tracking-widest text-foreground-subtle",
29745
- children: "Settings"
29746
- }), /* @__PURE__ */ jsx(ResetModelDefaultsButton, {
29747
- fields: localSchema,
29748
- modelId: settingsModelIdFor(addon, agentDefault, effectiveModelId, rootModel),
29749
- settings: agentDefault.settings,
29750
- onReset: (settings) => update({ settings })
29751
- })]
29752
- }), localSchema.map((field) => /* @__PURE__ */ jsx(ConfigSchemaField, {
29753
- field,
29754
- allFields: localSchema,
29755
- step: buildDisplayStep(addon, agentDefault, settingsModelIdFor(addon, agentDefault, effectiveModelId, rootModel)),
29756
- disabled: false,
29757
- onChange: (next) => update({ settings: { ...next.settings } })
29758
- }, field.key))]
29983
+ (fields.length > 0 || rootSourceState(addon.id, agentDefault.settings, rootModel)) && /* @__PURE__ */ jsx("div", {
29984
+ className: "pt-2 border-t border-border/50",
29985
+ children: /* @__PURE__ */ jsx(LayeredSettingsForm, {
29986
+ addon,
29987
+ fields,
29988
+ layers: { node: agentDefault.settings },
29989
+ target: "node",
29990
+ labels: { node: "This node" },
29991
+ modelId: settingsModelIdFor(addon, runningModel, agentDefault.settings, rootModel),
29992
+ ...rootModel !== void 0 ? { rootModel } : {},
29993
+ onChangeLayer: (settings) => update({ settings })
29994
+ })
29759
29995
  }),
29760
29996
  /* @__PURE__ */ jsx(ClusterSettingsHint, { addonId: addon.id })
29761
29997
  ]
29762
29998
  });
29763
29999
  }
29764
- function DeviceModeEditor({ addon, agentDefault, agentNodeId, currentPatch, modelsForFormat, engineFormat, effectiveModelId, rootModel, onChangePatch }) {
29765
- const effective = computeEffective("device", agentDefault, currentPatch);
29766
- const inheritedModelId = agentDefault.modelId ?? effectiveModelId;
29767
- const formatDefault = addon.defaultModelIdByFormat?.[engineFormat] ?? addon.defaultModelId;
29768
- const commitPatch = (next) => {
29769
- const hasAnyField = next.modelId !== void 0 || next.settings !== void 0;
29770
- onChangePatch?.(hasAnyField ? next : null);
29771
- };
29772
- const setModel = (modelId) => {
29773
- const { modelId: _prev, ...rest } = currentPatch ?? {};
29774
- commitPatch(modelId === void 0 ? rest : {
29775
- ...rest,
29776
- modelId
29777
- });
29778
- };
29779
- const setSettings = (settings) => {
29780
- const { settings: _prev, ...rest } = currentPatch ?? {};
29781
- commitPatch(settings === void 0 ? rest : {
29782
- ...rest,
29783
- settings
29784
- });
29785
- };
29786
- const modelOverridden = currentPatch?.modelId !== void 0;
29787
- const localSchema = nodeLocalConfigSchema(addon);
29788
- return /* @__PURE__ */ jsxs("div", {
29789
- className: "space-y-4 text-xs",
29790
- children: [
29791
- /* @__PURE__ */ jsxs("div", {
29792
- className: "rounded bg-muted/40 px-3 py-2 text-[11px] text-foreground-subtle",
29793
- children: [
29794
- "Provisioning for ",
29795
- /* @__PURE__ */ jsx("span", {
29796
- className: "font-semibold text-foreground",
29797
- children: agentNodeId
29798
- }),
29799
- " — model + settings only. Whether this camera runs the step is set by its per-camera gate above."
29800
- ]
29801
- }),
29802
- /* @__PURE__ */ jsx(RootModelSourceControl, {
29803
- stepId: addon.id,
29804
- settings: effective.settings,
29805
- rootModel,
29806
- onChange: (v) => setSettings(withUseRootModel(effective.settings, v))
29807
- }),
29808
- rootSourceState(addon.id, effective.settings, rootModel)?.effective === true && rootModel !== void 0 ? /* @__PURE__ */ jsx(RootSuppliedModelNote, {
29809
- rootModel,
29810
- stepModelId: effective.modelId ?? inheritedModelId
29811
- }) : /* @__PURE__ */ jsxs("div", { children: [
29812
- /* @__PURE__ */ jsxs("div", {
29813
- className: "flex items-center justify-between mb-1",
29814
- children: [/* @__PURE__ */ jsx("div", {
29815
- className: "text-[10px] uppercase tracking-widest text-foreground-subtle",
29816
- children: "Model"
29817
- }), modelOverridden ? /* @__PURE__ */ jsx("button", {
29818
- type: "button",
29819
- className: "text-[10px] text-foreground-subtle hover:text-foreground",
29820
- onClick: () => setModel(void 0),
29821
- children: "Clear"
29822
- }) : /* @__PURE__ */ jsx("button", {
29823
- type: "button",
29824
- className: "text-[10px] text-primary hover:underline",
29825
- onClick: () => setModel(inheritedModelId),
29826
- children: "Override"
29827
- })]
29828
- }),
29829
- /* @__PURE__ */ jsx(ModelPicker, {
29830
- models: modelsForFormat,
29831
- disabled: !modelOverridden,
29832
- value: (modelOverridden ? currentPatch?.modelId ?? inheritedModelId : inheritedModelId) ?? "",
29833
- defaultModelId: formatDefault,
29834
- onChange: (modelId) => setModel(modelId)
29835
- }),
29836
- !modelOverridden && /* @__PURE__ */ jsxs("div", {
29837
- className: "text-[10px] text-foreground-subtle mt-1",
29838
- children: ["inherits from ", agentNodeId]
29839
- })
29840
- ] }),
29841
- localSchema.length > 0 && (() => {
29842
- const settingsOverridden = currentPatch?.settings !== void 0;
29843
- return /* @__PURE__ */ jsxs("div", {
29844
- className: "pt-2 border-t border-border/50 space-y-3",
29845
- children: [
29846
- /* @__PURE__ */ jsxs("div", {
29847
- className: "flex items-center justify-between",
29848
- children: [/* @__PURE__ */ jsx("div", {
29849
- className: "text-[10px] uppercase tracking-widest text-foreground-subtle",
29850
- children: "Settings"
29851
- }), settingsOverridden ? /* @__PURE__ */ jsxs("div", {
29852
- className: "flex items-center gap-3",
29853
- children: [/* @__PURE__ */ jsx(ResetModelDefaultsButton, {
29854
- fields: localSchema,
29855
- modelId: settingsModelIdFor(addon, effective, inheritedModelId, rootModel),
29856
- settings: currentPatch?.settings,
29857
- onReset: (settings) => setSettings(settings)
29858
- }), /* @__PURE__ */ jsx("button", {
29859
- type: "button",
29860
- className: "text-[10px] text-foreground-subtle hover:text-foreground",
29861
- onClick: () => setSettings(void 0),
29862
- children: "Clear"
29863
- })]
29864
- }) : /* @__PURE__ */ jsx("button", {
29865
- type: "button",
29866
- className: "text-[10px] text-primary hover:underline",
29867
- onClick: () => setSettings({ ...agentDefault.settings }),
29868
- children: "Override"
29869
- })]
29870
- }),
29871
- localSchema.map((field) => /* @__PURE__ */ jsx(ConfigSchemaField, {
29872
- field,
29873
- allFields: localSchema,
29874
- step: buildDisplayStep(addon, effective, settingsModelIdFor(addon, effective, inheritedModelId, rootModel)),
29875
- disabled: !settingsOverridden,
29876
- onChange: (next) => setSettings({ ...next.settings })
29877
- }, field.key)),
29878
- !settingsOverridden && /* @__PURE__ */ jsxs("div", {
29879
- className: "text-[10px] text-foreground-subtle",
29880
- children: ["inherits from ", agentNodeId]
29881
- })
29882
- ]
29883
- });
29884
- })(),
29885
- /* @__PURE__ */ jsx(ClusterSettingsHint, { addonId: addon.id }),
29886
- /* @__PURE__ */ jsxs("div", {
29887
- className: "rounded bg-muted/40 px-3 py-2 text-[11px] text-foreground-subtle",
29888
- children: [/* @__PURE__ */ jsx("div", {
29889
- className: "font-semibold text-foreground mb-0.5",
29890
- children: "Effective provisioning preview"
29891
- }), /* @__PURE__ */ jsxs("div", {
29892
- className: "font-mono truncate",
29893
- children: [
29894
- addon.id,
29895
- " · model: ",
29896
- effective.modelId ?? inheritedModelId ?? "Auto"
29897
- ]
29898
- })]
29899
- })
29900
- ]
29901
- });
29902
- }
29903
- function AgentStepEditor(props) {
29904
- const { mode, addon, agentDefault, agentNodeId, currentPatch, onChangeAgentConfig, onChangePatch, engineFormat, effectiveModelId, rootModel } = props;
29905
- const modelsForFormat = useMemo(() => stepModelOptions(addon.models, engineFormat), [addon.models, engineFormat]);
29906
- if (mode === "agent") return /* @__PURE__ */ jsx(AgentModeEditor, {
29907
- addon,
29908
- agentDefault,
29909
- modelsForFormat,
29910
- engineFormat,
29911
- effectiveModelId,
29912
- ...rootModel !== void 0 ? { rootModel } : {},
29913
- onChangeAgentConfig
29914
- });
29915
- return /* @__PURE__ */ jsx(DeviceModeEditor, {
29916
- addon,
29917
- agentDefault,
29918
- agentNodeId,
29919
- currentPatch,
29920
- modelsForFormat,
29921
- engineFormat,
29922
- effectiveModelId,
29923
- ...rootModel !== void 0 ? { rootModel } : {},
29924
- onChangePatch
29925
- });
29926
- }
29927
30000
  //#endregion
29928
30001
  //#region src/primitives/icon-button.tsx
29929
30002
  var iconButtonVariants = cva("inline-flex items-center justify-center rounded-md font-medium transition-colors cursor-pointer disabled:opacity-50 disabled:pointer-events-none", {
@@ -33838,117 +33911,6 @@ async function waitForIceGathering(pc) {
33838
33911
  });
33839
33912
  }
33840
33913
  //#endregion
33841
- //#region src/lib/responsive.ts
33842
- /**
33843
- * Responsive design tokens — three-tier system.
33844
- *
33845
- * The admin-ui targets three width tiers; every component should pick
33846
- * the right token from this file instead of hand-coding breakpoints.
33847
- * Adopting the tokens uniformly is what makes the app feel consistent
33848
- * across operator devices (mobile / tablet / desktop) and what unlocks
33849
- * targeted tuning (e.g. shrink every label by 1px in one place).
33850
- *
33851
- * Tier definitions (Tailwind breakpoints):
33852
- *
33853
- * • **L1 — Compact** (`< 640px`, default = mobile portrait)
33854
- * Single column, tight padding, smallest text, icon-only buttons
33855
- * where labels can be inferred. The operator can still see every
33856
- * stat / action — no horizontal scroll, no clipped text. The user
33857
- * directive: "molta informazione in poco spazio quando la width è
33858
- * bassa." [a lot of information in little space when the width is low.]
33859
- *
33860
- * • **L2 — Standard** (`sm` — `640–1023px`, tablet + small laptop)
33861
- * 2-column grids, side panels become visible, button labels return.
33862
- * Targets ~768px–1024px viewports — the most common operator sizes.
33863
- *
33864
- * • **L3 — Spacious** (`lg+` — `≥ 1024px`, desktop)
33865
- * 4-column grids, generous padding, full-width header text,
33866
- * side-by-side composite layouts. The operator has elbow room.
33867
- *
33868
- * Conventions:
33869
- * - **Always start from L1** — the bare class is always the compact
33870
- * variant, then `sm:` adds room at 640px, `lg:` at 1024px. No
33871
- * desktop-first breakpoints; no max-width queries.
33872
- * - **Token strings are static** — kept as `as const` so callers can
33873
- * compose them via `cn()` / template literals without running a
33874
- * class generator at runtime.
33875
- * - **Pair the token with a comment** — the comment in the file
33876
- * names every breakpoint it crosses, so a reader can predict the
33877
- * layout without going to Tailwind docs.
33878
- */
33879
- /** Container padding for a card-style section (header + body). */
33880
- var SECTION_CARD = "rounded-lg border border-border bg-surface overflow-hidden";
33881
- /** Header strip inside a card (between border-b lines). */
33882
- var SECTION_HEADER = "border-b border-border px-3 sm:px-4 py-1.5 sm:py-2";
33883
- /** Body padding for a card-style section. */
33884
- var SECTION_BODY = "p-2 sm:p-3 lg:p-4";
33885
- /** Gap between cards in a vertical stack. */
33886
- var STACK_GAP = "space-y-3 sm:space-y-4";
33887
- /** Gap between cards in a grid (4 cells / row at lg). */
33888
- var GRID_GAP = "gap-2 sm:gap-3";
33889
- /** Row padding inside a divided list (e.g. InfoRow). */
33890
- var LIST_ROW = "px-3 sm:px-4 py-1.5 sm:py-2";
33891
- /** 1-up at L1, 2-up at L2, 4-up at L3 — quick-stat row. */
33892
- var GRID_QUICK_STATS = "grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-4";
33893
- /** 1-up at L1, 2-up at L2+ — paired panels (motion + detection rules). */
33894
- var GRID_PAIRED = "grid grid-cols-1 lg:grid-cols-2";
33895
- /** Side-by-side layout that stacks below md (canvas + side panel). */
33896
- var SPLIT_PANEL_OUTER = "flex flex-col-reverse md:flex-row";
33897
- /** Sidebar narrow lane in a SPLIT_PANEL_OUTER layout. */
33898
- var SPLIT_PANEL_SIDE = "w-full md:w-44 lg:w-52 md:flex-shrink-0 border-b md:border-b-0 md:border-l border-border";
33899
- /**
33900
- * The tier boundary at which a settings label/value row stops stacking.
33901
- *
33902
- * Below it (L1 — compact) the row is ONE column: label on its own line, value
33903
- * on the next at full width. Above it the row is label-left / value-right as
33904
- * before. The two-column form needs `SETTING_ROW_LABEL`'s lane plus a readable
33905
- * value beside it; a phone has neither, and the failure mode is not "cramped"
33906
- * but "the value is the part that gets cut" — the one thing the operator
33907
- * opened the page to read.
33908
- */
33909
- var SETTING_ROW_STACK_BREAKPOINT = "sm";
33910
- /** Outer row: single column at L1, label/value columns from `sm` up. */
33911
- var SETTING_ROW = "flex min-w-0 flex-col gap-0.5 py-1.5 sm:flex-row sm:items-center";
33912
- /** Label lane. Full width (and free to wrap) at L1; a fixed lane from `sm` up. */
33913
- var SETTING_ROW_LABEL = "min-w-0 text-[11px] leading-tight text-foreground-subtle sm:w-32 sm:shrink-0 sm:pr-2";
33914
- /**
33915
- * Value lane — the value text plus its trailing affordances (copy / reveal).
33916
- * `w-full` at L1 so the value owns the whole row once the label is above it;
33917
- * `sm:flex-1` makes it share the row again from `sm` up.
33918
- */
33919
- var SETTING_ROW_VALUE = "flex w-full min-w-0 items-center gap-1 sm:flex-1";
33920
- /**
33921
- * The value text itself. `break-all` lets an opaque token (a key, a URL) wrap
33922
- * at L1 instead of being cut mid-word; `sm:truncate` restores the single-line
33923
- * desktop form, where the row is wide enough for truncation to be a choice
33924
- * rather than data loss.
33925
- */
33926
- var SETTING_ROW_VALUE_TEXT = "min-w-0 break-all text-xs text-foreground sm:truncate";
33927
- /** Section header label (uppercase tracking-wider). */
33928
- var TEXT_SECTION_LABEL = "text-[10px] sm:text-[11px] font-semibold text-foreground uppercase tracking-wider";
33929
- /** Field label inside a row. */
33930
- var TEXT_FIELD_LABEL = "text-[11px] sm:text-xs text-foreground";
33931
- /** Sub-label / hint text. */
33932
- var TEXT_HINT = "text-[10px] text-foreground-subtle";
33933
- /** Primary value (a metric, badge, …). */
33934
- var TEXT_VALUE = "text-[11px] sm:text-xs font-medium text-foreground";
33935
- /** Big metric value (StatCard). */
33936
- var TEXT_METRIC = "text-base sm:text-lg font-semibold leading-tight text-foreground";
33937
- /** Default compact button. */
33938
- var BTN_COMPACT = "inline-flex items-center justify-center gap-1 rounded border border-border bg-surface px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-foreground hover:bg-surface-hover transition-colors disabled:opacity-40";
33939
- /** Primary compact button. */
33940
- var BTN_COMPACT_PRIMARY = "inline-flex items-center justify-center gap-1 rounded border border-primary/40 bg-primary/15 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-primary hover:bg-primary/25 transition-colors disabled:opacity-40";
33941
- /** Danger compact button. */
33942
- var BTN_COMPACT_DANGER = "inline-flex items-center justify-center gap-1 rounded border border-danger/40 bg-danger/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40";
33943
- /** Warning compact button (e.g. cancel-drawing). */
33944
- var BTN_COMPACT_WARNING = "inline-flex items-center justify-center gap-1 rounded border border-warning/40 bg-warning/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-warning hover:bg-warning/20 transition-colors disabled:opacity-40";
33945
- /** Compact text/select/number input. */
33946
- var INPUT_COMPACT = "w-full rounded border border-border bg-background px-1.5 py-0.5 sm:px-2 sm:py-1 text-[11px] sm:text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none";
33947
- /** Chip-style toggle (zone / class selectors in ZoneRulesEditor). */
33948
- var CHIP_BASE = "inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors";
33949
- var CHIP_ACTIVE = "border-primary/50 bg-primary/15 text-primary";
33950
- var CHIP_INACTIVE = "border-border bg-surface text-foreground-subtle hover:bg-surface-hover";
33951
- //#endregion
33952
33914
  //#region src/composites/data-table-layout.ts
33953
33915
  /**
33954
33916
  * At this many columns and above, `auto` switches a narrow viewport to cards.
@@ -55541,16 +55503,16 @@ function cellButtonClass(state, isSelected, extra) {
55541
55503
  //#endregion
55542
55504
  //#region src/composites/device-step-matrix.tsx
55543
55505
  /**
55544
- * DeviceStepMatrix — the per-camera "Detection pipeline → Steps" surface (#33)
55545
- * rendered as ONE hierarchical steps×nodes matrix.
55506
+ * DeviceStepMatrix — the READ-ONLY "Compare" view of the step inspector
55507
+ * (D756): one hierarchical steps × accelerators matrix showing what every
55508
+ * accelerator runs for every step, side by side.
55546
55509
  *
55547
- * Column 1 (STICKY): the indented step tree. Each step carries its slot +
55548
- * name + class-flow chips PLUS a per-camera, node-independent GATE control
55549
- * with THREE states — On / Off / Default (inherit). `package-detection` is
55550
- * zone-driven, so it shows a "Zones" badge instead of a gate.
55551
- * Columns 2..N (one per online node): the provisioned model chip (click →
55552
- * the model/config picker), a clickable "⚠ skip" when the step is gated ON
55553
- * but the node has no compatible model, or "—" when N/A.
55510
+ * Column 1 (STICKY): the indented step tree (slot + name + class-flow chips).
55511
+ * Columns 2..N (one per accelerator): the model chip, "⚠ skip" when the step
55512
+ * runs on the camera but the accelerator has no compatible model, or "—".
55513
+ * A click selects that (step, accelerator) in the inspector — the matrix
55514
+ * itself edits nothing (it used to host a slide-over editor that scrolled
55515
+ * away with the page).
55554
55516
  *
55555
55517
  * Responsive, container-measured (never a global media query, so it also works
55556
55518
  * embedded):
@@ -55561,77 +55523,20 @@ function cellButtonClass(state, isSelected, extra) {
55561
55523
  * single-node view: a node selector picks ONE node and the matrix renders
55562
55524
  * `step-tree × that-one-node`.
55563
55525
  */
55564
- /** Wider than the cluster matrix's 18rem: col-1 also hosts the gate control. */
55565
- var STEP_COL_REM$1 = 21;
55566
- var STEP_COL_PX = STEP_COL_REM$1 * 16;
55526
+ /** The sticky step column. */
55527
+ var STEP_COL_REM = 18;
55528
+ var STEP_COL_PX = STEP_COL_REM * 16;
55567
55529
  /**
55568
- * Narrow (mobile) step-column width. On a phone the wide 21rem column would
55569
- * occlude nearly the whole viewport, so the single-node layout pins a slimmer
55570
- * sticky step column and lets the device columns scroll horizontally beside it
55571
- * (both fully readable) rather than cramming every column into the viewport.
55530
+ * Narrow (mobile) step-column width. On a phone the wide column would occlude
55531
+ * nearly the whole viewport, so the single-node layout pins a slimmer sticky
55532
+ * step column and lets the device columns scroll horizontally beside it.
55572
55533
  */
55573
55534
  var STEP_COL_SINGLE_REM = 11;
55574
- function activeChoice(gate) {
55575
- if (!gate.explicit) return "default";
55576
- return gate.effectiveOn ? "on" : "off";
55577
- }
55578
- /**
55579
- * Tri-state segmented control. `Default` inherits the catalog value (shown in
55580
- * the caption); `On`/`Off` pin an explicit per-camera override. Touch-friendly
55581
- * 28px segments.
55582
- */
55583
- function GateControl({ gate, busy, onSet }) {
55584
- const active = activeChoice(gate);
55585
- const seg = (choice, label, value, activeClass) => /* @__PURE__ */ jsx("button", {
55586
- type: "button",
55587
- "aria-pressed": active === choice,
55588
- disabled: busy,
55589
- onClick: () => onSet(value),
55590
- className: cn("flex-1 px-2 py-1 text-[11px] font-medium leading-none transition-colors", "min-h-[26px]", active === choice ? activeClass : "text-foreground-subtle hover:bg-muted/60", busy && "opacity-50 cursor-not-allowed"),
55591
- children: label
55592
- });
55593
- return /* @__PURE__ */ jsxs("div", {
55594
- className: "flex flex-col gap-1",
55595
- children: [/* @__PURE__ */ jsxs("div", {
55596
- className: "inline-flex w-fit max-w-full self-start overflow-hidden rounded-md border border-border",
55597
- children: [
55598
- seg("default", "Auto", null, "bg-primary/15 text-primary"),
55599
- /* @__PURE__ */ jsx("span", { className: "w-px self-stretch bg-border" }),
55600
- seg("on", "On", true, "bg-emerald-500 text-white"),
55601
- /* @__PURE__ */ jsx("span", { className: "w-px self-stretch bg-border" }),
55602
- seg("off", "Off", false, "bg-foreground-subtle/70 text-white")
55603
- ]
55604
- }), /* @__PURE__ */ jsx("span", {
55605
- className: "text-[10px] leading-none text-foreground-subtle",
55606
- children: active === "default" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
55607
- "= default (",
55608
- gate.defaultOn ? "on" : "off",
55609
- ")"
55610
- ] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: ["overridden · default ", gate.defaultOn ? "on" : "off"] })
55611
- })]
55612
- });
55613
- }
55614
- function ZoneBadge() {
55615
- return /* @__PURE__ */ jsxs("div", {
55616
- className: "flex flex-col gap-1",
55617
- children: [/* @__PURE__ */ jsx("span", {
55618
- className: "inline-flex w-fit items-center gap-1 rounded-md border border-violet-500/40 bg-violet-500/10 px-2 py-1 text-[11px] font-medium text-violet-400",
55619
- children: "Zones"
55620
- }), /* @__PURE__ */ jsx("span", {
55621
- className: "text-[10px] leading-none text-foreground-subtle",
55622
- children: "driven by package zones"
55623
- })]
55624
- });
55625
- }
55626
- function StepGateCell({ node, depth, gate, busy, onSet, hideGate }) {
55627
- return /* @__PURE__ */ jsxs("div", {
55628
- className: "sticky left-0 z-10 flex flex-col gap-2 border-b border-border bg-surface px-3 py-2.5 text-xs min-w-0",
55535
+ function StepCell({ node, depth }) {
55536
+ return /* @__PURE__ */ jsx("div", {
55537
+ className: "sticky left-0 z-10 flex flex-col gap-2 border-b border-border bg-surface px-3 py-2 text-xs min-w-0",
55629
55538
  style: { paddingLeft: `${12 + depth * 14}px` },
55630
- children: [/* @__PURE__ */ jsx(StepLabel, { node }), hideGate ? null : gate.kind === "zone-driven" ? /* @__PURE__ */ jsx(ZoneBadge, {}) : /* @__PURE__ */ jsx(GateControl, {
55631
- gate,
55632
- busy,
55633
- onSet
55634
- })]
55539
+ children: /* @__PURE__ */ jsx(StepLabel, { node })
55635
55540
  });
55636
55541
  }
55637
55542
  /**
@@ -55670,18 +55575,18 @@ function NodeSelectorBar({ nodes, selected, onSelect }) {
55670
55575
  ]
55671
55576
  });
55672
55577
  }
55673
- function MatrixGrid$1({ tree, agents, gateFor, getCellState, onCellClick, selectedCell, onSetGate, gateBusy, single, hideGate }) {
55578
+ function MatrixGrid({ tree, agents, getCellState, onCellClick, selectedCell, single }) {
55674
55579
  const rows = useMemo(() => flattenTree(tree), [tree]);
55675
55580
  const groups = useMemo(() => groupAgentColumns(agents), [agents]);
55676
55581
  return /* @__PURE__ */ jsx("div", {
55677
55582
  className: "overflow-auto rounded border border-border",
55678
55583
  children: /* @__PURE__ */ jsxs("div", {
55679
55584
  className: "grid w-max",
55680
- style: { gridTemplateColumns: `${single ? STEP_COL_SINGLE_REM : STEP_COL_REM$1}rem repeat(${agents.length}, 13rem)` },
55585
+ style: { gridTemplateColumns: `${single ? STEP_COL_SINGLE_REM : STEP_COL_REM}rem repeat(${agents.length}, 13rem)` },
55681
55586
  children: [
55682
55587
  /* @__PURE__ */ jsx("div", {
55683
55588
  className: "sticky left-0 top-0 z-20 border-b border-border bg-muted/60 px-3 py-2 text-[10px] uppercase tracking-widest text-foreground-subtle",
55684
- children: hideGate ? "Step" : "Step · gate"
55589
+ children: "Step"
55685
55590
  }),
55686
55591
  groups.map((group) => group.grouped ? /* @__PURE__ */ jsx(GroupedAgentHeader, { group }, group.agentNodeId) : group.columns.map((col) => /* @__PURE__ */ jsxs("div", {
55687
55592
  className: "sticky top-0 z-10 min-w-0 border-b border-l border-border bg-muted/60 px-3 py-2",
@@ -55697,26 +55602,18 @@ function MatrixGrid$1({ tree, agents, gateFor, getCellState, onCellClick, select
55697
55602
  node,
55698
55603
  depth,
55699
55604
  agents,
55700
- gate: gateFor(node.addonId),
55701
55605
  getCellState,
55702
55606
  onCellClick,
55703
- selectedCell,
55704
- onSetGate,
55705
- gateBusy,
55706
- hideGate
55607
+ selectedCell
55707
55608
  }, node.addonId))
55708
55609
  ]
55709
55610
  })
55710
55611
  });
55711
55612
  }
55712
- function MatrixRow({ node, depth, agents, gate, getCellState, onCellClick, selectedCell, onSetGate, gateBusy, hideGate }) {
55713
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(StepGateCell, {
55613
+ function MatrixRow({ node, depth, agents, getCellState, onCellClick, selectedCell }) {
55614
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(StepCell, {
55714
55615
  node,
55715
- depth,
55716
- gate,
55717
- busy: gateBusy,
55718
- onSet: (next) => onSetGate(node.addonId, next),
55719
- hideGate
55616
+ depth
55720
55617
  }), agents.map((a) => {
55721
55618
  const state = getCellState(node.addonId, a);
55722
55619
  const isSelected = selectedCell !== null && selectedCell.addonId === node.addonId && agentColumnKey(selectedCell) === agentColumnKey(a);
@@ -55730,7 +55627,7 @@ function MatrixRow({ node, depth, agents, gate, getCellState, onCellClick, selec
55730
55627
  }, agentColumnKey(a));
55731
55628
  })] });
55732
55629
  }
55733
- function DeviceStepMatrix({ tree, agents, gateFor, getCellState, onCellClick, selectedCell, onSetGate, gateBusy, fallbackNodeId, onFallbackNodeChange, hideGate }) {
55630
+ function DeviceStepMatrix({ tree, agents, getCellState, onCellClick, selectedCell, fallbackNodeId, onFallbackNodeChange }) {
55734
55631
  const containerRef = useRef(null);
55735
55632
  const [width, setWidth] = useState(0);
55736
55633
  useLayoutEffect(() => {
@@ -55756,17 +55653,13 @@ function DeviceStepMatrix({ tree, agents, gateFor, getCellState, onCellClick, se
55756
55653
  nodes,
55757
55654
  selected: selectedNode.agentNodeId,
55758
55655
  onSelect: onFallbackNodeChange
55759
- }), /* @__PURE__ */ jsx(MatrixGrid$1, {
55656
+ }), /* @__PURE__ */ jsx(MatrixGrid, {
55760
55657
  tree,
55761
55658
  agents: shownAgents,
55762
- gateFor,
55763
55659
  getCellState,
55764
55660
  onCellClick,
55765
55661
  selectedCell,
55766
- onSetGate,
55767
- gateBusy,
55768
- single: single && selectedNode !== null,
55769
- hideGate
55662
+ single: single && selectedNode !== null
55770
55663
  })]
55771
55664
  });
55772
55665
  }
@@ -56796,17 +56689,7 @@ function PlaceholderStep({ addon, onClick }) {
56796
56689
  })
56797
56690
  });
56798
56691
  }
56799
- function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateId, onSelectTemplate, onSaveTemplate, onUpdateTemplate, onDeleteTemplate, readOnly = false, excludeAddons = [], hideTemplates = false, showOnlyEnabled = false, showSlotLabels = false, toggleMode = "simple", overrides = {}, onOverrideChange, inheritedEnabledByAddon = {}, hideModelAndSettings = false, allowAutoModel = false }) {
56800
- const stepExtraProps = (addonId) => ({
56801
- toggleMode,
56802
- hideModelAndSettings,
56803
- allowAutoModel,
56804
- ...toggleMode === "threeState" ? {
56805
- overrideState: overrides[addonId] !== void 0 ? overrides[addonId] : null,
56806
- onOverrideChange: onOverrideChange ? (next) => onOverrideChange(addonId, next) : void 0,
56807
- inheritedEnabled: inheritedEnabledByAddon[addonId]
56808
- } : {}
56809
- });
56692
+ function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateId, onSelectTemplate, onSaveTemplate, onUpdateTemplate, onDeleteTemplate, readOnly = false, excludeAddons = [], hideTemplates = false, showOnlyEnabled = false, showSlotLabels = false }) {
56810
56693
  const excluded = useMemo(() => new Set(excludeAddons), [excludeAddons]);
56811
56694
  const schemaMap = useMemo(() => buildSchemaMap(schema), [schema]);
56812
56695
  const [warnings, setWarnings] = useState([]);
@@ -56913,8 +56796,7 @@ function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateI
56913
56796
  allSchemas: schemaMap,
56914
56797
  onChange: handleStepChange,
56915
56798
  onDelete: readOnly ? void 0 : (id) => onChange(steps.filter((s) => s.addonId !== id)),
56916
- readOnly,
56917
- ...stepExtraProps(step.addonId)
56799
+ readOnly
56918
56800
  }), (step.children.length > 0 || childPlaceholders.length > 0) && /* @__PURE__ */ jsxs("div", {
56919
56801
  className: "ml-4 pl-3 border-l border-border/60 space-y-1.5",
56920
56802
  children: [
@@ -56943,8 +56825,7 @@ function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateI
56943
56825
  children: step.children.filter((c) => c.addonId !== id)
56944
56826
  });
56945
56827
  },
56946
- readOnly,
56947
- ...stepExtraProps(child.addonId)
56828
+ readOnly
56948
56829
  }), (child.children.length > 0 || childChildPlaceholders.length > 0) && /* @__PURE__ */ jsxs("div", {
56949
56830
  className: "ml-4 pl-3 border-l border-border/40 space-y-1.5",
56950
56831
  children: [
@@ -56975,8 +56856,7 @@ function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateI
56975
56856
  } : c)
56976
56857
  });
56977
56858
  },
56978
- readOnly,
56979
- ...stepExtraProps(grandchild.addonId)
56859
+ readOnly
56980
56860
  }, grandchild.addonId)),
56981
56861
  !readOnly && childChildPlaceholders.map((addon) => /* @__PURE__ */ jsx(PlaceholderStep, {
56982
56862
  addon,
@@ -57136,179 +57016,6 @@ function PipelineRuntimeSelector({ options, value, onChange }) {
57136
57016
  });
57137
57017
  }
57138
57018
  //#endregion
57139
- //#region src/composites/pipeline-tree-matrix.tsx
57140
- var STEP_COL_REM = 18;
57141
- function QuickToggle({ enabled, onChange, disabled }) {
57142
- return /* @__PURE__ */ jsx("button", {
57143
- type: "button",
57144
- role: "switch",
57145
- "aria-checked": enabled,
57146
- disabled,
57147
- onClick: (e) => {
57148
- e.stopPropagation();
57149
- onChange(!enabled);
57150
- },
57151
- className: cn("relative inline-flex h-3.5 w-7 shrink-0 items-center rounded-full transition-colors", enabled ? "bg-emerald-500" : "bg-foreground-subtle/30", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
57152
- title: enabled ? "Click to disable" : "Click to enable",
57153
- children: /* @__PURE__ */ jsx("span", { className: cn("inline-block h-3 w-3 rounded-full bg-white shadow transition-transform", enabled ? "translate-x-3.5" : "translate-x-0.5") })
57154
- });
57155
- }
57156
- function GridRow({ node, depth, agents, getCellState, onCellClick, selectedCell, toggleProps }) {
57157
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
57158
- className: "sticky left-0 z-10 bg-surface px-3 py-2 border-b border-border text-xs flex items-start gap-2 min-w-0",
57159
- style: { paddingLeft: `${12 + depth * 14}px` },
57160
- children: [/* @__PURE__ */ jsx(StepLabel, { node }), toggleProps && /* @__PURE__ */ jsx("span", {
57161
- className: "pl-2 pt-0.5 shrink-0",
57162
- children: /* @__PURE__ */ jsx(QuickToggle, {
57163
- enabled: toggleProps.enabled,
57164
- onChange: toggleProps.onChange,
57165
- disabled: toggleProps.disabled
57166
- })
57167
- })]
57168
- }), agents.map((a) => {
57169
- const state = getCellState(node.addonId, a);
57170
- return /* @__PURE__ */ jsx("button", {
57171
- type: "button",
57172
- onClick: () => onCellClick(node.addonId, a),
57173
- className: cellButtonClass(state, selectedCell !== null && selectedCell.addonId === node.addonId && agentColumnKey(selectedCell) === agentColumnKey(a), "min-w-0 overflow-hidden px-3 py-1.5 border-b border-l border-border"),
57174
- children: renderCellContent(state)
57175
- }, agentColumnKey(a));
57176
- })] });
57177
- }
57178
- /**
57179
- * Wide layout: horizontally self-scrolling matrix. The scroll lives INSIDE
57180
- * this `overflow-auto` box (sticky first column + sticky header row) so the
57181
- * page body never scrolls sideways. Column tracks are fixed px widths so the
57182
- * grid is static regardless of content.
57183
- */
57184
- function MatrixGrid({ rows, agents, getCellState, onCellClick, selectedCell, onToggleEnabled }) {
57185
- const gridTemplate = `${STEP_COL_REM}rem repeat(${agents.length}, 13rem)`;
57186
- const showToggle = onToggleEnabled !== void 0 && agents.length === 1;
57187
- const onlyAgent = agents[0];
57188
- const groups = groupAgentColumns(agents);
57189
- return /* @__PURE__ */ jsx("div", {
57190
- className: "overflow-auto border border-border rounded",
57191
- children: /* @__PURE__ */ jsxs("div", {
57192
- className: "grid w-max",
57193
- style: { gridTemplateColumns: gridTemplate },
57194
- children: [
57195
- /* @__PURE__ */ jsx("div", {
57196
- className: "sticky top-0 left-0 z-20 bg-muted/60 px-3 py-2 text-[10px] uppercase tracking-widest text-foreground-subtle border-b border-border",
57197
- children: "Step"
57198
- }),
57199
- groups.map((group) => group.grouped ? /* @__PURE__ */ jsx(GroupedAgentHeader, { group }, group.agentNodeId) : group.columns.map((col) => /* @__PURE__ */ jsxs("div", {
57200
- className: "sticky top-0 z-10 min-w-0 bg-muted/60 px-3 py-2 border-b border-l border-border",
57201
- children: [/* @__PURE__ */ jsx("div", {
57202
- className: "text-xs font-semibold text-foreground truncate",
57203
- children: col.agentNodeId
57204
- }), /* @__PURE__ */ jsx("div", {
57205
- className: "text-[10px] text-foreground-subtle truncate",
57206
- children: col.engineLabel
57207
- })]
57208
- }, agentColumnKey(col)))),
57209
- rows.map(({ node, depth }) => {
57210
- const cellState = showToggle && onlyAgent !== void 0 ? getCellState(node.addonId, onlyAgent) : null;
57211
- return /* @__PURE__ */ jsx(GridRow, {
57212
- node,
57213
- depth,
57214
- agents,
57215
- getCellState,
57216
- onCellClick,
57217
- selectedCell,
57218
- toggleProps: showToggle && cellState !== null ? {
57219
- enabled: cellState.kind === "enabled",
57220
- onChange: (next) => onToggleEnabled?.(node.addonId, next),
57221
- disabled: cellState.kind === "na"
57222
- } : void 0
57223
- }, node.addonId);
57224
- })
57225
- ]
57226
- })
57227
- });
57228
- }
57229
- /**
57230
- * Narrow layout: one card per agent column, each listing every step stacked
57231
- * vertically. Feature-parity with the matrix — same `onCellClick`, same
57232
- * `renderCellContent`, same single-agent `onToggleEnabled`.
57233
- */
57234
- function StackedCards({ rows, agents, getCellState, onCellClick, selectedCell, onToggleEnabled }) {
57235
- const showToggle = onToggleEnabled !== void 0 && agents.length === 1;
57236
- return /* @__PURE__ */ jsx("div", {
57237
- className: "space-y-3",
57238
- children: agents.map((a) => /* @__PURE__ */ jsxs("div", {
57239
- className: "border border-border rounded overflow-hidden",
57240
- children: [/* @__PURE__ */ jsxs("div", {
57241
- className: "bg-muted/60 px-3 py-2 border-b border-border",
57242
- children: [/* @__PURE__ */ jsx("div", {
57243
- className: "text-xs font-semibold text-foreground truncate",
57244
- children: a.deviceLabel ? `${a.agentNodeId} · ${a.deviceLabel}` : a.agentNodeId
57245
- }), /* @__PURE__ */ jsx("div", {
57246
- className: "text-[10px] text-foreground-subtle truncate",
57247
- children: a.engineLabel
57248
- })]
57249
- }), /* @__PURE__ */ jsx("ul", { children: rows.map(({ node, depth }) => {
57250
- const state = getCellState(node.addonId, a);
57251
- const isSelected = selectedCell !== null && selectedCell.addonId === node.addonId && agentColumnKey(selectedCell) === agentColumnKey(a);
57252
- const toggleProps = showToggle && state !== null ? {
57253
- enabled: state.kind === "enabled",
57254
- onChange: (next) => onToggleEnabled?.(node.addonId, next),
57255
- disabled: state.kind === "na"
57256
- } : void 0;
57257
- return /* @__PURE__ */ jsx("li", {
57258
- className: "border-b border-border last:border-b-0",
57259
- children: /* @__PURE__ */ jsxs("div", {
57260
- className: "flex items-center gap-2",
57261
- children: [/* @__PURE__ */ jsxs("button", {
57262
- type: "button",
57263
- onClick: () => onCellClick(node.addonId, a),
57264
- className: cellButtonClass(state, isSelected, "flex flex-1 min-w-0 items-start justify-between gap-3 px-3 py-2"),
57265
- style: { paddingLeft: `${12 + depth * 14}px` },
57266
- children: [/* @__PURE__ */ jsx(StepLabel, { node }), /* @__PURE__ */ jsx("span", {
57267
- className: "shrink-0 max-w-[45%] pt-0.5",
57268
- children: renderCellContent(state)
57269
- })]
57270
- }), toggleProps && /* @__PURE__ */ jsx("span", {
57271
- className: "pr-3 shrink-0",
57272
- children: /* @__PURE__ */ jsx(QuickToggle, {
57273
- enabled: toggleProps.enabled,
57274
- onChange: toggleProps.onChange,
57275
- disabled: toggleProps.disabled
57276
- })
57277
- })]
57278
- })
57279
- }, node.addonId);
57280
- }) })]
57281
- }, agentColumnKey(a)))
57282
- });
57283
- }
57284
- function PipelineTreeMatrix({ tree, agents, getCellState, onCellClick, selectedCell, onToggleEnabled }) {
57285
- const rows = useMemo(() => flattenTree(tree), [tree]);
57286
- return /* @__PURE__ */ jsxs("div", {
57287
- className: "@container/matrix w-full",
57288
- children: [/* @__PURE__ */ jsx("div", {
57289
- className: "@2xl/matrix:hidden",
57290
- children: /* @__PURE__ */ jsx(StackedCards, {
57291
- rows,
57292
- agents,
57293
- getCellState,
57294
- onCellClick,
57295
- selectedCell,
57296
- onToggleEnabled
57297
- })
57298
- }), /* @__PURE__ */ jsx("div", {
57299
- className: "hidden @2xl/matrix:block",
57300
- children: /* @__PURE__ */ jsx(MatrixGrid, {
57301
- rows,
57302
- agents,
57303
- getCellState,
57304
- onCellClick,
57305
- selectedCell,
57306
- onToggleEnabled
57307
- })
57308
- })]
57309
- });
57310
- }
57311
- //#endregion
57312
57019
  //#region src/composites/provider-badge.tsx
57313
57020
  var providerConfig = {
57314
57021
  onvif: {
@@ -57752,89 +57459,6 @@ function validateSelector(selector) {
57752
57459
  }
57753
57460
  }
57754
57461
  //#endregion
57755
- //#region src/composites/slide-over-panel.tsx
57756
- /**
57757
- * SlideOverPanel — a detail surface anchored to context on desktop and to the
57758
- * viewport on mobile.
57759
- *
57760
- * - **Desktop (`md+`):** an in-container, NON-modal slide-over pinned to the
57761
- * right edge of the nearest positioned ancestor. The host reserves space with
57762
- * a matching `md:pr-*` so the panel sits beside its content (e.g. the
57763
- * multi-node pipeline matrix), not over it.
57764
- * - **Mobile (`< md`):** a MODAL bottom sheet pinned to the viewport
57765
- * (`position: fixed`). It never derives its size from the surrounding
57766
- * container, so it can't stretch across a horizontally-laid-out node matrix
57767
- * and overflow the page — the previous behaviour when it was a fixed-width
57768
- * `absolute` panel anchored to the wide matrix wrapper.
57769
- *
57770
- * The whole desktop⇄mobile transform is pure Tailwind responsive classes on one
57771
- * element — no layout-shift on hydration, no portal. JS is used only to lock
57772
- * body scroll behind the mobile sheet and to wire Escape-to-close.
57773
- */
57774
- function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widthClass = "md:w-[360px]" }) {
57775
- const isMobile = useIsMobile();
57776
- useEffect(() => {
57777
- if (!open) return;
57778
- const onEsc = (e) => {
57779
- if (e.key === "Escape") onClose();
57780
- };
57781
- window.addEventListener("keydown", onEsc);
57782
- return () => window.removeEventListener("keydown", onEsc);
57783
- }, [open, onClose]);
57784
- useEffect(() => {
57785
- if (!open || !isMobile) return;
57786
- const previous = document.body.style.overflow;
57787
- document.body.style.overflow = "hidden";
57788
- return () => {
57789
- document.body.style.overflow = previous;
57790
- };
57791
- }, [open, isMobile]);
57792
- if (!open) return null;
57793
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
57794
- className: "fixed inset-0 z-40 bg-black/50 md:hidden",
57795
- onClick: onClose,
57796
- "aria-hidden": "true"
57797
- }), /* @__PURE__ */ jsxs("aside", {
57798
- className: cn("fixed inset-x-0 bottom-0 z-50 flex flex-col", "max-h-[85dvh] rounded-t-2xl border-t border-border", "bg-surface shadow-2xl pb-[env(safe-area-inset-bottom)]", "md:absolute md:inset-x-auto md:top-0 md:right-0 md:bottom-0 md:z-20", "md:max-h-none md:rounded-none md:border-t-0 md:border-l md:pb-0", widthClass),
57799
- role: "dialog",
57800
- "aria-modal": isMobile ? "true" : "false",
57801
- children: [
57802
- /* @__PURE__ */ jsx("div", {
57803
- className: "flex shrink-0 justify-center pt-2 pb-1 md:hidden",
57804
- "aria-hidden": "true",
57805
- children: /* @__PURE__ */ jsx("div", { className: "h-1 w-9 rounded-full bg-foreground-subtle/30" })
57806
- }),
57807
- /* @__PURE__ */ jsxs("header", {
57808
- className: "flex shrink-0 items-start justify-between gap-2 px-4 py-3 border-b border-border",
57809
- children: [/* @__PURE__ */ jsxs("div", {
57810
- className: "min-w-0",
57811
- children: [/* @__PURE__ */ jsx("div", {
57812
- className: "text-sm font-semibold text-foreground truncate",
57813
- children: title
57814
- }), subtitle !== void 0 && /* @__PURE__ */ jsx("div", {
57815
- className: "text-[11px] text-foreground-subtle mt-0.5 truncate",
57816
- children: subtitle
57817
- })]
57818
- }), /* @__PURE__ */ jsx("button", {
57819
- type: "button",
57820
- onClick: onClose,
57821
- className: "p-1 rounded hover:bg-muted text-foreground-subtle hover:text-foreground",
57822
- "aria-label": "Close panel",
57823
- children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
57824
- })]
57825
- }),
57826
- /* @__PURE__ */ jsx("div", {
57827
- className: "flex-1 min-h-0 overflow-y-auto overscroll-contain px-4 py-3",
57828
- children
57829
- }),
57830
- footer !== void 0 && /* @__PURE__ */ jsx("footer", {
57831
- className: "flex shrink-0 items-center gap-2 justify-end px-4 py-3 border-t border-border",
57832
- children: footer
57833
- })
57834
- ]
57835
- })] });
57836
- }
57837
- //#endregion
57838
57462
  //#region src/composites/snapshot-button.tsx
57839
57463
  /**
57840
57464
  * SnapshotButton — operator-facing manual snapshot trigger.
@@ -58020,51 +57644,725 @@ function StepTimings({ timings, totalMs, className }) {
58020
57644
  });
58021
57645
  }
58022
57646
  //#endregion
58023
- //#region src/composites/step-tree-master.tsx
58024
- var DOT_COLOR = {
58025
- inherit: "bg-muted",
58026
- on: "bg-emerald-500",
58027
- off: "bg-orange-500",
58028
- na: "bg-gray-300 opacity-50"
58029
- };
58030
- function TreeRow({ node, depth, selectedAddonId, onSelect, agentDots }) {
58031
- const isSelected = node.addonId === selectedAddonId;
58032
- const dots = agentDots?.[node.addonId] ?? [];
58033
- return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("button", {
57647
+ //#region src/composites/step-inspector/accelerator-tabs.tsx
57648
+ function AcceleratorTabs({ items, selectedId, onSelect }) {
57649
+ const onKeyDown = (e, index) => {
57650
+ const delta = e.key === "ArrowRight" ? 1 : e.key === "ArrowLeft" ? -1 : 0;
57651
+ if (delta === 0) return;
57652
+ e.preventDefault();
57653
+ const next = items[(index + delta + items.length) % items.length];
57654
+ if (next !== void 0) onSelect(next.id);
57655
+ };
57656
+ return /* @__PURE__ */ jsx("div", {
57657
+ role: "tablist",
57658
+ "aria-label": "Accelerator",
57659
+ className: "-mx-1 flex min-w-0 flex-nowrap gap-1 overflow-x-auto px-1 pb-0.5",
57660
+ children: items.map((item, index) => {
57661
+ const selected = item.id === selectedId;
57662
+ return /* @__PURE__ */ jsxs("button", {
57663
+ type: "button",
57664
+ role: "tab",
57665
+ "aria-selected": selected,
57666
+ "aria-label": item.marked ? `${item.label} (camera override)` : item.label,
57667
+ tabIndex: selected ? 0 : -1,
57668
+ onClick: () => onSelect(item.id),
57669
+ onKeyDown: (e) => onKeyDown(e, index),
57670
+ className: cn("inline-flex h-9 shrink-0 items-center gap-1 whitespace-nowrap rounded-md border px-2.5 text-[11px] font-medium transition-colors md:h-7", selected ? "border-primary/50 bg-primary/15 text-primary" : "border-border text-foreground-subtle hover:bg-surface-hover hover:text-foreground"),
57671
+ children: [item.label, item.marked && /* @__PURE__ */ jsx("span", {
57672
+ className: "h-1.5 w-1.5 rounded-full bg-amber-500",
57673
+ "aria-hidden": true
57674
+ })]
57675
+ }, item.id);
57676
+ })
57677
+ });
57678
+ }
57679
+ //#endregion
57680
+ //#region src/composites/step-inspector/gate-control.tsx
57681
+ /**
57682
+ * GateControl — whether ONE camera runs a step: Auto (the catalog default) /
57683
+ * On / Off. A per-camera, node-independent switch, written at once (it is not
57684
+ * part of the inspector's draft). `package-detection` is driven by package
57685
+ * zones and shows a badge instead.
57686
+ *
57687
+ * Segments are 36 px tall on a phone and 32 px from `md` up — the matrix this
57688
+ * replaced drew 26 px ones.
57689
+ */
57690
+ function activeChoice(gate) {
57691
+ if (!gate.explicit) return "auto";
57692
+ return gate.effectiveOn ? "on" : "off";
57693
+ }
57694
+ function GateControl({ gate, busy = false, onSet }) {
57695
+ if (gate.kind === "zone-driven") return /* @__PURE__ */ jsx("span", {
57696
+ className: "inline-flex items-center rounded-md border border-violet-500/40 bg-violet-500/10 px-2 py-1 text-[11px] font-medium text-violet-400",
57697
+ title: "Runs where this camera has package zones — set on the Zones tab",
57698
+ children: "Zones"
57699
+ });
57700
+ const active = activeChoice(gate);
57701
+ const segment = (choice, label, value, on) => /* @__PURE__ */ jsx("button", {
58034
57702
  type: "button",
58035
- onClick: () => onSelect(node.addonId),
58036
- className: cn("w-full flex items-center justify-between gap-2 text-left px-3 py-1.5 text-xs", "border-l-2", isSelected ? "bg-accent border-primary text-foreground font-medium" : "border-transparent hover:bg-muted/40 text-foreground"),
58037
- style: { paddingLeft: `${12 + depth * 14}px` },
58038
- children: [/* @__PURE__ */ jsx("span", {
58039
- className: "truncate",
58040
- children: node.addonName
58041
- }), dots.length > 0 && /* @__PURE__ */ jsx("span", {
58042
- className: "flex items-center gap-1 shrink-0",
58043
- children: dots.map((d) => /* @__PURE__ */ jsx("span", {
58044
- title: `${d.agentNodeId}: ${d.state}`,
58045
- className: cn("w-2 h-2 rounded-full", DOT_COLOR[d.state])
58046
- }, d.agentNodeId))
57703
+ role: "radio",
57704
+ "aria-checked": active === choice,
57705
+ disabled: busy,
57706
+ onClick: () => onSet(value),
57707
+ className: cn("h-9 min-w-12 px-3 text-xs font-medium transition-colors md:h-8", active === choice ? on : "text-foreground-subtle hover:bg-muted/60", busy && "cursor-not-allowed opacity-50"),
57708
+ children: label
57709
+ });
57710
+ return /* @__PURE__ */ jsxs("div", {
57711
+ className: "flex items-center gap-2",
57712
+ children: [/* @__PURE__ */ jsxs("div", {
57713
+ role: "radiogroup",
57714
+ "aria-label": "Runs on this camera",
57715
+ title: `Catalog default: ${gate.defaultOn ? "on" : "off"}`,
57716
+ className: "inline-flex overflow-hidden rounded-md border border-border",
57717
+ children: [
57718
+ segment("auto", "Auto", null, "bg-primary/15 text-primary"),
57719
+ /* @__PURE__ */ jsx("span", {
57720
+ className: "w-px self-stretch bg-border",
57721
+ "aria-hidden": true
57722
+ }),
57723
+ segment("on", "On", true, "bg-emerald-500 text-white"),
57724
+ /* @__PURE__ */ jsx("span", {
57725
+ className: "w-px self-stretch bg-border",
57726
+ "aria-hidden": true
57727
+ }),
57728
+ segment("off", "Off", false, "bg-foreground-subtle/70 text-white")
57729
+ ]
57730
+ }), /* @__PURE__ */ jsxs("span", {
57731
+ className: "hidden text-[10px] text-foreground-subtle @3xl/inspector:inline",
57732
+ children: ["default: ", gate.defaultOn ? "on" : "off"]
58047
57733
  })]
58048
- }), node.children.map((child) => /* @__PURE__ */ jsx(TreeRow, {
58049
- node: child,
58050
- depth: depth + 1,
58051
- selectedAddonId,
58052
- onSelect,
58053
- agentDots
58054
- }, child.addonId))] });
57734
+ });
57735
+ }
57736
+ /** The gate as a short list-row badge. */
57737
+ function GateBadge({ gate }) {
57738
+ if (gate.kind === "zone-driven") return /* @__PURE__ */ jsx("span", {
57739
+ className: "shrink-0 text-[9px] font-semibold uppercase text-violet-400",
57740
+ children: "zones"
57741
+ });
57742
+ const on = gate.effectiveOn;
57743
+ return /* @__PURE__ */ jsx("span", {
57744
+ className: cn("shrink-0 rounded px-1.5 py-px text-[9px] font-semibold uppercase", on ? "bg-emerald-500/15 text-emerald-500" : "bg-muted text-foreground-subtle", gate.explicit && "ring-1 ring-inset ring-current"),
57745
+ title: gate.explicit ? "Set for this camera" : "Catalog default",
57746
+ children: on ? "on" : "off"
57747
+ });
57748
+ }
57749
+ //#endregion
57750
+ //#region src/composites/step-inspector/segmented-choice.tsx
57751
+ /**
57752
+ * SegmentedChoice — a small, labelled single-choice group (a radiogroup of
57753
+ * buttons): which layer the inspector's settings edit ("All accelerators" /
57754
+ * "Only hub · NPU"). 36 px tall on a phone, 28 px from `md` up.
57755
+ */
57756
+ function SegmentedChoice({ label, options, value, onChange }) {
57757
+ return /* @__PURE__ */ jsx("div", {
57758
+ role: "radiogroup",
57759
+ "aria-label": label,
57760
+ className: "flex flex-wrap items-center gap-1",
57761
+ children: options.map((option) => /* @__PURE__ */ jsx("button", {
57762
+ type: "button",
57763
+ role: "radio",
57764
+ "aria-checked": value === option.value,
57765
+ onClick: () => onChange(option.value),
57766
+ className: cn("h-9 rounded-md border px-2.5 text-[11px] font-medium transition-colors md:h-7", value === option.value ? "border-primary/50 bg-primary/15 text-primary" : "border-border text-foreground-subtle hover:bg-surface-hover hover:text-foreground"),
57767
+ children: option.label
57768
+ }, option.value))
57769
+ });
57770
+ }
57771
+ //#endregion
57772
+ //#region src/composites/step-inspector/step-chips.tsx
57773
+ function chipText(state) {
57774
+ switch (state.kind) {
57775
+ case "enabled":
57776
+ if (state.suppliedByRoot !== void 0) return "root";
57777
+ return state.jumpTo !== void 0 ? `→ ${state.jumpTo}` : state.modelId;
57778
+ case "skip": return state.jumpTo !== void 0 ? `→ ${state.jumpTo}` : "skip";
57779
+ case "disabled": return "off";
57780
+ case "na": return "—";
57781
+ }
57782
+ }
57783
+ /** What a chip MEANS — the full model id, not its shortened text. */
57784
+ function chipKey(state) {
57785
+ return state.kind === "enabled" ? `${state.modelId}|${chipText(state)}` : chipText(state);
57786
+ }
57787
+ function chipTone(state, selected) {
57788
+ if (selected) return "border-primary/60 text-primary";
57789
+ if (state.kind === "skip" && state.jumpTo === void 0) return "border-amber-500/40 text-amber-500";
57790
+ if (state.kind === "na" || state.kind === "disabled") return "border-border/60 text-foreground-subtle/70";
57791
+ return "border-border text-foreground-subtle";
57792
+ }
57793
+ function StepChips({ chips, selectedId }) {
57794
+ const first = chips[0];
57795
+ if (first !== void 0 && chips.length > 1 && chips.every((c) => chipKey(c.state) === chipKey(first.state) && !(c.state.kind === "enabled" && c.state.overridden === true) && chipTone(c.state, c.id === selectedId) === chipTone(first.state, first.id === selectedId)) && first !== void 0) {
57796
+ const text = chipText(first.state);
57797
+ return /* @__PURE__ */ jsx("span", {
57798
+ className: "flex flex-wrap gap-1",
57799
+ children: /* @__PURE__ */ jsxs("span", {
57800
+ title: `${text} on ${chips.map((c) => c.label).join(", ")}`,
57801
+ className: cn("inline-flex max-w-[12rem] items-center gap-1 truncate rounded border px-1 font-mono text-[9px] leading-4", chipTone(first.state, first.id === selectedId)),
57802
+ children: [/* @__PURE__ */ jsx("span", {
57803
+ className: "truncate",
57804
+ children: text
57805
+ }), /* @__PURE__ */ jsxs("span", {
57806
+ className: "shrink-0 font-sans text-foreground-subtle/80",
57807
+ children: ["×", chips.length]
57808
+ })]
57809
+ })
57810
+ });
57811
+ }
57812
+ return /* @__PURE__ */ jsx("span", {
57813
+ className: "flex flex-wrap gap-1",
57814
+ children: chips.map((chip) => {
57815
+ const overridden = chip.state.kind === "enabled" && chip.state.overridden === true;
57816
+ const text = chipText(chip.state);
57817
+ return /* @__PURE__ */ jsxs("span", {
57818
+ title: `${chip.label}: ${chip.state.kind === "enabled" ? chip.state.modelId : text}${overridden ? " (camera override)" : ""}`,
57819
+ className: cn("inline-flex max-w-[9rem] items-center gap-0.5 truncate rounded border px-1 font-mono text-[9px] leading-4", chipTone(chip.state, chip.id === selectedId)),
57820
+ children: [/* @__PURE__ */ jsx("span", {
57821
+ className: "truncate",
57822
+ children: text
57823
+ }), overridden && /* @__PURE__ */ jsx("span", {
57824
+ className: "text-amber-500",
57825
+ "aria-hidden": true,
57826
+ children: "•"
57827
+ })]
57828
+ }, chip.id);
57829
+ })
57830
+ });
57831
+ }
57832
+ //#endregion
57833
+ //#region src/composites/step-inspector/step-inspector-layout.tsx
57834
+ /**
57835
+ * StepInspectorLayout — the master–detail frame of the step inspector.
57836
+ *
57837
+ * Desktop: the step list and the inspector side by side, each scrolling on its
57838
+ * own, in a block whose height FILLS the page's scroll container below it. So
57839
+ * neither pane depends on the page scroll position: the inspector's header and
57840
+ * save bar are always on screen, and the selected step stays visible in the
57841
+ * list. (The slide-over this replaced was absolutely positioned inside the
57842
+ * matrix block — its title and its Save button scrolled away with the page.)
57843
+ * In a narrow container (the camera page beside its live view, a tablet) the
57844
+ * two panes stack: the list on top, a third of the height.
57845
+ *
57846
+ * Phone: the list flows with the page; the inspector opens as a full-screen
57847
+ * sheet with "‹ Steps" to go back.
57848
+ */
57849
+ /** The tallest the inspector block can be without making its scroll container scroll. */
57850
+ function fillHeightPx(input) {
57851
+ const room = input.scrollerHeight - input.paddingBottom - input.offsetInScroller;
57852
+ return Math.max(input.minPx, Math.floor(room));
57853
+ }
57854
+ function scrollParentOf(el) {
57855
+ for (let p = el.parentElement; p !== null; p = p.parentElement) {
57856
+ const { overflowY } = getComputedStyle(p);
57857
+ if (overflowY === "auto" || overflowY === "scroll") return p;
57858
+ }
57859
+ return null;
57860
+ }
57861
+ /** Height of the block so that it ends at the bottom of its scroll container. */
57862
+ function useFillHeight(enabled, minPx) {
57863
+ const ref = useRef(null);
57864
+ const [height, setHeight] = useState(null);
57865
+ useLayoutEffect(() => {
57866
+ const el = ref.current;
57867
+ if (!enabled || el === null) return;
57868
+ const scroller = scrollParentOf(el);
57869
+ const measure = () => {
57870
+ const box = scroller ?? document.documentElement;
57871
+ const style = getComputedStyle(box);
57872
+ const top = scroller ? scroller.getBoundingClientRect().top : 0;
57873
+ const scrollTop = scroller ? scroller.scrollTop : window.scrollY;
57874
+ setHeight(fillHeightPx({
57875
+ scrollerHeight: scroller ? scroller.clientHeight : window.innerHeight,
57876
+ paddingBottom: Number.parseFloat(style.paddingBottom) || 0,
57877
+ offsetInScroller: el.getBoundingClientRect().top - top + scrollTop,
57878
+ minPx
57879
+ }));
57880
+ };
57881
+ measure();
57882
+ const RO = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
57883
+ if (scroller) RO?.observe(scroller);
57884
+ if (el.parentElement) RO?.observe(el.parentElement);
57885
+ window.addEventListener("resize", measure);
57886
+ return () => {
57887
+ RO?.disconnect();
57888
+ window.removeEventListener("resize", measure);
57889
+ };
57890
+ }, [enabled, minPx]);
57891
+ return {
57892
+ ref,
57893
+ height
57894
+ };
58055
57895
  }
58056
- function StepTreeMaster({ tree, selectedAddonId, onSelect, agentDots, className }) {
57896
+ function StepInspectorLayout({ list, detail, mobileDetailOpen, onMobileClose, minHeightPx = 420, className }) {
57897
+ const isMobile = useIsMobile();
57898
+ const { ref, height } = useFillHeight(!isMobile, minHeightPx);
57899
+ if (isMobile) return /* @__PURE__ */ jsxs("div", {
57900
+ className: cn("space-y-3", className),
57901
+ children: [/* @__PURE__ */ jsx("div", {
57902
+ className: SECTION_CARD,
57903
+ children: list
57904
+ }), /* @__PURE__ */ jsx(Dialog, {
57905
+ open: mobileDetailOpen,
57906
+ onOpenChange: (open) => !open && onMobileClose(),
57907
+ children: /* @__PURE__ */ jsx(DialogContent, {
57908
+ placement: "sheet-on-mobile",
57909
+ scroll: "body",
57910
+ className: "h-[100dvh] max-h-none w-full max-w-full rounded-none border-0 p-0 pt-[env(safe-area-inset-top)] pb-[env(safe-area-inset-bottom)]",
57911
+ children: mobileDetailOpen && detail
57912
+ })
57913
+ })]
57914
+ });
58057
57915
  return /* @__PURE__ */ jsx("div", {
58058
- className: cn("flex flex-col py-2", className),
58059
- children: tree.map((node) => /* @__PURE__ */ jsx(TreeRow, {
58060
- node,
58061
- depth: 0,
58062
- selectedAddonId,
58063
- onSelect,
58064
- agentDots
58065
- }, node.addonId))
57916
+ ref,
57917
+ className: cn("@container/inspector", className),
57918
+ style: height !== null ? { height } : void 0,
57919
+ children: /* @__PURE__ */ jsxs("div", {
57920
+ className: cn("grid h-full min-h-0 gap-3", "grid-cols-1 grid-rows-[minmax(9rem,32%)_minmax(0,1fr)]", "@xl/inspector:grid-cols-[minmax(14rem,19rem)_minmax(0,1fr)] @xl/inspector:grid-rows-1"),
57921
+ children: [/* @__PURE__ */ jsx("div", {
57922
+ className: cn(SECTION_CARD, "flex min-h-0 flex-col"),
57923
+ children: list
57924
+ }), /* @__PURE__ */ jsx("div", {
57925
+ className: cn(SECTION_CARD, "flex min-h-0 flex-col"),
57926
+ children: detail
57927
+ })]
57928
+ })
57929
+ });
57930
+ }
57931
+ /** "‹ Steps" — the phone sheet's way back to the list. */
57932
+ function BackToStepsButton({ onClick }) {
57933
+ return /* @__PURE__ */ jsxs("button", {
57934
+ type: "button",
57935
+ onClick,
57936
+ className: "inline-flex h-9 items-center gap-0.5 rounded-md border border-border px-2 text-xs text-foreground hover:bg-surface-hover",
57937
+ children: [/* @__PURE__ */ jsx(ChevronLeft, {
57938
+ className: "h-3.5 w-3.5",
57939
+ "aria-hidden": true
57940
+ }), "Steps"]
58066
57941
  });
58067
57942
  }
57943
+ //#endregion
57944
+ //#region src/composites/step-inspector/step-inspector-panel.tsx
57945
+ /**
57946
+ * StepInspectorPanel — the detail pane of the step inspector: a pinned header
57947
+ * (the step, its gate, the accelerator tabs), ONE scrolling body, and a pinned
57948
+ * save bar. Nothing in it depends on the page's scroll position — the slide-over
57949
+ * it replaced was anchored to the matrix block and scrolled away with it.
57950
+ */
57951
+ function SaveBar({ dirtyCount, saving, status, error, onSave, onDiscard }) {
57952
+ const dirty = dirtyCount > 0;
57953
+ const message = saving ? "Saving…" : dirty ? `${dirtyCount} unsaved change${dirtyCount === 1 ? "" : "s"}` : status === "saved" ? "Saved" : status === "error" ? error ?? "Save failed" : "No unsaved changes";
57954
+ return /* @__PURE__ */ jsxs("footer", {
57955
+ className: "flex shrink-0 items-center gap-2 border-t border-border bg-surface px-4 py-2 pb-[max(0.5rem,env(safe-area-inset-bottom))] md:pb-2",
57956
+ children: [
57957
+ /* @__PURE__ */ jsx("span", {
57958
+ role: "status",
57959
+ className: cn("min-w-0 flex-1 truncate text-[11px]", status === "error" && !dirty ? "text-danger" : dirty ? "text-amber-500" : "text-foreground-subtle"),
57960
+ children: message
57961
+ }),
57962
+ /* @__PURE__ */ jsx(Button, {
57963
+ variant: "outline",
57964
+ size: "md",
57965
+ disabled: !dirty || saving,
57966
+ onClick: onDiscard,
57967
+ children: "Discard"
57968
+ }),
57969
+ /* @__PURE__ */ jsx(Button, {
57970
+ variant: "primary",
57971
+ size: "md",
57972
+ disabled: !dirty || saving,
57973
+ onClick: onSave,
57974
+ children: "Save"
57975
+ })
57976
+ ]
57977
+ });
57978
+ }
57979
+ var StepInspectorPanel = forwardRef(function StepInspectorPanel({ title, subtitle, headerActions, headerExtra, leading, saveBar, onEscape, children, className }, headingRef) {
57980
+ const headingId = useId();
57981
+ const onKeyDown = (e) => {
57982
+ if (e.key !== "Escape" || onEscape === void 0) return;
57983
+ e.stopPropagation();
57984
+ onEscape();
57985
+ };
57986
+ return /* @__PURE__ */ jsxs("section", {
57987
+ "aria-labelledby": headingId,
57988
+ onKeyDown,
57989
+ className: cn("flex min-h-0 flex-1 flex-col overflow-hidden bg-surface", className),
57990
+ children: [
57991
+ /* @__PURE__ */ jsxs("header", {
57992
+ className: "shrink-0 space-y-2 border-b border-border px-4 py-2.5",
57993
+ children: [/* @__PURE__ */ jsxs("div", {
57994
+ className: "flex flex-wrap items-start gap-x-3 gap-y-2",
57995
+ children: [
57996
+ leading,
57997
+ /* @__PURE__ */ jsxs("div", {
57998
+ className: "min-w-[9rem] flex-1",
57999
+ children: [/* @__PURE__ */ jsx("h2", {
58000
+ id: headingId,
58001
+ ref: headingRef,
58002
+ tabIndex: -1,
58003
+ className: "truncate text-sm font-semibold text-foreground outline-none focus-visible:ring-2 focus-visible:ring-primary rounded",
58004
+ children: title
58005
+ }), subtitle !== void 0 && /* @__PURE__ */ jsx("div", {
58006
+ className: "mt-0.5 text-[11px] text-foreground-subtle",
58007
+ children: subtitle
58008
+ })]
58009
+ }),
58010
+ headerActions
58011
+ ]
58012
+ }), headerExtra]
58013
+ }),
58014
+ /* @__PURE__ */ jsx("div", {
58015
+ "data-inspector-body": true,
58016
+ className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-3",
58017
+ children
58018
+ }),
58019
+ saveBar !== void 0 && /* @__PURE__ */ jsx(SaveBar, { ...saveBar })
58020
+ ]
58021
+ });
58022
+ });
58023
+ //#endregion
58024
+ //#region src/composites/step-inspector/step-list.tsx
58025
+ /**
58026
+ * StepList — the master pane of the step inspector: every detection step of the
58027
+ * tree, one compact row each, as ONE tab stop.
58028
+ *
58029
+ * Keyboard (a listbox with a roving tabindex): ↑/↓/Home/End move the selection,
58030
+ * Enter or → hands focus to the inspector, `/` jumps to the search box. The
58031
+ * search matches a step's name or any of its field labels, so a question about
58032
+ * a knob ("face size", "person") finds the step that owns it; Enter in the box
58033
+ * selects the first hit and says which field it matched.
58034
+ */
58035
+ function matches(text, tokens) {
58036
+ const lower = text.toLowerCase();
58037
+ return tokens.every((t) => lower.includes(t));
58038
+ }
58039
+ /** Rows matching `query` (all tokens in the name, or all in one field label). */
58040
+ function searchSteps(rows, query) {
58041
+ const tokens = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
58042
+ if (tokens.length === 0) return rows.map((row) => ({ row }));
58043
+ const hits = [];
58044
+ for (const row of rows) {
58045
+ if (matches(row.name, tokens)) {
58046
+ hits.push({ row });
58047
+ continue;
58048
+ }
58049
+ const field = row.fieldLabels.find((l) => matches(l, tokens));
58050
+ if (field !== void 0) hits.push({
58051
+ row,
58052
+ matchedField: field
58053
+ });
58054
+ }
58055
+ return hits;
58056
+ }
58057
+ var StepList = forwardRef(function StepList({ rows, selectedId, onSelect, onActivate, onPick, label, className }, ref) {
58058
+ const [query, setQuery] = useState("");
58059
+ const listRef = useRef(null);
58060
+ const searchRef = useRef(null);
58061
+ const hits = useMemo(() => searchSteps(rows, query), [rows, query]);
58062
+ const tabStopId = hits.some((h) => h.row.addonId === selectedId) ? selectedId : hits[0]?.row.addonId ?? null;
58063
+ const pendingFocus = useRef(null);
58064
+ const tryFocus = (addonId) => {
58065
+ const el = listRef.current?.querySelector(`[data-step-id="${addonId}"]`);
58066
+ if (!el) return false;
58067
+ el.focus();
58068
+ return true;
58069
+ };
58070
+ const focusRow = (addonId) => {
58071
+ if (addonId === null) return;
58072
+ pendingFocus.current = tryFocus(addonId) ? null : addonId;
58073
+ };
58074
+ useLayoutEffect(() => {
58075
+ if (pendingFocus.current !== null && tryFocus(pendingFocus.current)) pendingFocus.current = null;
58076
+ });
58077
+ useImperativeHandle(ref, () => ({ focusSelected: () => focusRow(selectedId) }), [selectedId]);
58078
+ const move = (index) => {
58079
+ const target = hits[Math.max(0, Math.min(hits.length - 1, index))];
58080
+ if (target === void 0) return;
58081
+ onSelect(target.row.addonId, target.matchedField);
58082
+ focusRow(target.row.addonId);
58083
+ };
58084
+ const onRowKeyDown = (e, index, hit) => {
58085
+ switch (e.key) {
58086
+ case "ArrowDown":
58087
+ e.preventDefault();
58088
+ move(index + 1);
58089
+ return;
58090
+ case "ArrowUp":
58091
+ e.preventDefault();
58092
+ move(index - 1);
58093
+ return;
58094
+ case "Home":
58095
+ e.preventDefault();
58096
+ move(0);
58097
+ return;
58098
+ case "End":
58099
+ e.preventDefault();
58100
+ move(hits.length - 1);
58101
+ return;
58102
+ case "Enter":
58103
+ case "ArrowRight":
58104
+ e.preventDefault();
58105
+ onActivate(hit.row.addonId);
58106
+ return;
58107
+ case "/":
58108
+ e.preventDefault();
58109
+ searchRef.current?.focus();
58110
+ return;
58111
+ default:
58112
+ }
58113
+ };
58114
+ const onSearchKeyDown = (e) => {
58115
+ if (e.key === "Enter") {
58116
+ e.preventDefault();
58117
+ const first = hits[0];
58118
+ if (first !== void 0) {
58119
+ onSelect(first.row.addonId, first.matchedField);
58120
+ onPick?.(first.row.addonId);
58121
+ focusRow(first.row.addonId);
58122
+ }
58123
+ } else if (e.key === "Escape") {
58124
+ e.preventDefault();
58125
+ setQuery("");
58126
+ focusRow(selectedId);
58127
+ } else if (e.key === "ArrowDown") {
58128
+ e.preventDefault();
58129
+ focusRow(tabStopId);
58130
+ }
58131
+ };
58132
+ return /* @__PURE__ */ jsxs("div", {
58133
+ className: cn("flex min-h-0 flex-col", className),
58134
+ children: [/* @__PURE__ */ jsxs("div", {
58135
+ className: "relative shrink-0 border-b border-border p-1.5",
58136
+ children: [/* @__PURE__ */ jsx(Search, {
58137
+ className: "pointer-events-none absolute left-3.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-foreground-subtle",
58138
+ "aria-hidden": true
58139
+ }), /* @__PURE__ */ jsx("input", {
58140
+ ref: searchRef,
58141
+ type: "search",
58142
+ value: query,
58143
+ onChange: (e) => setQuery(e.target.value),
58144
+ onKeyDown: onSearchKeyDown,
58145
+ placeholder: "Find a step or setting /",
58146
+ "aria-label": "Find a step or setting",
58147
+ className: "h-9 w-full rounded-md border border-border bg-background pl-8 pr-2 text-xs text-foreground outline-none focus:border-primary focus:ring-1 focus:ring-primary/30 md:h-8"
58148
+ })]
58149
+ }), /* @__PURE__ */ jsxs("ul", {
58150
+ ref: listRef,
58151
+ role: "listbox",
58152
+ "aria-label": label,
58153
+ className: "min-h-0 flex-1 overflow-y-auto py-1",
58154
+ children: [hits.map((hit, index) => {
58155
+ const { row } = hit;
58156
+ const selected = row.addonId === selectedId;
58157
+ return /* @__PURE__ */ jsxs("li", {
58158
+ role: "option",
58159
+ "aria-selected": selected,
58160
+ tabIndex: row.addonId === tabStopId ? 0 : -1,
58161
+ "data-step-id": row.addonId,
58162
+ onClick: () => {
58163
+ onSelect(row.addonId, hit.matchedField);
58164
+ onPick?.(row.addonId);
58165
+ },
58166
+ onKeyDown: (e) => onRowKeyDown(e, index, hit),
58167
+ className: cn("cursor-pointer border-l-2 py-1 pl-2.5 pr-3 outline-none transition-colors", "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary", selected ? "border-primary bg-primary/10" : "border-transparent hover:bg-muted/40"),
58168
+ children: [
58169
+ /* @__PURE__ */ jsxs("div", {
58170
+ className: "flex min-w-0 items-baseline gap-2",
58171
+ children: [
58172
+ /* @__PURE__ */ jsx("span", {
58173
+ className: "w-[4.5rem] shrink-0 truncate",
58174
+ children: /* @__PURE__ */ jsx(SlotHeading, { slot: row.slot })
58175
+ }),
58176
+ /* @__PURE__ */ jsxs("span", {
58177
+ className: cn("min-w-0 flex-1 truncate text-xs font-medium", selected ? "text-foreground" : "text-foreground/90"),
58178
+ style: { paddingLeft: `${row.depth * 12}px` },
58179
+ children: [row.depth > 0 && /* @__PURE__ */ jsx("span", {
58180
+ className: "mr-1 text-foreground-subtle/60",
58181
+ "aria-hidden": true,
58182
+ children: "└"
58183
+ }), row.name]
58184
+ }),
58185
+ row.status
58186
+ ]
58187
+ }),
58188
+ hit.matchedField !== void 0 && /* @__PURE__ */ jsxs("div", {
58189
+ className: "mt-0.5 truncate pl-[5rem] text-[10px] text-primary",
58190
+ children: ["↳ ", hit.matchedField]
58191
+ }),
58192
+ row.detail !== void 0 && /* @__PURE__ */ jsx("div", {
58193
+ className: "mt-0.5 pl-[5rem]",
58194
+ children: row.detail
58195
+ })
58196
+ ]
58197
+ }, row.addonId);
58198
+ }), hits.length === 0 && /* @__PURE__ */ jsxs("li", {
58199
+ className: "px-3 py-4 text-center text-[11px] text-foreground-subtle",
58200
+ children: [
58201
+ "No step matches “",
58202
+ query,
58203
+ "”."
58204
+ ]
58205
+ })]
58206
+ })]
58207
+ });
58208
+ });
58209
+ //#endregion
58210
+ //#region src/composites/step-inspector/step-model-row.tsx
58211
+ var SOURCE_TONE = {
58212
+ camera: "border-primary/40 bg-primary/10 text-primary",
58213
+ node: "border-border bg-muted/40 text-foreground",
58214
+ default: "border-border/60 text-foreground-subtle",
58215
+ cluster: "border-primary/40 bg-primary/5 text-primary"
58216
+ };
58217
+ function StepModelRow({ label, format, modelId, source, sourceLabel, models, defaultModelId, expanded, onToggle, onChangeModel, onReset, resetLabel = "Reset", note, extra, changed = false, disabled = false }) {
58218
+ const pickable = models.length > 0 && note === void 0;
58219
+ const canExpand = pickable || extra !== void 0;
58220
+ return /* @__PURE__ */ jsxs("div", {
58221
+ className: cn("rounded-md border border-border", expanded && "bg-muted/10"),
58222
+ children: [
58223
+ /* @__PURE__ */ jsxs("div", {
58224
+ className: cn(LIST_ROW, "space-y-1"),
58225
+ children: [/* @__PURE__ */ jsxs("div", {
58226
+ className: "flex flex-wrap items-center gap-x-2 gap-y-1 text-xs",
58227
+ children: [
58228
+ /* @__PURE__ */ jsx("span", {
58229
+ className: "font-medium text-foreground",
58230
+ children: label
58231
+ }),
58232
+ /* @__PURE__ */ jsx("span", {
58233
+ className: "text-[10px] text-foreground-subtle",
58234
+ children: format
58235
+ }),
58236
+ /* @__PURE__ */ jsx("span", {
58237
+ className: cn("ml-auto rounded border px-1.5 py-px text-[10px] font-medium", SOURCE_TONE[source]),
58238
+ children: sourceLabel
58239
+ })
58240
+ ]
58241
+ }), /* @__PURE__ */ jsxs("div", {
58242
+ className: "flex items-center gap-2",
58243
+ children: [
58244
+ /* @__PURE__ */ jsxs("span", {
58245
+ className: "min-w-0 flex-1 truncate font-mono text-xs text-foreground",
58246
+ children: [modelId ?? "—", changed && /* @__PURE__ */ jsx("span", {
58247
+ className: "ml-1 text-amber-500",
58248
+ children: "•"
58249
+ })]
58250
+ }),
58251
+ onReset !== void 0 && /* @__PURE__ */ jsx("button", {
58252
+ type: "button",
58253
+ className: "inline-flex items-center justify-center gap-1 rounded border border-border bg-surface px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-foreground hover:bg-surface-hover transition-colors disabled:opacity-40",
58254
+ disabled,
58255
+ onClick: onReset,
58256
+ children: resetLabel
58257
+ }),
58258
+ canExpand && /* @__PURE__ */ jsx("button", {
58259
+ type: "button",
58260
+ className: cn("inline-flex items-center justify-center gap-1 rounded border border-border bg-surface px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-foreground hover:bg-surface-hover transition-colors disabled:opacity-40", "min-h-9 md:min-h-0"),
58261
+ "aria-expanded": expanded,
58262
+ "aria-label": `Change model for ${label}`,
58263
+ disabled,
58264
+ onClick: onToggle,
58265
+ children: expanded ? "Done" : pickable ? "Change" : "Route"
58266
+ })
58267
+ ]
58268
+ })]
58269
+ }),
58270
+ note !== void 0 && /* @__PURE__ */ jsx("div", {
58271
+ className: "border-t border-border/60 px-3 py-1.5 text-[10px] leading-snug text-foreground-subtle",
58272
+ children: note
58273
+ }),
58274
+ expanded && canExpand && /* @__PURE__ */ jsxs("div", {
58275
+ className: "space-y-3 border-t border-border/60 px-3 py-3",
58276
+ children: [pickable && /* @__PURE__ */ jsx(ModelPicker, {
58277
+ models,
58278
+ value: modelId ?? "",
58279
+ defaultModelId,
58280
+ disabled,
58281
+ onChange: onChangeModel
58282
+ }), extra]
58283
+ })
58284
+ ]
58285
+ });
58286
+ }
58287
+ //#endregion
58288
+ //#region src/composites/step-inspector/step-model-list.tsx
58289
+ /**
58290
+ * StepModelList — the model section of the step inspector.
58291
+ *
58292
+ * While nothing is pinned, edited or worth a note, the accelerators are
58293
+ * summarised by model — one line per distinct model, naming the accelerators
58294
+ * that run it ("yolov9m-320-int8 · hub iGPU, hub NPU, little-unraid iGPU") —
58295
+ * with "Per accelerator" to open one `StepModelRow` each. Four near-identical
58296
+ * rows pushed the settings, the thing most edits are about, below the fold.
58297
+ * A pin, a pending change or a note (no build here, root-supplied) shows every
58298
+ * row, so nothing that differs from the default is ever folded away.
58299
+ */
58300
+ /** True when the rows can be summarised: nothing pinned here, edited, or noted. */
58301
+ function modelRowsAreFoldable(rows) {
58302
+ return rows.length >= 2 && rows.every((r) => r.note === void 0 && r.onReset === void 0 && r.changed !== true && !r.expanded);
58303
+ }
58304
+ function groupByModel(rows) {
58305
+ const groups = [];
58306
+ for (const row of rows) {
58307
+ const modelId = row.modelId ?? "—";
58308
+ const index = groups.findIndex((g) => g.modelId === modelId && g.sourceLabel === row.sourceLabel);
58309
+ const existing = groups[index];
58310
+ if (existing !== void 0) groups[index] = {
58311
+ ...existing,
58312
+ labels: [...existing.labels, row.label]
58313
+ };
58314
+ else groups.push({
58315
+ modelId,
58316
+ labels: [row.label],
58317
+ sourceLabel: row.sourceLabel
58318
+ });
58319
+ }
58320
+ return groups;
58321
+ }
58322
+ function StepModelList({ rows }) {
58323
+ const [open, setOpen] = useState(false);
58324
+ if (!open && modelRowsAreFoldable(rows)) {
58325
+ const groups = groupByModel(rows);
58326
+ return /* @__PURE__ */ jsxs("div", {
58327
+ className: cn("rounded-md border border-border", LIST_ROW),
58328
+ children: [/* @__PURE__ */ jsx("ul", {
58329
+ className: "space-y-1",
58330
+ children: groups.map((g) => /* @__PURE__ */ jsxs("li", {
58331
+ className: "flex flex-wrap items-baseline gap-x-2 text-xs",
58332
+ children: [
58333
+ /* @__PURE__ */ jsx("span", {
58334
+ className: "font-mono text-foreground",
58335
+ children: g.modelId
58336
+ }),
58337
+ /* @__PURE__ */ jsx("span", {
58338
+ className: "min-w-0 flex-1 text-[11px] text-foreground-subtle",
58339
+ children: g.labels.length === rows.length ? `all ${rows.length} accelerators` : g.labels.join(", ")
58340
+ }),
58341
+ /* @__PURE__ */ jsx("span", {
58342
+ className: "rounded border border-border px-1.5 py-px text-[10px] font-medium text-foreground-subtle",
58343
+ children: g.sourceLabel
58344
+ })
58345
+ ]
58346
+ }, `${g.modelId}|${g.sourceLabel}`))
58347
+ }), /* @__PURE__ */ jsx("div", {
58348
+ className: "mt-1.5 flex justify-end",
58349
+ children: /* @__PURE__ */ jsx("button", {
58350
+ type: "button",
58351
+ className: cn(BTN_COMPACT, "min-h-9 md:min-h-0"),
58352
+ "aria-expanded": false,
58353
+ onClick: () => setOpen(true),
58354
+ children: "Per accelerator"
58355
+ })
58356
+ })]
58357
+ });
58358
+ }
58359
+ return /* @__PURE__ */ jsx("div", {
58360
+ className: "space-y-2",
58361
+ children: rows.map(({ id, ...row }) => /* @__PURE__ */ jsx(StepModelRow, { ...row }, id))
58362
+ });
58363
+ }
58364
+ //#endregion
58365
+ //#region src/composites/step-tree.ts
58068
58366
  /**
58069
58367
  * Helper: build a StepTreeNode[] from a `PipelineSchema` by chaining on
58070
58368
  * `inputClasses` ⇔ `outputClasses` compatibility. Mirrors the orchestrator
@@ -61009,4 +61307,4 @@ var SceneMonitorEditor = lazy(() => import("./SceneMonitorEditor-vfWTm6qv.js").t
61009
61307
  /** Lazy-wrapped `PrivacyMaskSettings` — code-split off the main bundle. */
61010
61308
  var PrivacyMaskSettings = lazy(() => import("./PrivacyMaskSettings-DMkchqO1.js").then((m) => ({ default: m.PrivacyMaskSettings })));
61011
61309
  //#endregion
61012
- export { AddonGlobalSettingsForm, AdminLinkQuickAction, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, AppShell, ArcKnob, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, Badge, BatteryBadge, BottomSheet, Breadcrumb, BrightnessPanel, Button, ButtonControl, ButtonHeroCard, CARD_MODE_MIN_COLUMNS, CENTER, CHIP_ACTIVE, CHIP_BASE, CHIP_INACTIVE, CLASS_COLORS, COLUMN_BREAKPOINT_CLASS, COLUMN_PRIORITY, COMMIT_DEDUPE_TOLERANCE_MS, COMMIT_DEDUPE_WINDOW_MS, CONTROL_CAP_NAMES, CONTROL_FILLS, CameraStreamPlayer, Card, Checkbox, ChildSectionAccordion, ClimatePanel, CodeBlock, CollapsibleCard, ConfigFormBuilder, FormField as ConfigFormField, ConfigNotificationTargetMultiSelectFieldView, ConfigNotificationTargetSelectFieldView, ConfigSchemaField, ConfirmActionButton, ConfirmDialogProvider, ConsumablesPanel, ContainerChildrenProvider, ContainerPrimaryHero, ControlColumn, ControlHeroCard, ControlInlineControl, ControlPanel, CopyButton, CoverHeroCard, CoverInlineControl, CoverPanel, CustomFieldRenderersProvider, DEFAULT_COLOR, DEVICE_COLUMNS, DEVICE_LIST_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_OPTIONS, DEVICE_PICKER_GROUP_STORAGE_KEY, DEVICE_ROLE_META, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DISPLAY_ICON_REGISTRY, DataTable, DataTableFilterBar, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceFilterBar, DeviceGrid, DeviceItem, DeviceList, DeviceMultiSelectField, DevicePicker, DeviceQuickDetailProvider, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, DevicesFailedLine, DevicesLoadingLine, DevicesWidenWarning, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DiscoveryPanel, DoorbellRecentPanel, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, DummyHeroCard, DummyInline, EMPTY_DATA_TABLE_FILTER, EVENT_KIND_ICONS, EmptyState, EndpointResultsCard, EndpointTestCard, ErrorBox, EventKindGlyph, EventStream, ExtensionsPanel, FILL, FLEET_LIST_GC_TIME_MS, FLEET_LIST_QUERY_KEY, FLEET_LIST_STALE_TIME_MS, FanHeroCard, FanInlineControl, FanPanel, FilterBar, FloatingEventStream, FloatingLogStream, FloatingPanel, FormField$1 as FormField, GRID_GAP, GRID_PAIRED, GRID_QUICK_STATS, GripTrack, GroupedModelSelector, HOST_WIDGETS, HUB_SESSION_RUN_MS, HlsVideo, HoverZoomImage, HubSessionTestCard, HumidifierHeroCard, HumidifierInlineControl, INPUT_COMPACT, INPUT_SHELL, IconAction, IconButton, IconPicker, ImageHeroCard, ImageInlineControl, ImageSelector, InferenceConfigSelector, Input, KebabMenu, KeyValueList, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LightHeroCard, LightInlineControl, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, MODE_COLOR, MaskShapeCanvas, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, MobileDrawer, ModelPicker, MotionZonesSettings, NAVIGATION_DRIVE_INTERVAL_MS, NatResultCard, NavigationPanel, NetworkLinkBadge, NodeMultiSelectField, NodePicker, NodeSelectField, NotificationTargetSelectField, NotificationTargetsField, OPTION_SELECT_SEARCH_MIN_OPTIONS, OfflineBadge, OptionSelect, PHASE_CONFIG, PICKER_CHIP_LIMIT, PICKER_DEFAULT_GROUP_BY, PICKER_GROUP_BY_MODES, PICKER_GROUP_COLLAPSE_AT, PICKER_NONE_KEY, PICKER_NOUN_PLURAL, PICKER_NO_FILTERS, PICKER_PAGE_SIZE, PICKER_SEARCH_DEBOUNCE_MS, PICKER_WINDOW, PRIORITY, PTZOverlay, PageHeader, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PipelineTreeMatrix, PlaceholderChipField, PlayerOverlaysProvider, Popover, PopoverContent, PopoverRowAction, PopoverTrigger, PrimaryChildPicker, PrivacyMaskSettings, ProviderBadge, PtzPanel, QrCode, RECONNECT_POLICY, RECORDED_PLAYBACK_MODES, RIGHT, ROI_AREA_WARN_FRACTION, ROLE_DESCRIPTOR, RadialGauge, RecordedPlaybackProvider, RecordingPanel, ResponseLog, RoleDisplayDefaultsFromServer, RoleDisplayDefaultsProvider, RunReport, SCENE_CAPTURE_VARIANTS, SECTION_BODY, SECTION_CARD, SECTION_HEADER, SETTING_ROW, SETTING_ROW_LABEL, SETTING_ROW_STACK_BREAKPOINT, SETTING_ROW_VALUE, SETTING_ROW_VALUE_TEXT, SNAPSHOT_MEDIA_PATH, SPLIT_PANEL_OUTER, SPLIT_PANEL_SIDE, STACK_GAP, STATE_COLOR, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, SectionCard, Select, SelectedChip, SemanticBadge, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideOverPanel, SlideToggle, SnapshotButton, SortHeaderButton, StatCard, StateValuesStream, StatusBadge, StepTimings, StepTreeMaster, Stepper, StreamBrokerSelector, StreamDebugOverlay, StreamPanel, Switch, SwitchHeroCard, SwitchInlineControl, SwitchPanel, SystemProvider, TABLE_SCROLL_MAX_H, TEXT_FIELD_LABEL, TEXT_HINT, TEXT_METRIC, TEXT_SECTION_LABEL, TEXT_VALUE, TIMEZONES, Tabs, TabsContent, TabsList, TabsTrigger, TapToggle, ThemeProvider, ThermostatHeroCard, ThermostatInlineControl, TimezoneSelector, Tooltip, TooltipContent, TooltipTrigger, UnitPicker, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, VodPlaybackProvider, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, ZoneEditingProvider, MicOff as a, agentColumnKey, allDeviceTypeFilterOptions, applyFleetQueryDefaults, applyPickerFilters, ariaSortForColumn, badgeFor, buildPeerConnectionConfig, buildStepTreeFromSchema, EyeOff as c, catalogHasDraft, childEntityId, childListName, chipOverflow, classifyAddressScope, classifyCapability, classifySessionVerdict, clearPickerGroup, cn, columnsForContext, compareSrflxMappings, containerChildToRef, countableDevices, coverHighlight, coverageLine, createSharedContext, createTheme, cursorFractionFor, darkColors, dataTableFacets, defaultTheme, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, deviceIntegrationResolver, deviceListStateOf, deviceMatchesFilter, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, draftFromQuery, emptyDevicesWidens, emptySessionRun, ensureMfHostInit, eventKindLabel, filterDataTableRows, filterDeviceOptions, filterOptions as filterOptionSelectOptions, filterPickerDevices, finalizeSessionRun, findTimezone, flattenPickerGrouping, flattenPickerRows, fleetViewOf, formatControlDateTime, formatLastSeen, formatNumeric, freezeVerdict, fuzzyMatch, getClassColor, getPhaseVisual, groupAgentColumns, groupChildrenByLayout, groupPickerDevices, groupPickerDevicesBy, hardwareLabel, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humidifierTint, Mic as i, initialScrubState, insertAtSelection, isAbsentProvider, isDataTableFilterActive, isFieldVisible, isGroupExpanded, Camera as l, lawnMowerActivityMeta, lightColors, loadRemoteBundle, makeScrubBridge, metadataEntries, metadataString, mirror, mountAddonPage, mountPath, Square as n, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, normalizeForSearch, ImageOff as o, offListSelections, openTopLayer, optionSearchText as optionSelectSearchText, orphanDeviceLabel, overrideEntityIdFromLink, pageRows, parentDetailOf, parseIceCandidate, parsePickerGroupBy, parseRecordedServerMessage, partitionSelected as partitionOptionSelectSelected, partitionSuggested, pickerFacetFilterShown, pickerFacetKey, pickerFacetOptions, pickerFiltersActive, pickerGroupKey, pickerHiddenSelectedCount, pickerLocationKey, pickerQueryTokens, pickerRowFacts, pickerSearchText, pickerZoneFilterSuspended, pinnedStreamChoices, providerIcons, RotateCcw as r, readStoredGroupBy, reduceSessionRun, resetHubMountForTests, resetPickerFilters, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDeviceIntegration, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolveSearchable as resolveOptionSelectSearchable, resolveParentNames, resolvePrimaryChild, resolveSelectedDevices, resolveSensorDisplay, resolveStepDefaultModel, resolveTableLayout, roiTooLarge, rootSourceState, routerBasename, Grid2x2 as s, sameLocationSuggestions, scrubReducer, selectPickerGroup, selectedDeviceOptions, serializeRecordedCommand, shouldCommit, shouldEmit, shouldShowAddNewFooter, shouldShowUseQueryRow, shouldUseSingleNode, showsNoCamerasHint, sortRows, sortRowsByColumn, statusIcons, statusLine, stepHasModelForFormat, stepModelOptions, stripParentNamePrefix, summarizeHubCandidates, Trash2 as t, tabForSelector, tankAlert, themeToCss, toStationaryOverlayBox, toggleDataTableFacet, togglePickerDevice, togglePickerKey, trpc, typeLabel, createLucideIcon as u, useAccessoriesGetStatus, useAccessoriesSetChildHidden, useAddonPagesListPages, useAddonSettingsGetDeviceSettings, useAddonSettingsGetGlobalSettings, useAddonSettingsGetIntegrationSettings, useAddonSettingsUpdateDeviceSettings, useAddonSettingsUpdateGlobalSettings, useAddonWidgetsListWidgets, useAddonsApplyAutoUpdateToAll, useAddonsCancelJob, useAddonsCustom, useAddonsForceRefresh, useAddonsGetAddonAutoUpdate, useAddonsGetAutoUpdateSettings, useAddonsGetJob, useAddonsGetLastRestart, useAddonsGetLogs, useAddonsGetVersions, useAddonsInstallFromWorkspace, useAddonsInstallPackage, useAddonsIsWorkspaceAvailable, useAddonsList, useAddonsListCapabilityProviders, useAddonsListFrameworkPackages, useAddonsListJobs, useAddonsListPackages, useAddonsListUpdates, useAddonsListWorkspacePackages, useAddonsOnAddonLogs, useAddonsReloadPackages, useAddonsRestartAddon, useAddonsRestartServer, useAddonsRetryLoad, useAddonsRollbackPackage, useAddonsSearchAvailable, useAddonsSetAddonAutoUpdate, useAddonsSetAutoUpdateSettings, useAddonsSetCapabilityProviderEnabled, useAddonsStartJob, useAddonsUninstallPackage, useAddonsUpdatePackage, useAirQualitySensorGetStatus, useAlarmPanelArm, useAlarmPanelDisarm, useAlarmPanelGetStatus, useAlarmPanelTrigger, useAlert, useAlertsDismiss, useAlertsEmit, useAlertsGetUnreadCount, useAlertsList, useAlertsMarkAllRead, useAlertsMarkRead, useAlertsUpdate, useAllWidgets, useAmbientLightSensorGetStatus, useAudioAnalysisApplyDeviceSettingsPatch, useAudioAnalysisGetDeviceLiveContribution, useAudioAnalysisGetDeviceSettingsContribution, useAudioAnalysisResolveDeviceSettings, useAudioAnalyzerAnalyseChunk, useAudioAnalyzerAttachDevice, useAudioAnalyzerClassify, useAudioAnalyzerDetachDevice, useAudioAnalyzerDispose, useAudioAnalyzerIsReady, useAudioAnalyzerReprobeAudioEngine, useAudioCodecCanHandle, useAudioCodecCloseSession, useAudioCodecCreateDecodeSession, useAudioCodecCreateEncodeSession, useAudioCodecFlushEncode, useAudioCodecListActiveSessions, useAudioCodecListSupportedCodecs, useAudioCodecPullEncoded, useAudioCodecPullPcm, useAudioCodecPushEncodedFrame, useAudioCodecPushPcm, useAudioMetricsGetCurrentSnapshot, useAudioMetricsGetHistory, useAutomationControlDisable, useAutomationControlEnable, useAutomationControlGetStatus, useAutomationControlTrigger, useBackupCancel, useBackupDelete, useBackupDeleteSchedule, useBackupGetEntries, useBackupList, useBackupListArchives, useBackupListDestinations, useBackupListLocations, useBackupListRuns, useBackupListSchedules, useBackupPreviewSchedule, useBackupRestore, useBackupTrigger, useBackupUpsertDestinationPolicy, useBackupUpsertSchedule, useBatteryGetStatus, useBatteryWakeForStream, useBinaryGetStatus, useBrightnessGetStatus, useBrightnessSetBrightness, useBrokerAdd, useBrokerGet, useBrokerGetBrokerConfig, useBrokerGetSettings, useBrokerGetSettingsSchema, useBrokerGetState, useBrokerGetStatus, useBrokerList, useBrokerListProviders, useBrokerPublish, useBrokerRemove, useBrokerSetSettings, useBrokerSubscribe, useBrokerTestConnection, useBrokerTestSettings, useBrokerUnsubscribe, useButtonPress, useCalendarsGetPreferences, useCalendarsListCalendars, useCalendarsListEvents, useCalendarsSetCalendarPreference, useCameraCredentialsGetCredentials, useCameraCredentialsGetStatus, useCameraGridLayoutApplyDeviceSettingsPatch, useCameraGridLayoutGetDeviceLiveContribution, useCameraGridLayoutGetDeviceSettingsContribution, useCameraGridLayoutGetLayout, useCameraGridLayoutSaveLayout, useCameraPipelineConfigApplyDeviceSettingsPatch, useCameraPipelineConfigGetDeviceLiveContribution, useCameraPipelineConfigGetDeviceSettingsContribution, useCameraStreamsGetBrokerStreams, useCameraStreamsGetCameraStreams, useCameraStreamsGetProfileRtspEntries, useCameraStreamsGetRtspEntries, useCameraStreamsPickStream, useCapabilityPresence, useCarbonMonoxideGetStatus, useClimateControlGetStatus, useClimateControlSetFanMode, useClimateControlSetMode, useClimateControlSetPreset, useClimateControlSetSwingHorizontal, useClimateControlSetSwingVertical, useClimateControlSetTarget, useClimateControlSetTargetHumidity, useClimateControlSetTargetRange, useClusterNodes, useClusterTopology, useColorGetStatus, useColorSetColor, useConfirm, useConnectionTestDescribeTest, useConnectionTestTestSettings, useConnectivityGetStatus, useConsumablesGetStatus, useConsumablesReset, useContactGetStatus, useContainerChildren, useControlGetStatus, useControlSetValue, useCoreBlocksCompile, useCoreBlocksCreate, useCoreBlocksCreateComposition, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetBlockSettings, useCoreBlocksGetComposition, useCoreBlocksGetCustomization, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksListComposableCaps, useCoreBlocksListCompositions, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoreBlocksUpdateBlockSettings, useCoreBlocksUpdateComposition, useCoreBlocksValidateComposition, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDataTableFilter, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderCreateSession, useDecoderDestroySession, useDecoderGetFrame, useDecoderGetInfo, useDecoderGetShmStats, useDecoderGetStats, useDecoderListActiveSessions, useDecoderOpenStream, useDecoderPullFrames, useDecoderPullHandles, useDecoderPushPacket, useDecoderReprobeHwaccel, useDecoderSupportsCodec, useDecoderUpdateConfig, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdminLink, useDeviceAdminLinkGetAdminLink, useDeviceAdoptionAdopt, useDeviceAdoptionGetCandidate, useDeviceAdoptionGetStatus, useDeviceAdoptionListCandidateFilters, useDeviceAdoptionListCandidates, useDeviceAdoptionRefresh, useDeviceAdoptionRelease, useDeviceAdoptionResync, useDeviceAutotrack, useDeviceBattery, useDeviceCapSlice, useDeviceCapability, useDeviceDetections, useDeviceDiscoveryAdoptDevice, useDeviceDiscoveryGetStatus, useDeviceDiscoveryListDiscovered, useDeviceDiscoveryRefreshDiscovery, useDeviceDiscoveryReleaseDevice, useDeviceExportApplyDeviceSettingsPatch, useDeviceExportExposeDevice, useDeviceExportGetDeviceLiveContribution, useDeviceExportGetDeviceSettingsContribution, useDeviceExportGetStatus, useDeviceExportListExposedDevices, useDeviceExportListSupportedDeviceKinds, useDeviceExportUnexposeDevice, useDeviceExtensionListCandidates, useDeviceExtensionListSlots, useDeviceExtensionListSources, useDeviceExtensionSetSlot, useDeviceId, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyInitialMeta, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerGetWrapperActivation, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListDeviceIdsByCaps, useDeviceManagerListLocationDescriptions, useDeviceManagerListLocationIcons, useDeviceManagerListLocations, useDeviceManagerListPersistedByAddon, useDeviceManagerListSiteZones, useDeviceManagerListWrappersForCap, useDeviceManagerLoadConfig, useDeviceManagerLoadMeta, useDeviceManagerLoadRuntimeState, useDeviceManagerMigrateDevice, useDeviceManagerPersistConfig, useDeviceManagerProbeStreams, useDeviceManagerProviderCreationType, useDeviceManagerProviderDiscoveryParamsSchema, useDeviceManagerRegisterDevice, useDeviceManagerRemove, useDeviceManagerRemoveByIntegration, useDeviceManagerRemoveDevice, useDeviceManagerRemoveLocation, useDeviceManagerRemoveSiteZone, useDeviceManagerRenameLocation, useDeviceManagerRenameSiteZone, useDeviceManagerRunDeviceAction, useDeviceManagerSetChildLayout, useDeviceManagerSetDisabled, useDeviceManagerSetDisplay, useDeviceManagerSetIntegrationId, useDeviceManagerSetLinkDeviceId, useDeviceManagerSetLocation, useDeviceManagerSetLocationDescription, useDeviceManagerSetLocationIcon, useDeviceManagerSetLocationZone, useDeviceManagerSetMetadata, useDeviceManagerSetName, useDeviceManagerSetPrimaryChildEntityId, useDeviceManagerSetRole, useDeviceManagerSetRoleDisplayDefaults, useDeviceManagerSetSiteZone, useDeviceManagerSetStreamProfileMap, useDeviceManagerSetType, useDeviceManagerSetWrapperActive, useDeviceManagerTestCreationField, useDeviceManagerTestField, useDeviceManagerUpdateConfig, useDeviceManagerUpdateDeviceField, useDeviceManagerUpdateDeviceFieldsBatch, useDeviceNetworkLink, useDeviceOpsGetConfigEntries, useDeviceOpsGetRawState, useDeviceOpsGetSettingsSchema, useDeviceOpsGetStreamSources, useDeviceOpsRemoveDevice, useDeviceOpsRunAction, useDeviceOpsSetConfig, useDeviceProviderAdoptDiscoveredDevice, useDeviceProviderCreateDevice, useDeviceProviderDiscoverDevices, useDeviceProviderGetChildCreationSchema, useDeviceProviderGetDevices, useDeviceProviderGetDiscoveryParamsSchema, useDeviceProviderGetManualCreationType, useDeviceProviderGetStatus, useDeviceProviderReloadDevice, useDeviceProviderStart, useDeviceProviderStop, useDeviceProviderSupportsDiscovery, useDeviceProviderSupportsManualCreation, useDeviceProviderTestCreationField, useDeviceProxy, useDeviceQuickDetailOpen, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateClaimFields, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetNativeCapSlice, useDeviceStateGetSnapshot, useDeviceStateListClaims, useDeviceStatePatchOwnedFields, useDeviceStateReleaseClaim, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDoorbellEvents, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, useFaceGalleryAssignFace, useFaceGalleryAssignFaces, useFaceGalleryAuditIdentitySamples, useFaceGalleryCreateIdentity, useFaceGalleryDeleteFace, useFaceGalleryDeleteIdentity, useFaceGalleryGetFaceByTrack, useFaceGalleryGetFaceMedia, useFaceGalleryListIdentities, useFaceGalleryListIdentitySamples, useFaceGalleryListRecentFaces, useFaceGalleryRemoveSample, useFaceGalleryRenameIdentity, useFaceGallerySuggestFaceClusters, useFaceGalleryUnassignFace, useFaceGalleryUnassignFaces, useFanControlGetStatus, useFanControlSetDirection, useFanControlSetOscillating, useFanControlSetPercentage, useFanControlSetPreset, useFeatureProbeGetStatus, useFloodGetStatus, useGasGetStatus, useHumidifierGetStatus, useHumidifierSetMode, useHumidifierSetOn, useHumidifierSetTargetHumidity, useHumiditySensorGetStatus, useImageGetStatus, useImageSettingsGetOptions, useImageSettingsGetStatus, useImageSettingsSetSettings, useIntegrationsCreate, useIntegrationsDelete, useIntegrationsGet, useIntegrationsGetAvailableTypes, useIntegrationsGetByAddonId, useIntegrationsGetSettings, useIntegrationsList, useIntegrationsSetSettings, useIntegrationsTestConnection, useIntegrationsUpdate, useIntercomEndTalkSession, useIntercomGetStatus, useIntercomHandleAnswer, useIntercomPushTalkAudio, useIntercomStartSession, useIntercomStartTalkSession, useIntercomStopSession, useIsMidWidth, useIsMobile, useLawnMowerControlDock, useLawnMowerControlGetStatus, useLawnMowerControlPause, useLawnMowerControlStartMowing, useLiveBuffer, useLiveEvent, useLlmCancel, useLlmDeleteModel, useLlmDeleteProfile, useLlmGenerate, useLlmGenerateVision, useLlmGetDefaults, useLlmGetRuntimeStatus, useLlmGetUsage, useLlmInstallModel, useLlmListModelCatalog, useLlmListModels, useLlmListNodeModels, useLlmListProfileKinds, useLlmListProfiles, useLlmListRuntimeNodes, useLlmResolveModelRef, useLlmSetDefault, useLlmStartRuntime, useLlmStopRuntime, useLlmTestProfile, useLlmUpsertProfile, useLocalNetworkAddCustomAddress, useLocalNetworkDownloadCa, useLocalNetworkGetAddresses, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetHubAddresses, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkRemoveCustomAddress, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkSetAddressRole, useLocalNetworkSetAllowedAddresses, useLocalNetworkSetNotificationEndpoint, useLocalNetworkSetViewerEndpoints, useLocalNetworkUploadCertificate, useLockControlGetStatus, useLockControlLock, useLockControlOpen, useLockControlUnlock, useMediaPlayerGetStatus, useMediaPlayerNext, useMediaPlayerPause, useMediaPlayerPlay, useMediaPlayerPlayMedia, useMediaPlayerPrevious, useMediaPlayerSeek, useMediaPlayerSelectSource, useMediaPlayerSetMute, useMediaPlayerSetRepeat, useMediaPlayerSetShuffle, useMediaPlayerSetVolume, useMediaPlayerStop, useMeshNetworkGetStatus, useMeshNetworkJoin, useMeshNetworkLeave, useMeshNetworkListPeers, useMeshNetworkLogout, useMeshNetworkStartLogin, useMeshNetworkTestConnection, useMetricsProviderCollectSnapshot, useMetricsProviderGetAddonStats, useMetricsProviderGetCached, useMetricsProviderGetCpuTemperature, useMetricsProviderGetCurrent, useMetricsProviderGetDiskSpace, useMetricsProviderGetGpuInfo, useMetricsProviderGetLoadSeries, useMetricsProviderGetProcessStats, useMetricsProviderListAddonInstances, useMetricsProviderListNodeProcesses, useMotionDetectionAnalyze, useMotionDetectionApplyDeviceSettingsPatch, useMotionDetectionGetDeviceLiveContribution, useMotionDetectionGetDeviceSettingsContribution, useMotionDetectionRemoveCamera, useMotionDetectionReset, useMotionGetStatus, useMotionIsDetected, useMotionTriggerGetStatus, useMotionTriggerSetMotionTrigger, useMotionZonesGetOptions, useMotionZonesGetStatus, useMotionZonesSetZone, useMqttBrokerAddBroker, useMqttBrokerGetBrokerConfig, useMqttBrokerGetStatus, useMqttBrokerListBrokers, useMqttBrokerRemoveBroker, useMqttBrokerStartEmbeddedBroker, useMqttBrokerStopEmbeddedBroker, useMqttBrokerTestConnection, useNativeObjectDetectionGetOptions, useNativeObjectDetectionGetStatus, useNativeObjectDetectionSetEnabled, useNativeObjectDetectionSetSettings, useNavigation, useNavigationGetFeatures, useNavigationGetStatus, useNavigationGoToPoint, useNavigationListActions, useNavigationMove, useNavigationPlaySound, useNavigationRunAction, useNavigationSetLightLevel, useNavigationSetLightMode, useNavigationSetLightOn, useNavigationStop, useNetworkAccessGetEndpoint, useNetworkAccessGetStatus, useNetworkAccessListEndpoints, useNetworkAccessStart, useNetworkAccessStop, useNetworkLinkGetStatus, useNetworkQualityGetAllStats, useNetworkQualityGetDeviceStats, useNetworkQualityReportClientStats, useNodesClusterAddonStatus, useNodesDeployAddon, useNodesDirectory, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputGetTarget, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputProbeTargetConfig, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesActivateAlarmProfile, useNotificationRulesCancelSnooze, useNotificationRulesCreateAlarmProfile, useNotificationRulesCreateRule, useNotificationRulesCreateSequence, useNotificationRulesCreateSnooze, useNotificationRulesDeleteAlarmProfile, useNotificationRulesDeleteRule, useNotificationRulesDeleteSequence, useNotificationRulesGetAlarmConfig, useNotificationRulesGetAlarmSensors, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesGetRuleLastRuns, useNotificationRulesGetSequence, useNotificationRulesGetTemplateCatalog, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSequences, useNotificationRulesListSnoozes, useNotificationRulesPreviewStateSummary, useNotificationRulesPreviewTemplate, useNotificationRulesRenameAlarmProfile, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotificationRulesUpdateSequence, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerDeleteTemplate, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerListTemplates, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdManagerUpsertTemplate, useOsdSetOverlay, usePTZ, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePickerSiteZones, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTrackRelation, usePipelineAnalyticsClearTracks, usePipelineAnalyticsCompleteRetrainTrack, usePipelineAnalyticsCountRelocatableMedia, usePipelineAnalyticsCountUnstampedEventMedia, usePipelineAnalyticsDeleteDeviceEvents, usePipelineAnalyticsDeleteTracks, usePipelineAnalyticsDeselectRetrainFrame, usePipelineAnalyticsGetActiveTracks, usePipelineAnalyticsGetAudioEvents, usePipelineAnalyticsGetDeviceLiveContribution, usePipelineAnalyticsGetDeviceSettingsContribution, usePipelineAnalyticsGetEventDensity, usePipelineAnalyticsGetEventDensityBatch, usePipelineAnalyticsGetEventMedia, usePipelineAnalyticsGetEventMediaFootprintByKind, usePipelineAnalyticsGetEventStoreFootprint, usePipelineAnalyticsGetKeyEvents, usePipelineAnalyticsGetKeyEventsBatch, usePipelineAnalyticsGetMediaReclaimStatus, usePipelineAnalyticsGetMotionEvents, usePipelineAnalyticsGetObjectEmbeddingRebuildStatus, usePipelineAnalyticsGetObjectEvents, usePipelineAnalyticsGetRetrainExportUrl, usePipelineAnalyticsGetRetrainFrameImage, usePipelineAnalyticsGetSensorEvents, usePipelineAnalyticsGetStorageMigrationMoveStatus, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTrackRelations, usePipelineAnalyticsListTracks, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsSetTrackPurity, usePipelineAnalyticsSetTrackRelation, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineExecutorCacheFrameInPool, usePipelineExecutorClearDeviceOverrides, usePipelineExecutorClearModelBoundDeviceOverrides, usePipelineExecutorDeleteModel, usePipelineExecutorDeleteTemplate, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDefaultSteps, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetGlobalPipelineConfig, usePipelineExecutorGetGlobalSteps, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorListTemplates, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSaveTemplate, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorUpdateTemplate, usePipelineExecutorValidatePipeline, usePipelineOrchestratorApplyAutoTune, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorDeleteTemplate, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraStepOverrides, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetClusterModelChoice, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetEffectiveShares, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetPlacementStats, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorListTemplates, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorPlanAutoTune, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorRequestOccupancyLook, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSaveTemplate, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraPipelineForAgent, usePipelineOrchestratorSetCameraSensors, usePipelineOrchestratorSetCameraStepOverride, usePipelineOrchestratorSetCameraStepSettings, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetLoadBalancingShares, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorSetShareSource, usePipelineOrchestratorSuggestShares, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, usePipelineOrchestratorUpdateTemplate, usePipelineRunnerAttachCamera, usePipelineRunnerDetachCamera, usePipelineRunnerGetAllCameraMetrics, usePipelineRunnerGetCameraMetrics, usePipelineRunnerGetLocalCameras, usePipelineRunnerGetLocalLoad, usePipelineRunnerGetLocalMetrics, usePipelineRunnerGetNativeCrop, usePipelineRunnerGetParkedTrackFrame, usePipelineRunnerParkTrackFrame, usePipelineRunnerReleaseParkedTrackFrames, usePipelineRunnerReportMotion, usePipelineRunnerRequestOccupancyBurst, usePipelineRunnerRunDetailSubtree, usePipelineRunnerRunStatelessStep, usePlateGalleryAssignPlate, usePlateGalleryAssignPlates, usePlateGalleryCorrectPlateText, usePlateGalleryCreateVehicle, usePlateGalleryDeletePlate, usePlateGalleryDeleteVehicle, usePlateGalleryGetPlateByTrack, usePlateGalleryGetPlateMedia, usePlateGalleryListPlates, usePlateGalleryListVehicleSamples, usePlateGalleryListVehicles, usePlateGalleryRemoveVehicleSample, usePlateGalleryRenameVehicle, usePlateGallerySearchPlates, usePlateGallerySuggestPlateClusters, usePlateGalleryUnassignPlate, usePlateGalleryUnassignPlates, usePlayerOverlayLayer, usePlayerOverlayLayers, usePlayerToolbarButton, usePlayerToolbarButtons, usePowerMeterGetStatus, usePresenceGetStatus, usePressureSensorGetStatus, usePrivacyMaskGetOptions, usePrivacyMaskGetStatus, usePrivacyMaskSetAudioEnabled, usePrivacyMaskSetMask, usePrompt, usePtzAutotrackGetSettings, usePtzAutotrackGetStatus, usePtzAutotrackSetEnabled, usePtzAutotrackSetSettings, usePtzCaptureHomeHere, usePtzContinuousMove, usePtzDeletePreset, usePtzGetHomePreset, usePtzGetHomeReturn, usePtzGetOptions, usePtzGetPosition, usePtzGetPresets, usePtzGetStatus, usePtzGoHome, usePtzGoToPreset, usePtzMove, usePtzSavePreset, usePtzSetAutofocus, usePtzSetHomePreset, usePtzSetHomeReturn, usePtzStop, useRebootReboot, useRecordedPlayback, useRecordingArchiveApplyDeviceSettingsPatch, useRecordingArchiveCancelRelocateJob, useRecordingArchiveCancelStorageMigrationMove, useRecordingArchiveDeleteFootprint, useRecordingArchiveGetAvailabilityBatch, useRecordingArchiveGetDaysWithRecordingsBatch, useRecordingArchiveGetDeviceConfig, useRecordingArchiveGetDeviceLiveContribution, useRecordingArchiveGetDeviceSettingsContribution, useRecordingArchiveGetPlacement, useRecordingArchiveGetRelocateResidue, useRecordingArchiveGetStatus, useRecordingArchiveGetStorageMigrationMoveStatus, useRecordingArchiveGetStorageUsage, useRecordingArchiveListOpsLog, useRecordingArchiveListRelocateJobs, useRecordingArchiveLocateSegment, useRecordingArchivePauseForStorageMigration, useRecordingArchivePlanStorageRebalance, useRecordingArchivePruneFootage, useRecordingArchiveReadGopBytes, useRecordingArchiveReadSegmentBytes, useRecordingArchiveReadWindowBytes, useRecordingArchiveReconcileLedgerAgainstDisk, useRecordingArchiveRefreshStorageLocationsForMigration, useRecordingArchiveRelocateFootage, useRecordingArchiveRenderClip, useRecordingArchiveRenderGif, useRecordingArchiveRescanStorage, useRecordingArchiveResumeForStorageMigration, useRecordingArchiveSetDeviceConfig, useRecordingArchiveSetDevicePlacement, useRecordingArchiveStartStorageMigrationMove, useRecordingArchiveStartStorageRebalance, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetDaysWithRecordings, useRecordingGetPlayback, useRecordingGetPlaybackOptions, useRecordingListSources, useRecordingOnboardGetOptions, useRecordingOnboardGetStatus, useRecordingOnboardSetSettings, useRecordingSignalGetStatus, useRemoteComponent, useRoleDisplayDefaults, useSceneMonitorCaptureReference, useSceneMonitorCreateScene, useSceneMonitorDeleteReference, useSceneMonitorDeleteScene, useSceneMonitorGetStatus, useSceneMonitorListScenes, useSceneMonitorListScenesBatch, useSceneMonitorRecheckNow, useSceneMonitorResetScene, useSceneMonitorUpdateScene, useScriptRunnerGetStatus, useScriptRunnerRun, useScriptRunnerStop, useScrubController, useServerManagementApplyServerUpdate, useServerManagementCheckServerUpdate, useServerManagementGetServerPackageStatus, useServerManagementRestartServer, useServerManagementRollbackServerUpdate, useSettingsStoreAggregate, useSettingsStoreCount, useSettingsStoreDeclareCollection, useSettingsStoreDelete, useSettingsStoreDeleteWhere, useSettingsStoreGet, useSettingsStoreHistogram, useSettingsStoreInsert, useSettingsStoreInsertMany, useSettingsStoreIsEmpty, useSettingsStoreQuery, useSettingsStoreSet, useSettingsStoreUpdate, useSettingsStoreUpdateWhere, useSettingsStoreUpsert, useSmokeGetStatus, useSnapshotApplyDeviceSettingsPatch, useSnapshotGetDebugState, useSnapshotGetDeviceLiveContribution, useSnapshotGetDeviceSettingsContribution, useSnapshotGetSnapshot, useSnapshotGetSnapshotLinks, useSnapshotGetSnapshotOverview, useSnapshotGetStatus, useSnapshotInvalidateCache, useStationaryOverlay, useStorageAbortUpload, useStorageBeginDownload, useStorageBeginUpload, useStorageDelete, useStorageDeleteLocation, useStorageEndDownload, useStorageExists, useStorageFinalizeUpload, useStorageGetAvailableSpace, useStorageList, useStorageListDrainProgress, useStorageListLocationDeclarations, useStorageListLocations, useStorageListProviders, useStorageMigrationCancel, useStorageMigrationCleanupCancel, useStorageMigrationCleanupStart, useStorageMigrationCleanupStatus, useStorageMigrationDrain, useStorageMigrationHistory, useStorageMigrationMovers, useStorageMigrationPlan, useStorageMigrationResidue, useStorageMigrationStart, useStorageMigrationStatus, useStorageRead, useStorageReadChunk, useStorageResolve, useStorageTestConfig, useStorageTestLocation, useStorageUpsertLocation, useStorageWrite, useStorageWriteChunk, useStoredGroupBy, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerPullFrameHandles, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerSubscribeFrames, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, useStreamBrokerUnsubscribeFrames, useStreamCatalogGetCatalog, useStreamParamsGetConfigSchema, useStreamParamsGetOptions, useStreamParamsGetStatus, useStreamParamsSetProfile, useStreamSignalsListSignals, useSwitchGetStatus, useSwitchSetState, useSystem, useSystemDetectSiteLocation, useSystemFeatureFlags, useSystemForceRetentionCleanup, useSystemGetFailureContributions, useSystemGetLoadContributions, useSystemGetLoggingSettings, useSystemGetRequestCensus, useSystemGetRetentionConfig, useSystemGetSiteLocation, useSystemHealth, useSystemInfo, useSystemMutation, useSystemNetworkAddresses, useSystemQuery, useSystemSetLoggingSettings, useSystemSetRetentionConfig, useSystemSetSiteLocation, useTamperGetStatus, useTemperatureSensorGetStatus, useTerminalSessionAdoptLegacyMonitor, useTerminalSessionClose, useTerminalSessionCreateInstance, useTerminalSessionDeleteInstance, useTerminalSessionListInstances, useTerminalSessionListLegacyCameras, useTerminalSessionListProfiles, useTerminalSessionListSessions, useTerminalSessionOpenSession, useTerminalSessionPullOutput, useTerminalSessionResize, useTerminalSessionSetInstanceEnabled, useTerminalSessionUpdateInstance, useTerminalSessionWriteInput, useThemeMode, useToastOnToast, useTurnProviderGetTurnServers, useUpdateGetStatus, useUpdateInstallUpdate, useUrlQueryParam, useUserManagementConfirmTotp, useUserManagementCreateApiKey, useUserManagementCreateScopedToken, useUserManagementCreateUser, useUserManagementDeleteUser, useUserManagementDisableTotp, useUserManagementGetTotpStatus, useUserManagementListApiKeys, useUserManagementListOauthSessions, useUserManagementListScopedTokens, useUserManagementListUsers, useUserManagementOauthExchangeCode, useUserManagementOauthIssueCode, useUserManagementOauthRefresh, useUserManagementOauthVerifyAccessToken, useUserManagementResetPassword, useUserManagementRevokeApiKey, useUserManagementRevokeOauthSession, useUserManagementRevokeScopedToken, useUserManagementSetUserScopes, useUserManagementSetupTotp, useUserManagementUpdateUser, useUserManagementValidateApiKey, useUserManagementValidateCredentials, useUserManagementValidateScopedToken, useUserManagementVerifyTotp, useVacuumControlGetStatus, useVacuumControlLocate, useVacuumControlPause, useVacuumControlReturnToBase, useVacuumControlSetFanSpeed, useVacuumControlStart, useVacuumControlStop, useValveClose, useValveGetStatus, useValveOpen, useValveSetPosition, useValveStop, useVibrationGetStatus, useVideoclipsDialClipStream, useVideoclipsGetClipPlayback, useVideoclipsGetPlaybackOptions, useVideoclipsListClips, useVideoclipsListSources, useVideoclipsOfferClipBytes, useVideoclipsReadClipBytes, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionApplyDownlinkProbe, useWebrtcSessionCloseSession, useWebrtcSessionCreateSession, useWebrtcSessionGetIceCandidates, useWebrtcSessionGetSessionDebug, useWebrtcSessionGetSessionState, useWebrtcSessionHandleAnswer, useWebrtcSessionHandleOffer, useWebrtcSessionHasAdaptiveBitrate, useWebrtcSessionListStreams, useWidget, useWidgetMetadata, useWidgetRegistry, useZoneAnalyticsGetCameraHistory, useZoneAnalyticsGetCurrentSnapshot, useZoneAnalyticsGetCurrentSnapshotBatch, useZoneAnalyticsGetUnzonedHistory, useZoneAnalyticsGetZoneHistory, useZoneEditing, useZoneRulesListRules, useZoneRulesSetRules, useZonesAddZone, useZonesListZones, useZonesRemoveZone, useZonesUpdateZone, vacuumStateMeta, validateScopes, valveStateMeta, variantLabel, waterHeaterPhase, waterHeaterTint, weatherConditionMeta, weatherTint, withResolvedParentDetail, writeStoredGroupBy };
61310
+ export { AcceleratorTabs, AddonGlobalSettingsForm, AdminLinkQuickAction, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, AppShell, ArcKnob, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, BackToStepsButton, Badge, BatteryBadge, BottomSheet, Breadcrumb, BrightnessPanel, Button, ButtonControl, ButtonHeroCard, CARD_MODE_MIN_COLUMNS, CENTER, CHIP_ACTIVE, CHIP_BASE, CHIP_INACTIVE, CLASS_COLORS, COLUMN_BREAKPOINT_CLASS, COLUMN_PRIORITY, COMMIT_DEDUPE_TOLERANCE_MS, COMMIT_DEDUPE_WINDOW_MS, CONTROL_CAP_NAMES, CONTROL_FILLS, CameraStreamPlayer, Card, Checkbox, ChildSectionAccordion, ClimatePanel, CodeBlock, CollapsibleCard, ConfigFormBuilder, FormField as ConfigFormField, ConfigNotificationTargetMultiSelectFieldView, ConfigNotificationTargetSelectFieldView, ConfigSchemaField, ConfirmActionButton, ConfirmDialogProvider, ConsumablesPanel, ContainerChildrenProvider, ContainerPrimaryHero, ControlColumn, ControlHeroCard, ControlInlineControl, ControlPanel, CopyButton, CoverHeroCard, CoverInlineControl, CoverPanel, CustomFieldRenderersProvider, DEFAULT_COLOR, DEVICE_COLUMNS, DEVICE_LIST_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_OPTIONS, DEVICE_PICKER_GROUP_STORAGE_KEY, DEVICE_ROLE_META, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DISPLAY_ICON_REGISTRY, DataTable, DataTableFilterBar, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceFilterBar, DeviceGrid, DeviceItem, DeviceList, DeviceMultiSelectField, DevicePicker, DeviceQuickDetailProvider, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, DevicesFailedLine, DevicesLoadingLine, DevicesWidenWarning, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DiscoveryPanel, DoorbellRecentPanel, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, DummyHeroCard, DummyInline, EMPTY_DATA_TABLE_FILTER, EVENT_KIND_ICONS, EmptyState, EndpointResultsCard, EndpointTestCard, ErrorBox, EventKindGlyph, EventStream, ExtensionsPanel, FILL, FLEET_LIST_GC_TIME_MS, FLEET_LIST_QUERY_KEY, FLEET_LIST_STALE_TIME_MS, FanHeroCard, FanInlineControl, FanPanel, FilterBar, FloatingEventStream, FloatingLogStream, FloatingPanel, FormField$1 as FormField, GRID_GAP, GRID_PAIRED, GRID_QUICK_STATS, GateBadge, GateControl, GripTrack, GroupedModelSelector, HOST_WIDGETS, HUB_SESSION_RUN_MS, HlsVideo, HoverZoomImage, HubSessionTestCard, HumidifierHeroCard, HumidifierInlineControl, INPUT_COMPACT, INPUT_SHELL, IconAction, IconButton, IconPicker, ImageHeroCard, ImageInlineControl, ImageSelector, InferenceConfigSelector, Input, KebabMenu, KeyValueList, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LayeredSettingsForm, LightHeroCard, LightInlineControl, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, MODE_COLOR, MaskShapeCanvas, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, MobileDrawer, ModelPicker, MotionZonesSettings, NAVIGATION_DRIVE_INTERVAL_MS, NatResultCard, NavigationPanel, NetworkLinkBadge, NodeMultiSelectField, NodePicker, NodeSelectField, NotificationTargetSelectField, NotificationTargetsField, OPTION_SELECT_SEARCH_MIN_OPTIONS, OfflineBadge, OptionSelect, PHASE_CONFIG, PICKER_CHIP_LIMIT, PICKER_DEFAULT_GROUP_BY, PICKER_GROUP_BY_MODES, PICKER_GROUP_COLLAPSE_AT, PICKER_NONE_KEY, PICKER_NOUN_PLURAL, PICKER_NO_FILTERS, PICKER_PAGE_SIZE, PICKER_SEARCH_DEBOUNCE_MS, PICKER_WINDOW, PRIORITY, PTZOverlay, PageHeader, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PlaceholderChipField, PlayerOverlaysProvider, Popover, PopoverContent, PopoverRowAction, PopoverTrigger, PrimaryChildPicker, PrivacyMaskSettings, ProviderBadge, PtzPanel, QrCode, RECONNECT_POLICY, RECORDED_PLAYBACK_MODES, RIGHT, ROI_AREA_WARN_FRACTION, ROLE_DESCRIPTOR, RadialGauge, RecordedPlaybackProvider, RecordingPanel, ResponseLog, RoleDisplayDefaultsFromServer, RoleDisplayDefaultsProvider, RootModelSourceControl, RootSuppliedModelNote, RunReport, SCENE_CAPTURE_VARIANTS, SECTION_BODY, SECTION_CARD, SECTION_HEADER, SETTING_ROW, SETTING_ROW_LABEL, SETTING_ROW_STACK_BREAKPOINT, SETTING_ROW_VALUE, SETTING_ROW_VALUE_TEXT, SNAPSHOT_MEDIA_PATH, SPLIT_PANEL_OUTER, SPLIT_PANEL_SIDE, STACK_GAP, STATE_COLOR, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, SectionCard, SegmentedChoice, Select, SelectedChip, SemanticBadge, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideToggle, SnapshotButton, SortHeaderButton, StatCard, StateValuesStream, StatusBadge, StepChips, StepInspectorLayout, StepInspectorPanel, StepList, StepModelList, StepModelRow, StepTimings, Stepper, StreamBrokerSelector, StreamDebugOverlay, StreamPanel, Switch, SwitchHeroCard, SwitchInlineControl, SwitchPanel, SystemProvider, TABLE_SCROLL_MAX_H, TEXT_FIELD_LABEL, TEXT_HINT, TEXT_METRIC, TEXT_SECTION_LABEL, TEXT_VALUE, TIMEZONES, Tabs, TabsContent, TabsList, TabsTrigger, TapToggle, ThemeProvider, ThermostatHeroCard, ThermostatInlineControl, TimezoneSelector, Tooltip, TooltipContent, TooltipTrigger, UnitPicker, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, VodPlaybackProvider, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, ZoneEditingProvider, MicOff as a, agentColumnKey, allDeviceTypeFilterOptions, applyFleetQueryDefaults, applyPickerFilters, ariaSortForColumn, badgeFor, bindsToModel, buildPeerConnectionConfig, buildStepTreeFromSchema, EyeOff as c, catalogHasDraft, childEntityId, childListName, chipOverflow, classifyAddressScope, classifyCapability, classifySessionVerdict, clearPickerGroup, cn, columnsForContext, compareSrflxMappings, containerChildToRef, countableDevices, coverHighlight, coverageLine, createSharedContext, createTheme, cursorFractionFor, darkColors, dataTableFacets, defaultOfField, defaultTheme, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, deviceIntegrationResolver, deviceListStateOf, deviceMatchesFilter, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, draftFromQuery, emptyDevicesWidens, emptySessionRun, ensureMfHostInit, eventKindLabel, fillHeightPx, filterDataTableRows, filterDeviceOptions, filterOptions as filterOptionSelectOptions, filterPickerDevices, finalizeSessionRun, findTimezone, flattenPickerGrouping, flattenPickerRows, fleetViewOf, formatControlDateTime, formatLastSeen, formatNumeric, formatSettingValue, freezeVerdict, fuzzyMatch, getClassColor, getPhaseVisual, groupAgentColumns, groupChildrenByLayout, groupPickerDevices, groupPickerDevicesBy, hardwareLabel, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humidifierTint, Mic as i, initialScrubState, insertAtSelection, isAbsentProvider, isDataTableFilterActive, isFieldVisible, isGroupExpanded, isValueField, Camera as l, lawnMowerActivityMeta, lightColors, loadRemoteBundle, makeScrubBridge, metadataEntries, metadataString, mirror, modelRowsAreFoldable, mountAddonPage, mountPath, Square as n, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, normalizeForSearch, ImageOff as o, offListSelections, openTopLayer, optionSearchText as optionSelectSearchText, orphanDeviceLabel, overrideEntityIdFromLink, pageRows, parentDetailOf, parseIceCandidate, parsePickerGroupBy, parseRecordedServerMessage, partitionSelected as partitionOptionSelectSelected, partitionSuggested, pickerFacetFilterShown, pickerFacetKey, pickerFacetOptions, pickerFiltersActive, pickerGroupKey, pickerHiddenSelectedCount, pickerLocationKey, pickerQueryTokens, pickerRowFacts, pickerSearchText, pickerZoneFilterSuspended, pinnedStreamChoices, providerIcons, RotateCcw as r, readStoredGroupBy, reduceSessionRun, resetHubMountForTests, resetPickerFilters, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDeviceIntegration, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolveSearchable as resolveOptionSelectSearchable, resolveParentNames, resolvePrimaryChild, resolveSelectedDevices, resolveSensorDisplay, resolveStepDefaultModel, resolveTableLayout, roiTooLarge, rootSourceState, routerBasename, Grid2x2 as s, sameLocationSuggestions, scrubReducer, searchSteps, selectPickerGroup, selectedDeviceOptions, serializeRecordedCommand, settingsModelIdFor, shouldCommit, shouldEmit, shouldShowAddNewFooter, shouldShowUseQueryRow, shouldUseSingleNode, showsNoCamerasHint, sortRows, sortRowsByColumn, statusIcons, statusLine, stepFieldDomId, stepHasModelForFormat, stepLocalFields, stepModelOptions, stripParentNamePrefix, summarizeHubCandidates, Trash2 as t, tabForSelector, tankAlert, themeToCss, toStationaryOverlayBox, toggleDataTableFacet, togglePickerDevice, togglePickerKey, trpc, typeLabel, createLucideIcon as u, useAccessoriesGetStatus, useAccessoriesSetChildHidden, useAddonPagesListPages, useAddonSettingsGetDeviceSettings, useAddonSettingsGetGlobalSettings, useAddonSettingsGetIntegrationSettings, useAddonSettingsUpdateDeviceSettings, useAddonSettingsUpdateGlobalSettings, useAddonWidgetsListWidgets, useAddonsApplyAutoUpdateToAll, useAddonsCancelJob, useAddonsCustom, useAddonsForceRefresh, useAddonsGetAddonAutoUpdate, useAddonsGetAutoUpdateSettings, useAddonsGetJob, useAddonsGetLastRestart, useAddonsGetLogs, useAddonsGetVersions, useAddonsInstallFromWorkspace, useAddonsInstallPackage, useAddonsIsWorkspaceAvailable, useAddonsList, useAddonsListCapabilityProviders, useAddonsListFrameworkPackages, useAddonsListJobs, useAddonsListPackages, useAddonsListUpdates, useAddonsListWorkspacePackages, useAddonsOnAddonLogs, useAddonsReloadPackages, useAddonsRestartAddon, useAddonsRestartServer, useAddonsRetryLoad, useAddonsRollbackPackage, useAddonsSearchAvailable, useAddonsSetAddonAutoUpdate, useAddonsSetAutoUpdateSettings, useAddonsSetCapabilityProviderEnabled, useAddonsStartJob, useAddonsUninstallPackage, useAddonsUpdatePackage, useAirQualitySensorGetStatus, useAlarmPanelArm, useAlarmPanelDisarm, useAlarmPanelGetStatus, useAlarmPanelTrigger, useAlert, useAlertsDismiss, useAlertsEmit, useAlertsGetUnreadCount, useAlertsList, useAlertsMarkAllRead, useAlertsMarkRead, useAlertsUpdate, useAllWidgets, useAmbientLightSensorGetStatus, useAudioAnalysisApplyDeviceSettingsPatch, useAudioAnalysisGetDeviceLiveContribution, useAudioAnalysisGetDeviceSettingsContribution, useAudioAnalysisResolveDeviceSettings, useAudioAnalyzerAnalyseChunk, useAudioAnalyzerAttachDevice, useAudioAnalyzerClassify, useAudioAnalyzerDetachDevice, useAudioAnalyzerDispose, useAudioAnalyzerIsReady, useAudioAnalyzerReprobeAudioEngine, useAudioCodecCanHandle, useAudioCodecCloseSession, useAudioCodecCreateDecodeSession, useAudioCodecCreateEncodeSession, useAudioCodecFlushEncode, useAudioCodecListActiveSessions, useAudioCodecListSupportedCodecs, useAudioCodecPullEncoded, useAudioCodecPullPcm, useAudioCodecPushEncodedFrame, useAudioCodecPushPcm, useAudioMetricsGetCurrentSnapshot, useAudioMetricsGetHistory, useAutomationControlDisable, useAutomationControlEnable, useAutomationControlGetStatus, useAutomationControlTrigger, useBackupCancel, useBackupDelete, useBackupDeleteSchedule, useBackupGetEntries, useBackupList, useBackupListArchives, useBackupListDestinations, useBackupListLocations, useBackupListRuns, useBackupListSchedules, useBackupPreviewSchedule, useBackupRestore, useBackupTrigger, useBackupUpsertDestinationPolicy, useBackupUpsertSchedule, useBatteryGetStatus, useBatteryWakeForStream, useBinaryGetStatus, useBrightnessGetStatus, useBrightnessSetBrightness, useBrokerAdd, useBrokerGet, useBrokerGetBrokerConfig, useBrokerGetSettings, useBrokerGetSettingsSchema, useBrokerGetState, useBrokerGetStatus, useBrokerList, useBrokerListProviders, useBrokerPublish, useBrokerRemove, useBrokerSetSettings, useBrokerSubscribe, useBrokerTestConnection, useBrokerTestSettings, useBrokerUnsubscribe, useButtonPress, useCalendarsGetPreferences, useCalendarsListCalendars, useCalendarsListEvents, useCalendarsSetCalendarPreference, useCameraCredentialsGetCredentials, useCameraCredentialsGetStatus, useCameraGridLayoutApplyDeviceSettingsPatch, useCameraGridLayoutGetDeviceLiveContribution, useCameraGridLayoutGetDeviceSettingsContribution, useCameraGridLayoutGetLayout, useCameraGridLayoutSaveLayout, useCameraPipelineConfigApplyDeviceSettingsPatch, useCameraPipelineConfigGetDeviceLiveContribution, useCameraPipelineConfigGetDeviceSettingsContribution, useCameraStreamsGetBrokerStreams, useCameraStreamsGetCameraStreams, useCameraStreamsGetProfileRtspEntries, useCameraStreamsGetRtspEntries, useCameraStreamsPickStream, useCapabilityPresence, useCarbonMonoxideGetStatus, useClimateControlGetStatus, useClimateControlSetFanMode, useClimateControlSetMode, useClimateControlSetPreset, useClimateControlSetSwingHorizontal, useClimateControlSetSwingVertical, useClimateControlSetTarget, useClimateControlSetTargetHumidity, useClimateControlSetTargetRange, useClusterNodes, useClusterTopology, useColorGetStatus, useColorSetColor, useConfirm, useConnectionTestDescribeTest, useConnectionTestTestSettings, useConnectivityGetStatus, useConsumablesGetStatus, useConsumablesReset, useContactGetStatus, useContainerChildren, useControlGetStatus, useControlSetValue, useCoreBlocksCompile, useCoreBlocksCreate, useCoreBlocksCreateComposition, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetBlockSettings, useCoreBlocksGetComposition, useCoreBlocksGetCustomization, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksListComposableCaps, useCoreBlocksListCompositions, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoreBlocksUpdateBlockSettings, useCoreBlocksUpdateComposition, useCoreBlocksValidateComposition, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDataTableFilter, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderCreateSession, useDecoderDestroySession, useDecoderGetFrame, useDecoderGetInfo, useDecoderGetShmStats, useDecoderGetStats, useDecoderListActiveSessions, useDecoderOpenStream, useDecoderPullFrames, useDecoderPullHandles, useDecoderPushPacket, useDecoderReprobeHwaccel, useDecoderSupportsCodec, useDecoderUpdateConfig, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdminLink, useDeviceAdminLinkGetAdminLink, useDeviceAdoptionAdopt, useDeviceAdoptionGetCandidate, useDeviceAdoptionGetStatus, useDeviceAdoptionListCandidateFilters, useDeviceAdoptionListCandidates, useDeviceAdoptionRefresh, useDeviceAdoptionRelease, useDeviceAdoptionResync, useDeviceAutotrack, useDeviceBattery, useDeviceCapSlice, useDeviceCapability, useDeviceDetections, useDeviceDiscoveryAdoptDevice, useDeviceDiscoveryGetStatus, useDeviceDiscoveryListDiscovered, useDeviceDiscoveryRefreshDiscovery, useDeviceDiscoveryReleaseDevice, useDeviceExportApplyDeviceSettingsPatch, useDeviceExportExposeDevice, useDeviceExportGetDeviceLiveContribution, useDeviceExportGetDeviceSettingsContribution, useDeviceExportGetStatus, useDeviceExportListExposedDevices, useDeviceExportListSupportedDeviceKinds, useDeviceExportUnexposeDevice, useDeviceExtensionListCandidates, useDeviceExtensionListSlots, useDeviceExtensionListSources, useDeviceExtensionSetSlot, useDeviceId, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyInitialMeta, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerGetWrapperActivation, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListDeviceIdsByCaps, useDeviceManagerListLocationDescriptions, useDeviceManagerListLocationIcons, useDeviceManagerListLocations, useDeviceManagerListPersistedByAddon, useDeviceManagerListSiteZones, useDeviceManagerListWrappersForCap, useDeviceManagerLoadConfig, useDeviceManagerLoadMeta, useDeviceManagerLoadRuntimeState, useDeviceManagerMigrateDevice, useDeviceManagerPersistConfig, useDeviceManagerProbeStreams, useDeviceManagerProviderCreationType, useDeviceManagerProviderDiscoveryParamsSchema, useDeviceManagerRegisterDevice, useDeviceManagerRemove, useDeviceManagerRemoveByIntegration, useDeviceManagerRemoveDevice, useDeviceManagerRemoveLocation, useDeviceManagerRemoveSiteZone, useDeviceManagerRenameLocation, useDeviceManagerRenameSiteZone, useDeviceManagerRunDeviceAction, useDeviceManagerSetChildLayout, useDeviceManagerSetDisabled, useDeviceManagerSetDisplay, useDeviceManagerSetIntegrationId, useDeviceManagerSetLinkDeviceId, useDeviceManagerSetLocation, useDeviceManagerSetLocationDescription, useDeviceManagerSetLocationIcon, useDeviceManagerSetLocationZone, useDeviceManagerSetMetadata, useDeviceManagerSetName, useDeviceManagerSetPrimaryChildEntityId, useDeviceManagerSetRole, useDeviceManagerSetRoleDisplayDefaults, useDeviceManagerSetSiteZone, useDeviceManagerSetStreamProfileMap, useDeviceManagerSetType, useDeviceManagerSetWrapperActive, useDeviceManagerTestCreationField, useDeviceManagerTestField, useDeviceManagerUpdateConfig, useDeviceManagerUpdateDeviceField, useDeviceManagerUpdateDeviceFieldsBatch, useDeviceNetworkLink, useDeviceOpsGetConfigEntries, useDeviceOpsGetRawState, useDeviceOpsGetSettingsSchema, useDeviceOpsGetStreamSources, useDeviceOpsRemoveDevice, useDeviceOpsRunAction, useDeviceOpsSetConfig, useDeviceProviderAdoptDiscoveredDevice, useDeviceProviderCreateDevice, useDeviceProviderDiscoverDevices, useDeviceProviderGetChildCreationSchema, useDeviceProviderGetDevices, useDeviceProviderGetDiscoveryParamsSchema, useDeviceProviderGetManualCreationType, useDeviceProviderGetStatus, useDeviceProviderReloadDevice, useDeviceProviderStart, useDeviceProviderStop, useDeviceProviderSupportsDiscovery, useDeviceProviderSupportsManualCreation, useDeviceProviderTestCreationField, useDeviceProxy, useDeviceQuickDetailOpen, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateClaimFields, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetNativeCapSlice, useDeviceStateGetSnapshot, useDeviceStateListClaims, useDeviceStatePatchOwnedFields, useDeviceStateReleaseClaim, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDoorbellEvents, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, useFaceGalleryAssignFace, useFaceGalleryAssignFaces, useFaceGalleryAuditIdentitySamples, useFaceGalleryCreateIdentity, useFaceGalleryDeleteFace, useFaceGalleryDeleteIdentity, useFaceGalleryGetFaceByTrack, useFaceGalleryGetFaceMedia, useFaceGalleryListIdentities, useFaceGalleryListIdentitySamples, useFaceGalleryListRecentFaces, useFaceGalleryRemoveSample, useFaceGalleryRenameIdentity, useFaceGallerySuggestFaceClusters, useFaceGalleryUnassignFace, useFaceGalleryUnassignFaces, useFanControlGetStatus, useFanControlSetDirection, useFanControlSetOscillating, useFanControlSetPercentage, useFanControlSetPreset, useFeatureProbeGetStatus, useFloodGetStatus, useGasGetStatus, useHumidifierGetStatus, useHumidifierSetMode, useHumidifierSetOn, useHumidifierSetTargetHumidity, useHumiditySensorGetStatus, useImageGetStatus, useImageSettingsGetOptions, useImageSettingsGetStatus, useImageSettingsSetSettings, useIntegrationsCreate, useIntegrationsDelete, useIntegrationsGet, useIntegrationsGetAvailableTypes, useIntegrationsGetByAddonId, useIntegrationsGetSettings, useIntegrationsList, useIntegrationsSetSettings, useIntegrationsTestConnection, useIntegrationsUpdate, useIntercomEndTalkSession, useIntercomGetStatus, useIntercomHandleAnswer, useIntercomPushTalkAudio, useIntercomStartSession, useIntercomStartTalkSession, useIntercomStopSession, useIsMidWidth, useIsMobile, useLawnMowerControlDock, useLawnMowerControlGetStatus, useLawnMowerControlPause, useLawnMowerControlStartMowing, useLiveBuffer, useLiveEvent, useLlmCancel, useLlmDeleteModel, useLlmDeleteProfile, useLlmGenerate, useLlmGenerateVision, useLlmGetDefaults, useLlmGetRuntimeStatus, useLlmGetUsage, useLlmInstallModel, useLlmListModelCatalog, useLlmListModels, useLlmListNodeModels, useLlmListProfileKinds, useLlmListProfiles, useLlmListRuntimeNodes, useLlmResolveModelRef, useLlmSetDefault, useLlmStartRuntime, useLlmStopRuntime, useLlmTestProfile, useLlmUpsertProfile, useLocalNetworkAddCustomAddress, useLocalNetworkDownloadCa, useLocalNetworkGetAddresses, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetHubAddresses, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkRemoveCustomAddress, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkSetAddressRole, useLocalNetworkSetAllowedAddresses, useLocalNetworkSetNotificationEndpoint, useLocalNetworkSetViewerEndpoints, useLocalNetworkUploadCertificate, useLockControlGetStatus, useLockControlLock, useLockControlOpen, useLockControlUnlock, useMediaPlayerGetStatus, useMediaPlayerNext, useMediaPlayerPause, useMediaPlayerPlay, useMediaPlayerPlayMedia, useMediaPlayerPrevious, useMediaPlayerSeek, useMediaPlayerSelectSource, useMediaPlayerSetMute, useMediaPlayerSetRepeat, useMediaPlayerSetShuffle, useMediaPlayerSetVolume, useMediaPlayerStop, useMeshNetworkGetStatus, useMeshNetworkJoin, useMeshNetworkLeave, useMeshNetworkListPeers, useMeshNetworkLogout, useMeshNetworkStartLogin, useMeshNetworkTestConnection, useMetricsProviderCollectSnapshot, useMetricsProviderGetAddonStats, useMetricsProviderGetCached, useMetricsProviderGetCpuTemperature, useMetricsProviderGetCurrent, useMetricsProviderGetDiskSpace, useMetricsProviderGetGpuInfo, useMetricsProviderGetLoadSeries, useMetricsProviderGetProcessStats, useMetricsProviderListAddonInstances, useMetricsProviderListNodeProcesses, useMotionDetectionAnalyze, useMotionDetectionApplyDeviceSettingsPatch, useMotionDetectionGetDeviceLiveContribution, useMotionDetectionGetDeviceSettingsContribution, useMotionDetectionRemoveCamera, useMotionDetectionReset, useMotionGetStatus, useMotionIsDetected, useMotionTriggerGetStatus, useMotionTriggerSetMotionTrigger, useMotionZonesGetOptions, useMotionZonesGetStatus, useMotionZonesSetZone, useMqttBrokerAddBroker, useMqttBrokerGetBrokerConfig, useMqttBrokerGetStatus, useMqttBrokerListBrokers, useMqttBrokerRemoveBroker, useMqttBrokerStartEmbeddedBroker, useMqttBrokerStopEmbeddedBroker, useMqttBrokerTestConnection, useNativeObjectDetectionGetOptions, useNativeObjectDetectionGetStatus, useNativeObjectDetectionSetEnabled, useNativeObjectDetectionSetSettings, useNavigation, useNavigationGetFeatures, useNavigationGetStatus, useNavigationGoToPoint, useNavigationListActions, useNavigationMove, useNavigationPlaySound, useNavigationRunAction, useNavigationSetLightLevel, useNavigationSetLightMode, useNavigationSetLightOn, useNavigationStop, useNetworkAccessGetEndpoint, useNetworkAccessGetStatus, useNetworkAccessListEndpoints, useNetworkAccessStart, useNetworkAccessStop, useNetworkLinkGetStatus, useNetworkQualityGetAllStats, useNetworkQualityGetDeviceStats, useNetworkQualityReportClientStats, useNodesClusterAddonStatus, useNodesDeployAddon, useNodesDirectory, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputGetTarget, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputProbeTargetConfig, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesActivateAlarmProfile, useNotificationRulesCancelSnooze, useNotificationRulesCreateAlarmProfile, useNotificationRulesCreateRule, useNotificationRulesCreateSequence, useNotificationRulesCreateSnooze, useNotificationRulesDeleteAlarmProfile, useNotificationRulesDeleteRule, useNotificationRulesDeleteSequence, useNotificationRulesGetAlarmConfig, useNotificationRulesGetAlarmSensors, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesGetRuleLastRuns, useNotificationRulesGetSequence, useNotificationRulesGetTemplateCatalog, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSequences, useNotificationRulesListSnoozes, useNotificationRulesPreviewStateSummary, useNotificationRulesPreviewTemplate, useNotificationRulesRenameAlarmProfile, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotificationRulesUpdateSequence, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerDeleteTemplate, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerListTemplates, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdManagerUpsertTemplate, useOsdSetOverlay, usePTZ, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePickerSiteZones, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTrackRelation, usePipelineAnalyticsClearTracks, usePipelineAnalyticsCompleteRetrainTrack, usePipelineAnalyticsCountRelocatableMedia, usePipelineAnalyticsCountUnstampedEventMedia, usePipelineAnalyticsDeleteDeviceEvents, usePipelineAnalyticsDeleteTracks, usePipelineAnalyticsDeselectRetrainFrame, usePipelineAnalyticsGetActiveTracks, usePipelineAnalyticsGetAudioEvents, usePipelineAnalyticsGetDeviceLiveContribution, usePipelineAnalyticsGetDeviceSettingsContribution, usePipelineAnalyticsGetEventDensity, usePipelineAnalyticsGetEventDensityBatch, usePipelineAnalyticsGetEventMedia, usePipelineAnalyticsGetEventMediaFootprintByKind, usePipelineAnalyticsGetEventStoreFootprint, usePipelineAnalyticsGetKeyEvents, usePipelineAnalyticsGetKeyEventsBatch, usePipelineAnalyticsGetMediaReclaimStatus, usePipelineAnalyticsGetMotionEvents, usePipelineAnalyticsGetObjectEmbeddingRebuildStatus, usePipelineAnalyticsGetObjectEvents, usePipelineAnalyticsGetRetrainExportUrl, usePipelineAnalyticsGetRetrainFrameImage, usePipelineAnalyticsGetSensorEvents, usePipelineAnalyticsGetStorageMigrationMoveStatus, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTrackRelations, usePipelineAnalyticsListTracks, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsSetTrackPurity, usePipelineAnalyticsSetTrackRelation, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineExecutorCacheFrameInPool, usePipelineExecutorClearDeviceOverrides, usePipelineExecutorClearModelBoundDeviceOverrides, usePipelineExecutorDeleteModel, usePipelineExecutorDeleteTemplate, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDefaultSteps, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetGlobalPipelineConfig, usePipelineExecutorGetGlobalSteps, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorListTemplates, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSaveTemplate, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorUpdateTemplate, usePipelineExecutorValidatePipeline, usePipelineOrchestratorApplyAutoTune, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorDeleteTemplate, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraStepOverrides, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetClusterModelChoice, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetEffectiveShares, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetPlacementStats, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorListTemplates, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorPlanAutoTune, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorRequestOccupancyLook, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSaveTemplate, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraPipelineForAgent, usePipelineOrchestratorSetCameraSensors, usePipelineOrchestratorSetCameraStepOverride, usePipelineOrchestratorSetCameraStepSettings, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetLoadBalancingShares, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorSetShareSource, usePipelineOrchestratorSuggestShares, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, usePipelineOrchestratorUpdateTemplate, usePipelineRunnerAttachCamera, usePipelineRunnerDetachCamera, usePipelineRunnerGetAllCameraMetrics, usePipelineRunnerGetCameraMetrics, usePipelineRunnerGetLocalCameras, usePipelineRunnerGetLocalLoad, usePipelineRunnerGetLocalMetrics, usePipelineRunnerGetNativeCrop, usePipelineRunnerGetParkedTrackFrame, usePipelineRunnerParkTrackFrame, usePipelineRunnerReleaseParkedTrackFrames, usePipelineRunnerReportMotion, usePipelineRunnerRequestOccupancyBurst, usePipelineRunnerRunDetailSubtree, usePipelineRunnerRunStatelessStep, usePlateGalleryAssignPlate, usePlateGalleryAssignPlates, usePlateGalleryCorrectPlateText, usePlateGalleryCreateVehicle, usePlateGalleryDeletePlate, usePlateGalleryDeleteVehicle, usePlateGalleryGetPlateByTrack, usePlateGalleryGetPlateMedia, usePlateGalleryListPlates, usePlateGalleryListVehicleSamples, usePlateGalleryListVehicles, usePlateGalleryRemoveVehicleSample, usePlateGalleryRenameVehicle, usePlateGallerySearchPlates, usePlateGallerySuggestPlateClusters, usePlateGalleryUnassignPlate, usePlateGalleryUnassignPlates, usePlayerOverlayLayer, usePlayerOverlayLayers, usePlayerToolbarButton, usePlayerToolbarButtons, usePowerMeterGetStatus, usePresenceGetStatus, usePressureSensorGetStatus, usePrivacyMaskGetOptions, usePrivacyMaskGetStatus, usePrivacyMaskSetAudioEnabled, usePrivacyMaskSetMask, usePrompt, usePtzAutotrackGetSettings, usePtzAutotrackGetStatus, usePtzAutotrackSetEnabled, usePtzAutotrackSetSettings, usePtzCaptureHomeHere, usePtzContinuousMove, usePtzDeletePreset, usePtzGetHomePreset, usePtzGetHomeReturn, usePtzGetOptions, usePtzGetPosition, usePtzGetPresets, usePtzGetStatus, usePtzGoHome, usePtzGoToPreset, usePtzMove, usePtzSavePreset, usePtzSetAutofocus, usePtzSetHomePreset, usePtzSetHomeReturn, usePtzStop, useRebootReboot, useRecordedPlayback, useRecordingArchiveApplyDeviceSettingsPatch, useRecordingArchiveCancelRelocateJob, useRecordingArchiveCancelStorageMigrationMove, useRecordingArchiveDeleteFootprint, useRecordingArchiveGetAvailabilityBatch, useRecordingArchiveGetDaysWithRecordingsBatch, useRecordingArchiveGetDeviceConfig, useRecordingArchiveGetDeviceLiveContribution, useRecordingArchiveGetDeviceSettingsContribution, useRecordingArchiveGetPlacement, useRecordingArchiveGetRelocateResidue, useRecordingArchiveGetStatus, useRecordingArchiveGetStorageMigrationMoveStatus, useRecordingArchiveGetStorageUsage, useRecordingArchiveListOpsLog, useRecordingArchiveListRelocateJobs, useRecordingArchiveLocateSegment, useRecordingArchivePauseForStorageMigration, useRecordingArchivePlanStorageRebalance, useRecordingArchivePruneFootage, useRecordingArchiveReadGopBytes, useRecordingArchiveReadSegmentBytes, useRecordingArchiveReadWindowBytes, useRecordingArchiveReconcileLedgerAgainstDisk, useRecordingArchiveRefreshStorageLocationsForMigration, useRecordingArchiveRelocateFootage, useRecordingArchiveRenderClip, useRecordingArchiveRenderGif, useRecordingArchiveRescanStorage, useRecordingArchiveResumeForStorageMigration, useRecordingArchiveSetDeviceConfig, useRecordingArchiveSetDevicePlacement, useRecordingArchiveStartStorageMigrationMove, useRecordingArchiveStartStorageRebalance, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetDaysWithRecordings, useRecordingGetPlayback, useRecordingGetPlaybackOptions, useRecordingListSources, useRecordingOnboardGetOptions, useRecordingOnboardGetStatus, useRecordingOnboardSetSettings, useRecordingSignalGetStatus, useRemoteComponent, useRoleDisplayDefaults, useSceneMonitorCaptureReference, useSceneMonitorCreateScene, useSceneMonitorDeleteReference, useSceneMonitorDeleteScene, useSceneMonitorGetStatus, useSceneMonitorListScenes, useSceneMonitorListScenesBatch, useSceneMonitorRecheckNow, useSceneMonitorResetScene, useSceneMonitorUpdateScene, useScriptRunnerGetStatus, useScriptRunnerRun, useScriptRunnerStop, useScrubController, useServerManagementApplyServerUpdate, useServerManagementCheckServerUpdate, useServerManagementGetServerPackageStatus, useServerManagementRestartServer, useServerManagementRollbackServerUpdate, useSettingsStoreAggregate, useSettingsStoreCount, useSettingsStoreDeclareCollection, useSettingsStoreDelete, useSettingsStoreDeleteWhere, useSettingsStoreGet, useSettingsStoreHistogram, useSettingsStoreInsert, useSettingsStoreInsertMany, useSettingsStoreIsEmpty, useSettingsStoreQuery, useSettingsStoreSet, useSettingsStoreUpdate, useSettingsStoreUpdateWhere, useSettingsStoreUpsert, useSmokeGetStatus, useSnapshotApplyDeviceSettingsPatch, useSnapshotGetDebugState, useSnapshotGetDeviceLiveContribution, useSnapshotGetDeviceSettingsContribution, useSnapshotGetSnapshot, useSnapshotGetSnapshotLinks, useSnapshotGetSnapshotOverview, useSnapshotGetStatus, useSnapshotInvalidateCache, useStationaryOverlay, useStorageAbortUpload, useStorageBeginDownload, useStorageBeginUpload, useStorageDelete, useStorageDeleteLocation, useStorageEndDownload, useStorageExists, useStorageFinalizeUpload, useStorageGetAvailableSpace, useStorageList, useStorageListDrainProgress, useStorageListLocationDeclarations, useStorageListLocations, useStorageListProviders, useStorageMigrationCancel, useStorageMigrationCleanupCancel, useStorageMigrationCleanupStart, useStorageMigrationCleanupStatus, useStorageMigrationDrain, useStorageMigrationHistory, useStorageMigrationMovers, useStorageMigrationPlan, useStorageMigrationResidue, useStorageMigrationStart, useStorageMigrationStatus, useStorageRead, useStorageReadChunk, useStorageResolve, useStorageTestConfig, useStorageTestLocation, useStorageUpsertLocation, useStorageWrite, useStorageWriteChunk, useStoredGroupBy, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerPullFrameHandles, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerSubscribeFrames, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, useStreamBrokerUnsubscribeFrames, useStreamCatalogGetCatalog, useStreamParamsGetConfigSchema, useStreamParamsGetOptions, useStreamParamsGetStatus, useStreamParamsSetProfile, useStreamSignalsListSignals, useSwitchGetStatus, useSwitchSetState, useSystem, useSystemDetectSiteLocation, useSystemFeatureFlags, useSystemForceRetentionCleanup, useSystemGetFailureContributions, useSystemGetLoadContributions, useSystemGetLoggingSettings, useSystemGetRequestCensus, useSystemGetRetentionConfig, useSystemGetSiteLocation, useSystemHealth, useSystemInfo, useSystemMutation, useSystemNetworkAddresses, useSystemQuery, useSystemSetLoggingSettings, useSystemSetRetentionConfig, useSystemSetSiteLocation, useTamperGetStatus, useTemperatureSensorGetStatus, useTerminalSessionAdoptLegacyMonitor, useTerminalSessionClose, useTerminalSessionCreateInstance, useTerminalSessionDeleteInstance, useTerminalSessionListInstances, useTerminalSessionListLegacyCameras, useTerminalSessionListProfiles, useTerminalSessionListSessions, useTerminalSessionOpenSession, useTerminalSessionPullOutput, useTerminalSessionResize, useTerminalSessionSetInstanceEnabled, useTerminalSessionUpdateInstance, useTerminalSessionWriteInput, useThemeMode, useToastOnToast, useTurnProviderGetTurnServers, useUpdateGetStatus, useUpdateInstallUpdate, useUrlQueryParam, useUserManagementConfirmTotp, useUserManagementCreateApiKey, useUserManagementCreateScopedToken, useUserManagementCreateUser, useUserManagementDeleteUser, useUserManagementDisableTotp, useUserManagementGetTotpStatus, useUserManagementListApiKeys, useUserManagementListOauthSessions, useUserManagementListScopedTokens, useUserManagementListUsers, useUserManagementOauthExchangeCode, useUserManagementOauthIssueCode, useUserManagementOauthRefresh, useUserManagementOauthVerifyAccessToken, useUserManagementResetPassword, useUserManagementRevokeApiKey, useUserManagementRevokeOauthSession, useUserManagementRevokeScopedToken, useUserManagementSetUserScopes, useUserManagementSetupTotp, useUserManagementUpdateUser, useUserManagementValidateApiKey, useUserManagementValidateCredentials, useUserManagementValidateScopedToken, useUserManagementVerifyTotp, useVacuumControlGetStatus, useVacuumControlLocate, useVacuumControlPause, useVacuumControlReturnToBase, useVacuumControlSetFanSpeed, useVacuumControlStart, useVacuumControlStop, useValveClose, useValveGetStatus, useValveOpen, useValveSetPosition, useValveStop, useVibrationGetStatus, useVideoclipsDialClipStream, useVideoclipsGetClipPlayback, useVideoclipsGetPlaybackOptions, useVideoclipsListClips, useVideoclipsListSources, useVideoclipsOfferClipBytes, useVideoclipsReadClipBytes, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionApplyDownlinkProbe, useWebrtcSessionCloseSession, useWebrtcSessionCreateSession, useWebrtcSessionGetIceCandidates, useWebrtcSessionGetSessionDebug, useWebrtcSessionGetSessionState, useWebrtcSessionHandleAnswer, useWebrtcSessionHandleOffer, useWebrtcSessionHasAdaptiveBitrate, useWebrtcSessionListStreams, useWidget, useWidgetMetadata, useWidgetRegistry, useZoneAnalyticsGetCameraHistory, useZoneAnalyticsGetCurrentSnapshot, useZoneAnalyticsGetCurrentSnapshotBatch, useZoneAnalyticsGetUnzonedHistory, useZoneAnalyticsGetZoneHistory, useZoneEditing, useZoneRulesListRules, useZoneRulesSetRules, useZonesAddZone, useZonesListZones, useZonesRemoveZone, useZonesUpdateZone, vacuumStateMeta, validateScopes, valveStateMeta, variantLabel, waterHeaterPhase, waterHeaterTint, weatherConditionMeta, weatherTint, withResolvedParentDetail, withUseRootModel, writeStoredGroupBy };