@camstack/addon-matter-broker 0.1.24 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +560 -104
  2. package/dist/addon.mjs +560 -104
  3. package/package.json +1 -1
package/dist/addon.mjs CHANGED
@@ -7110,6 +7110,17 @@ var ModelCatalogEntrySchema = object({
7110
7110
  "imagenet",
7111
7111
  "none"
7112
7112
  ]).optional(),
7113
+ /**
7114
+ * The model already applies softmax IN-GRAPH — its raw output is a
7115
+ * probability distribution, not logits. When set, the `softmax`
7116
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7117
+ * probability vector collapses it toward uniform (top-1 score craters far
7118
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7119
+ * the output is raw logits and the postprocessor applies softmax (the normal
7120
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7121
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7122
+ */
7123
+ outputProbabilities: boolean().optional(),
7113
7124
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7114
7125
  /**
7115
7126
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -7669,6 +7680,160 @@ var EncodeProfileSchema = object({
7669
7680
  */
7670
7681
  outputArgs: array(string$2()).optional()
7671
7682
  });
7683
+ var COCO_TO_MACRO = {
7684
+ mapping: {
7685
+ person: "person",
7686
+ bicycle: "vehicle",
7687
+ car: "vehicle",
7688
+ motorcycle: "vehicle",
7689
+ airplane: "vehicle",
7690
+ bus: "vehicle",
7691
+ train: "vehicle",
7692
+ truck: "vehicle",
7693
+ boat: "vehicle",
7694
+ bird: "animal",
7695
+ cat: "animal",
7696
+ dog: "animal",
7697
+ horse: "animal",
7698
+ sheep: "animal",
7699
+ cow: "animal",
7700
+ elephant: "animal",
7701
+ bear: "animal",
7702
+ zebra: "animal",
7703
+ giraffe: "animal",
7704
+ suitcase: "package",
7705
+ backpack: "package",
7706
+ handbag: "package"
7707
+ },
7708
+ preserveOriginal: false
7709
+ };
7710
+ var AUDIO_MACRO_LABELS = [
7711
+ {
7712
+ id: "speech",
7713
+ name: "Speech",
7714
+ icon: "🗣️"
7715
+ },
7716
+ {
7717
+ id: "scream",
7718
+ name: "Scream / Shout",
7719
+ icon: "😱"
7720
+ },
7721
+ {
7722
+ id: "crying",
7723
+ name: "Crying / Baby",
7724
+ icon: "😢"
7725
+ },
7726
+ {
7727
+ id: "laughter",
7728
+ name: "Laughter",
7729
+ icon: "😂"
7730
+ },
7731
+ {
7732
+ id: "music",
7733
+ name: "Music",
7734
+ icon: "🎵"
7735
+ },
7736
+ {
7737
+ id: "dog",
7738
+ name: "Dog",
7739
+ icon: "🐕"
7740
+ },
7741
+ {
7742
+ id: "cat",
7743
+ name: "Cat",
7744
+ icon: "🐈"
7745
+ },
7746
+ {
7747
+ id: "bird",
7748
+ name: "Bird",
7749
+ icon: "🐦"
7750
+ },
7751
+ {
7752
+ id: "animal",
7753
+ name: "Animal (other)",
7754
+ icon: "🐾"
7755
+ },
7756
+ {
7757
+ id: "alarm",
7758
+ name: "Alarm / Siren",
7759
+ icon: "🚨"
7760
+ },
7761
+ {
7762
+ id: "doorbell",
7763
+ name: "Doorbell / Knock",
7764
+ icon: "🔔"
7765
+ },
7766
+ {
7767
+ id: "glass_breaking",
7768
+ name: "Glass Breaking",
7769
+ icon: "💥"
7770
+ },
7771
+ {
7772
+ id: "gunshot",
7773
+ name: "Gunshot / Explosion",
7774
+ icon: "💣"
7775
+ },
7776
+ {
7777
+ id: "vehicle",
7778
+ name: "Vehicle",
7779
+ icon: "🚗"
7780
+ },
7781
+ {
7782
+ id: "siren",
7783
+ name: "Emergency Siren",
7784
+ icon: "🚑"
7785
+ },
7786
+ {
7787
+ id: "fire",
7788
+ name: "Fire / Smoke",
7789
+ icon: "🔥"
7790
+ },
7791
+ {
7792
+ id: "water",
7793
+ name: "Water",
7794
+ icon: "💧"
7795
+ },
7796
+ {
7797
+ id: "wind",
7798
+ name: "Wind / Weather",
7799
+ icon: "🌬️"
7800
+ },
7801
+ {
7802
+ id: "door",
7803
+ name: "Door",
7804
+ icon: "🚪"
7805
+ },
7806
+ {
7807
+ id: "footsteps",
7808
+ name: "Footsteps",
7809
+ icon: "👣"
7810
+ },
7811
+ {
7812
+ id: "crowd",
7813
+ name: "Crowd / Chatter",
7814
+ icon: "👥"
7815
+ },
7816
+ {
7817
+ id: "telephone",
7818
+ name: "Telephone",
7819
+ icon: "📞"
7820
+ },
7821
+ {
7822
+ id: "engine",
7823
+ name: "Engine / Motor",
7824
+ icon: "⚙️"
7825
+ },
7826
+ {
7827
+ id: "tools",
7828
+ name: "Tools / Construction",
7829
+ icon: "🔨"
7830
+ },
7831
+ {
7832
+ id: "silence",
7833
+ name: "Silence",
7834
+ icon: "🤫"
7835
+ }
7836
+ ];
7672
7837
  var YAMNET_TO_MACRO = {
7673
7838
  mapping: {
7674
7839
  Speech: "speech",
@@ -7935,6 +8100,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
7935
8100
  for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
7936
8101
  for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
7937
8102
  /**
8103
+ * Unified event-kind taxonomy — THE single source of truth for
8104
+ * `kind → { parentKind, category, level, color, iconId, labelKey, label,
8105
+ * icon }`.
8106
+ *
8107
+ * This dictionary folds together what used to be scattered across four
8108
+ * copies:
8109
+ * - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
8110
+ * - `addon-post-analysis/.../services/event-kinds.ts`
8111
+ * (MOTION/PERSON/VEHICLE… _COLOR constants)
8112
+ * - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
8113
+ * - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
8114
+ * - the COCO / audio class maps (macro ↔ sub relationships)
8115
+ *
8116
+ * The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
8117
+ * `@camstack/types`. The UI-side mapping `iconId → lucide component` and
8118
+ * `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
8119
+ * color or an icon: they read this dictionary (server descriptors carry the
8120
+ * fields inline; the client resolves color/icon/label from `iconId`/`kind`).
8121
+ *
8122
+ * Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
8123
+ */
8124
+ var TAXONOMY_COLORS = {
8125
+ motion: "#f59e0b",
8126
+ audio: "#06b6d4",
8127
+ person: "#22c55e",
8128
+ vehicle: "#3b82f6",
8129
+ animal: "#f97316",
8130
+ package: "#a855f7",
8131
+ sensor: "#8b5cf6",
8132
+ control: "#10b981",
8133
+ genericDetection: "#64748b"
8134
+ };
8135
+ var DETECTION_SUB_COLORS = {
8136
+ car: "#f59e0b",
8137
+ truck: "#d97706",
8138
+ bus: "#b45309",
8139
+ motorcycle: "#eab308",
8140
+ bicycle: "#ca8a04",
8141
+ airplane: "#60a5fa",
8142
+ boat: "#2563eb",
8143
+ train: "#1d4ed8",
8144
+ bird: "#14b8a6",
8145
+ dog: "#84cc16",
8146
+ cat: "#f97316",
8147
+ horse: "#a16207",
8148
+ sheep: "#a3a3a3",
8149
+ cow: "#78716c",
8150
+ elephant: "#6b7280",
8151
+ bear: "#7c2d12",
8152
+ zebra: "#404040",
8153
+ giraffe: "#d4a373"
8154
+ };
8155
+ function titleCase(id) {
8156
+ return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
8157
+ }
8158
+ var entries = /* @__PURE__ */ new Map();
8159
+ function macro(kind, category, color, iconId, label) {
8160
+ entries.set(kind, {
8161
+ kind,
8162
+ parentKind: null,
8163
+ level: "macro",
8164
+ category,
8165
+ color,
8166
+ iconId,
8167
+ labelKey: `eventKind.${kind}`,
8168
+ label
8169
+ });
8170
+ }
8171
+ function sub(kind, parentKind, category, color, iconId, label) {
8172
+ entries.set(kind, {
8173
+ kind,
8174
+ parentKind,
8175
+ level: "sub",
8176
+ category,
8177
+ color,
8178
+ iconId,
8179
+ labelKey: `eventKind.${kind}`,
8180
+ label
8181
+ });
8182
+ }
8183
+ macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
8184
+ macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
8185
+ macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
8186
+ macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
8187
+ macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
8188
+ macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
8189
+ macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
8190
+ macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
8191
+ for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
8192
+ if (macroClass !== "vehicle" && macroClass !== "animal") continue;
8193
+ if (entries.has(cocoClass)) continue;
8194
+ sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
8195
+ }
8196
+ sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
8197
+ sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
8198
+ sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
8199
+ sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
8200
+ sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
8201
+ sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
8202
+ sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
8203
+ sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
8204
+ sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
8205
+ sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
8206
+ sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
8207
+ sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
8208
+ sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
8209
+ sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
8210
+ sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
8211
+ sub("siren", "control", "control", "#dc2626", "siren", "Siren");
8212
+ sub("button", "control", "control", "#10b981", "button", "Button");
8213
+ sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
8214
+ for (const l of AUDIO_MACRO_LABELS) {
8215
+ const kind = `audio-${l.id}`;
8216
+ if (entries.has(kind)) continue;
8217
+ sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
8218
+ }
8219
+ /** The complete taxonomy dictionary, keyed by kind. */
8220
+ var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
8221
+ /**
7938
8222
  * Error types for the safe expression engine. Two distinct classes so callers
7939
8223
  * can tell a compile-time (grammar) failure from a runtime (evaluation)
7940
8224
  * failure — both are non-fatal to the host: read paths degrade to "skip link".
@@ -12127,10 +12411,7 @@ var ConfigUISchemaNullableBridge = custom();
12127
12411
  var InferenceCapabilitiesBridge = custom();
12128
12412
  var ModelAvailabilityListBridge = custom();
12129
12413
  var PipelineRunResultBridge = custom();
12130
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12131
- kind: "mutation",
12132
- auth: "admin"
12133
- }), method(object({ nodeId: string$2() }), EngineProvisioningSchema), method(_void(), record(string$2(), object({
12414
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string$2() }), EngineProvisioningSchema), method(_void(), record(string$2(), object({
12134
12415
  modelId: string$2(),
12135
12416
  settings: record(string$2(), unknown()).readonly()
12136
12417
  }))), method(object({ steps: record(string$2(), object({
@@ -12190,13 +12471,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12190
12471
  * (inputClasses ≠ null) are skipped and served per-track via
12191
12472
  * pipelineRunner.runDetailSubtree (two-plane design).
12192
12473
  */
12193
- plane: _enum(["full", "frame"]).optional()
12474
+ plane: _enum(["full", "frame"]).optional(),
12475
+ /**
12476
+ * Inference-device selector (Phase 2 multi-device). Format
12477
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12478
+ * Omitted ⇒ the runner's default device (current single-engine
12479
+ * behaviour). Selects WHICH device pool of the node runs the call.
12480
+ */
12481
+ deviceKey: string$2().optional()
12194
12482
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12195
12483
  engine: PipelineEngineChoiceSchema.optional(),
12196
12484
  steps: array(PipelineStepInputSchema).min(1),
12197
12485
  frames: array(FrameInputSchema).min(1).max(255),
12198
12486
  deviceId: number().optional(),
12199
- sessionId: string$2().optional()
12487
+ sessionId: string$2().optional(),
12488
+ /**
12489
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12490
+ * the batch to the Python pool's bench preprocess cache
12491
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12492
+ * preprocessed ONCE and every later inference is a pure-inference cache
12493
+ * hit — the sustained-throughput run measures inference, not
12494
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12495
+ * full preprocess every call, correct). Fresh per sustained run;
12496
+ * released via `uncacheFrame`.
12497
+ */
12498
+ frameId: number().int().nonnegative().optional(),
12499
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12500
+ deviceKey: string$2().optional()
12200
12501
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12201
12502
  data: _instanceof(Uint8Array),
12202
12503
  width: number().int().positive(),
@@ -12228,8 +12529,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12228
12529
  * - `runtime` — main camera-serving engine (no idle TTL).
12229
12530
  * - `warm-override` — benchmark/test override held in the warm
12230
12531
  * cache; auto-disposed after the idle TTL.
12532
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12533
+ * multi-device, keyed by `deviceKey`) resolved
12534
+ * via `resolveDeviceFactory`. Runs alongside the
12535
+ * `runtime` engine on a DIFFERENT accelerator
12536
+ * (NPU / iGPU / Coral) — this is how the
12537
+ * Engines tab shows all pools running at once.
12231
12538
  */
12232
- kind: _enum(["runtime", "warm-override"]),
12539
+ kind: _enum([
12540
+ "runtime",
12541
+ "warm-override",
12542
+ "device-pool"
12543
+ ]),
12233
12544
  /** Native pid of the underlying Python pool (null when no pool). */
12234
12545
  poolPid: number().nullable(),
12235
12546
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12604,7 +12915,14 @@ var RunnerCameraConfigSchema = object({
12604
12915
  * camera's detect node differs from its source-owner (P2d, gated by the
12605
12916
  * `remoteSourcingNodes` rollout setting).
12606
12917
  */
12607
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12918
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12919
+ /**
12920
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12921
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12922
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12923
+ * this only selects WHICH device pool of that node runs the session.
12924
+ */
12925
+ deviceKey: string$2().optional()
12608
12926
  });
12609
12927
  motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
12610
12928
  /**
@@ -12625,6 +12943,19 @@ var RunnerLocalLoadSchema = object({
12625
12943
  avgInferenceTimeMs: number(),
12626
12944
  /** Total queue depth across motion + detection queues. */
12627
12945
  queueDepthTotal: number(),
12946
+ /**
12947
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
12948
+ * this runner currently has attached cameras on, so the orchestrator's second
12949
+ * `balance()` pass (over a node's devices) weights on real per-pool session
12950
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
12951
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
12952
+ */
12953
+ devices: array(object({
12954
+ deviceKey: string$2(),
12955
+ backend: string$2(),
12956
+ attachedCameras: number(),
12957
+ queueDepthTotal: number()
12958
+ })).default([]),
12628
12959
  /** Hardware capability flags reported by this node. */
12629
12960
  hardware: object({
12630
12961
  hasGpu: boolean(),
@@ -15773,6 +16104,8 @@ var BaseDeviceProvider = class extends BaseAddon {
15773
16104
  return toDeviceSummary(device, this.addonId);
15774
16105
  }
15775
16106
  };
16107
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
16108
+ new Set(Object.values(DeviceType));
15776
16109
  /**
15777
16110
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
15778
16111
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -18933,17 +19266,30 @@ var EventKindCategorySchema = _enum([
18933
19266
  "audio",
18934
19267
  "detection",
18935
19268
  "sensor",
19269
+ "control",
18936
19270
  "custom",
18937
19271
  "package"
18938
19272
  ]);
19273
+ /** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
19274
+ var EventKindLevelSchema = _enum(["macro", "sub"]);
18939
19275
  var EventKindDescriptorSchema = object({
18940
- /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
19276
+ /** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
18941
19277
  kind: string$2(),
19278
+ /** i18n key resolved on the UI side; `label` is the English fallback. */
19279
+ labelKey: string$2(),
19280
+ /** English fallback label (kept for clients that don't translate). */
18942
19281
  label: string$2(),
18943
19282
  /** Hex color for timeline/legend rendering. */
18944
19283
  color: string$2(),
19284
+ /** Dictionary id → lucide component on the UI side. */
19285
+ iconId: string$2(),
19286
+ /** Legacy closed-vocab glyph — fallback for `iconId`. */
18945
19287
  icon: EventKindIconSchema,
18946
19288
  category: EventKindCategorySchema,
19289
+ /** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
19290
+ parentKind: string$2().nullable(),
19291
+ /** Derived from `parentKind`, explicit for the client tree. */
19292
+ level: EventKindLevelSchema,
18947
19293
  /** Which cap + device contributes this kind. For built-ins the camera
18948
19294
  * itself; for sensor kinds the LINKED source device. */
18949
19295
  source: object({
@@ -19016,11 +19362,21 @@ var TrackAudioLabelSchema = object({
19016
19362
  firstAt: number(),
19017
19363
  lastAt: number()
19018
19364
  });
19365
+ /**
19366
+ * How a track was produced. `pipeline` (default / absent) = the spatial
19367
+ * detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
19368
+ * linked sensor/control state change (no positions; carries a snapshot). The
19369
+ * spatial subsystems (tracker association, occupancy count, re-id/embedding,
19370
+ * resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
19371
+ */
19372
+ var TrackSourceSchema = _enum(["pipeline", "sensor"]);
19019
19373
  var TrackSchema = object({
19020
19374
  trackId: string$2(),
19021
19375
  deviceId: number(),
19022
19376
  className: string$2(),
19023
19377
  label: string$2().optional(),
19378
+ /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
19379
+ source: TrackSourceSchema.optional(),
19024
19380
  firstSeen: number(),
19025
19381
  lastSeen: number(),
19026
19382
  /** Frame-rate position history (subject to maxPositionHistory cap). */
@@ -19397,6 +19753,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19397
19753
  eventId: string$2(),
19398
19754
  timestamp: number()
19399
19755
  });
19756
+ /**
19757
+ * Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
19758
+ * `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
19759
+ * caps into per-camera event-kind descriptors.
19760
+ *
19761
+ * The descriptor DATA (color / iconId / labelKey / parentKind / category)
19762
+ * is NOT duplicated here — every entry is derived from the single
19763
+ * `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
19764
+ * ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
19765
+ * control cap means adding one line here (and a taxonomy entry); the anti-
19766
+ * drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
19767
+ * eventful cap is missing.
19768
+ */
19769
+ /** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
19770
+ var LEGACY_ICON = {
19771
+ motion: "motion",
19772
+ audio: "audio",
19773
+ person: "person",
19774
+ vehicle: "vehicle",
19775
+ animal: "animal",
19776
+ package: "package",
19777
+ door: "door",
19778
+ pir: "pir",
19779
+ smoke: "smoke",
19780
+ water: "water",
19781
+ button: "button",
19782
+ generic: "generic",
19783
+ gas: "smoke",
19784
+ vibration: "generic",
19785
+ tamper: "generic",
19786
+ presence: "person",
19787
+ lock: "generic",
19788
+ siren: "generic",
19789
+ switch: "generic",
19790
+ doorbell: "button"
19791
+ };
19792
+ function legacyIcon(iconId) {
19793
+ return LEGACY_ICON[iconId] ?? "generic";
19794
+ }
19795
+ /**
19796
+ * Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
19797
+ * The anti-drift guard cross-checks this against the eventful caps declared
19798
+ * in `packages/types/src/capabilities/*.cap.ts`.
19799
+ */
19800
+ var CAP_TO_KIND = {
19801
+ contact: "contact",
19802
+ motion: "motion-sensor",
19803
+ smoke: "smoke",
19804
+ flood: "flood",
19805
+ gas: "gas",
19806
+ "carbon-monoxide": "carbon-monoxide",
19807
+ vibration: "vibration",
19808
+ tamper: "tamper",
19809
+ presence: "presence",
19810
+ "enum-sensor": "enum-sensor",
19811
+ "event-emitter": "device-event",
19812
+ "lock-control": "lock",
19813
+ switch: "switch",
19814
+ button: "button",
19815
+ doorbell: "doorbell"
19816
+ };
19817
+ function buildDescriptor(capName, kind) {
19818
+ const t = EVENT_TAXONOMY[kind];
19819
+ if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
19820
+ return {
19821
+ ...t,
19822
+ icon: legacyIcon(t.iconId)
19823
+ };
19824
+ }
19825
+ Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
19400
19826
  var CameraPipelineConfigSchema = object({
19401
19827
  engine: PipelineEngineChoiceSchema.optional(),
19402
19828
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19415,13 +19841,11 @@ var PipelineTemplateSchema = object({
19415
19841
  createdAt: string$2(),
19416
19842
  updatedAt: string$2()
19417
19843
  });
19418
- var AgentAddonConfigSchema = object({
19419
- enabled: boolean(),
19844
+ var DeviceStepConfigSchema = object({
19420
19845
  modelId: string$2().optional(),
19421
- settings: record(string$2(), unknown()).readonly()
19846
+ settings: record(string$2(), unknown()).optional()
19422
19847
  });
19423
19848
  var AgentPipelineSettingsSchema = object({
19424
- addonDefaults: record(string$2(), AgentAddonConfigSchema).readonly(),
19425
19849
  maxCameras: number().int().nonnegative().nullable().default(null),
19426
19850
  /** Per-node detection weight (relative share for the quota balancer). */
19427
19851
  detectWeight: number().positive().optional(),
@@ -19445,7 +19869,22 @@ var AgentPipelineSettingsSchema = object({
19445
19869
  * it already uses to reach the hub). Set this only when the auto-detected
19446
19870
  * address is wrong (multi-homed host, NAT, custom interface).
19447
19871
  */
19448
- reachableHost: string$2().optional()
19872
+ reachableHost: string$2().optional(),
19873
+ /**
19874
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19875
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19876
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19877
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19878
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19879
+ * the default model/settings for every camera landing on that accelerator;
19880
+ * a stepId absent ⇒ the step uses that device's format default.
19881
+ */
19882
+ inferenceDevices: record(string$2(), object({
19883
+ enabled: boolean(),
19884
+ weight: number().positive().optional(),
19885
+ maxSessions: number().int().positive().optional(),
19886
+ steps: record(string$2(), DeviceStepConfigSchema).optional()
19887
+ })).optional()
19449
19888
  });
19450
19889
  var CameraPipelineForAgentSchema = object({
19451
19890
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19455,14 +19894,13 @@ var CameraPipelineForAgentSchema = object({
19455
19894
  }).nullable()
19456
19895
  });
19457
19896
  var CameraStepOverridePatchSchema = object({
19458
- enabled: boolean().optional(),
19459
19897
  modelId: string$2().optional(),
19460
19898
  settings: record(string$2(), unknown()).readonly().optional()
19461
19899
  });
19462
19900
  var CameraPipelineSettingsSchema = object({
19463
19901
  pinnedAgentNodeId: string$2().optional(),
19464
19902
  stepToggles: record(string$2(), boolean()).optional(),
19465
- stepOverridesByAgent: record(string$2(), record(string$2(), CameraStepOverridePatchSchema)).optional(),
19903
+ stepOverridesByDevice: record(string$2(), record(string$2(), record(string$2(), CameraStepOverridePatchSchema))).optional(),
19466
19904
  pipelineByAgent: record(string$2(), CameraPipelineForAgentSchema).optional()
19467
19905
  });
19468
19906
  /**
@@ -19676,6 +20114,44 @@ var CameraStatusSchema = object({
19676
20114
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
19677
20115
  fetchedAt: number()
19678
20116
  });
20117
+ var NodeInferenceDeviceSchema = object({
20118
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20119
+ key: string$2(),
20120
+ backend: string$2(),
20121
+ device: string$2(),
20122
+ format: _enum(MODEL_FORMATS),
20123
+ /** Whether the node's live probe reports the device as usable right now. */
20124
+ available: boolean(),
20125
+ /**
20126
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20127
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20128
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20129
+ * not a balanced target). An explicit stored value always wins; a stored-only
20130
+ * (unavailable) key keeps its stored value.
20131
+ */
20132
+ enabled: boolean(),
20133
+ /** Relative balancer weight for the enabled device (default 1). */
20134
+ weight: number(),
20135
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20136
+ maxSessions: number().nullable(),
20137
+ /** Object-detection model the executor defaults to for this deviceKey. */
20138
+ defaultModelId: string$2(),
20139
+ /**
20140
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20141
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20142
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20143
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20144
+ * available per format; this is the stored selection that becomes the
20145
+ * default for EVERY camera landing on this accelerator.
20146
+ */
20147
+ steps: record(string$2(), DeviceStepConfigSchema).optional()
20148
+ });
20149
+ var NodeInferenceDevicesSchema = object({
20150
+ nodeId: string$2(),
20151
+ /** False when the node's platform-probe was unreachable (no live device set). */
20152
+ reachable: boolean(),
20153
+ devices: array(NodeInferenceDeviceSchema).readonly()
20154
+ });
19679
20155
  method(object({
19680
20156
  deviceId: number(),
19681
20157
  agentNodeId: string$2()
@@ -19685,7 +20161,13 @@ method(object({
19685
20161
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
19686
20162
  kind: "mutation",
19687
20163
  auth: "admin"
19688
- }), method(_void(), object({ migrated: number() }), {
20164
+ }), method(object({
20165
+ deviceId: number(),
20166
+ deviceKey: string$2()
20167
+ }), object({ success: literal(true) }), {
20168
+ kind: "mutation",
20169
+ auth: "admin"
20170
+ }), method(object({ deviceId: number() }), object({ deviceKey: string$2().nullable() })), method(_void(), object({ migrated: number() }), {
19689
20171
  kind: "mutation",
19690
20172
  auth: "admin"
19691
20173
  }), method(_void(), array(PipelineAssignmentSchema).readonly()), method(object({ deviceId: number() }), PipelineAssignmentSchema.nullable()), method(_void(), array(AgentLoadSummarySchema).readonly()), method(_void(), GlobalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(object({ nodeId: string$2() }), CapabilityBindingsSchema), method(object({
@@ -19719,13 +20201,7 @@ method(object({
19719
20201
  }))), method(object({ agentNodeId: string$2() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
19720
20202
  nodeId: string$2(),
19721
20203
  settings: AgentPipelineSettingsSchema
19722
- })).readonly()), method(object({
19723
- agentNodeId: string$2(),
19724
- defaults: record(string$2(), AgentAddonConfigSchema)
19725
- }), object({ success: literal(true) }), {
19726
- kind: "mutation",
19727
- auth: "admin"
19728
- }), method(object({ agentNodeId: string$2() }), object({
20204
+ })).readonly()), method(object({ agentNodeId: string$2() }), object({
19729
20205
  success: boolean(),
19730
20206
  removed: boolean()
19731
20207
  }), {
@@ -19757,7 +20233,18 @@ method(object({
19757
20233
  }), object({ success: literal(true) }), {
19758
20234
  kind: "mutation",
19759
20235
  auth: "admin"
19760
- }), method(object({ agentNodeId: string$2() }), object({
20236
+ }), method(object({
20237
+ agentNodeId: string$2(),
20238
+ inferenceDevices: record(string$2(), object({
20239
+ enabled: boolean(),
20240
+ weight: number().positive().optional(),
20241
+ maxSessions: number().int().positive().optional(),
20242
+ steps: record(string$2(), DeviceStepConfigSchema).optional()
20243
+ }))
20244
+ }), object({ success: literal(true) }), {
20245
+ kind: "mutation",
20246
+ auth: "admin"
20247
+ }), method(object({ nodeId: string$2() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string$2() }), object({
19761
20248
  success: literal(true),
19762
20249
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
19763
20250
  effectiveModelId: string$2().nullable(),
@@ -19773,9 +20260,10 @@ method(object({
19773
20260
  }), object({ success: literal(true) }), {
19774
20261
  kind: "mutation",
19775
20262
  auth: "admin"
19776
- }), method(object({ deviceId: number() }), record(string$2(), record(string$2(), CameraStepOverridePatchSchema)).nullable()), method(object({
20263
+ }), method(object({ deviceId: number() }), record(string$2(), record(string$2(), record(string$2(), CameraStepOverridePatchSchema))).nullable()), method(object({
19777
20264
  deviceId: number(),
19778
20265
  agentNodeId: string$2(),
20266
+ deviceKey: string$2(),
19779
20267
  addonId: string$2(),
19780
20268
  patch: CameraStepOverridePatchSchema.nullable()
19781
20269
  }), object({ success: literal(true) }), {
@@ -19812,14 +20300,13 @@ method(object({
19812
20300
  });
19813
20301
  /**
19814
20302
  * server-management — per-NODE singleton capability for a node's ROOT
19815
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
19816
- * agents).
20303
+ * package lifecycle (runtime-updatable node packages).
19817
20304
  *
19818
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
19819
- * on agents) carries the whole software stack in its npm dep tree, so ONE
19820
- * version describes the node. Updates install into
19821
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
19822
- * starter (probation boot + auto-rollback to N-1).
20305
+ * Every node role runs the SAME root package (`@camstack/server`), which
20306
+ * carries the whole software stack in its npm dep tree, so ONE version
20307
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20308
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20309
+ * no auto-rollback).
19823
20310
  *
19824
20311
  * Providers:
19825
20312
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -19927,7 +20414,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
19927
20414
  /** Explicit target version; omitted = latest from the registry. */
19928
20415
  version: string$2().optional() }), ServerUpdateActionResultSchema, {
19929
20416
  kind: "mutation",
19930
- auth: "admin"
20417
+ auth: "admin",
20418
+ timeoutMs: 16 * 6e4
19931
20419
  }), method(_void(), ServerUpdateActionResultSchema, {
19932
20420
  kind: "mutation",
19933
20421
  auth: "admin"
@@ -20971,22 +21459,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
20971
21459
  var RestartAddonResultSchema = unknown();
20972
21460
  var InstallPackageResultSchema = unknown();
20973
21461
  var ReloadPackagesResultSchema = unknown();
20974
- /**
20975
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
20976
- * server restarts so the admin UI can react to the `restartingAt`
20977
- * timestamp (shows reconnect overlay). The transition from
20978
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
20979
- * `system.restart-completed` event after the new process boots.
20980
- *
20981
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
20982
- */
20983
- var UpdateFrameworkPackageResultSchema = object({
20984
- packageName: string$2(),
20985
- fromVersion: string$2(),
20986
- toVersion: string$2(),
20987
- /** Ms-epoch the server scheduled its self-restart. */
20988
- restartingAt: number()
20989
- });
20990
21462
  var BulkUpdateItemStatusSchema = _enum([
20991
21463
  "queued",
20992
21464
  "updating",
@@ -21114,13 +21586,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21114
21586
  }), object({ success: literal(true) }), {
21115
21587
  kind: "mutation",
21116
21588
  auth: "admin"
21117
- }), method(object({
21118
- packageName: string$2().min(1),
21119
- version: string$2().optional(),
21120
- deferRestart: boolean().optional()
21121
- }), UpdateFrameworkPackageResultSchema, {
21122
- kind: "mutation",
21123
- auth: "admin"
21124
21589
  }), method(object({ name: string$2() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string$2() }), RestartAddonResultSchema, {
21125
21590
  kind: "mutation",
21126
21591
  auth: "admin"
@@ -22003,10 +22468,10 @@ var TopologyCategorySchema = object({
22003
22468
  addons: array(TopologyCategoryAddonSchema).readonly()
22004
22469
  });
22005
22470
  /**
22006
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22007
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22008
- * version visibility for the Server management surface. Nullable: offline
22009
- * rows and pre-phase-2 nodes report none.
22471
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22472
+ * root package for every node role) as reported by its `registerNode`
22473
+ * manifest — version visibility for the Server management surface. Nullable:
22474
+ * offline rows and nodes that never reported one.
22010
22475
  */
22011
22476
  var TopologyRootPackageSchema = object({
22012
22477
  name: string$2(),
@@ -22394,17 +22859,28 @@ var PlatformScoreSchema = object({
22394
22859
  format: _enum([
22395
22860
  "onnx",
22396
22861
  "coreml",
22397
- "openvino"
22862
+ "openvino",
22863
+ "tflite"
22398
22864
  ]),
22399
22865
  score: number(),
22400
22866
  reason: string$2(),
22401
22867
  available: boolean()
22402
22868
  });
22869
+ var InferenceDeviceDescriptorSchema = object({
22870
+ key: string$2(),
22871
+ backend: string$2(),
22872
+ device: string$2(),
22873
+ format: ModelFormatSchema,
22874
+ runtime: literal("python"),
22875
+ score: number(),
22876
+ available: boolean()
22877
+ });
22403
22878
  var PlatformCapabilitiesSchema = object({
22404
22879
  hardware: HardwareInfoSchema,
22405
22880
  scores: array(PlatformScoreSchema).readonly(),
22406
22881
  bestScore: PlatformScoreSchema,
22407
- pythonPath: string$2().nullable()
22882
+ pythonPath: string$2().nullable(),
22883
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22408
22884
  });
22409
22885
  var ModelRequirementSchema = object({
22410
22886
  modelId: string$2(),
@@ -23283,12 +23759,6 @@ Object.freeze({
23283
23759
  addonId: null,
23284
23760
  access: "delete"
23285
23761
  },
23286
- "addons.updateFrameworkPackage": {
23287
- capName: "addons",
23288
- capScope: "system",
23289
- addonId: null,
23290
- access: "create"
23291
- },
23292
23762
  "addons.updatePackage": {
23293
23763
  capName: "addons",
23294
23764
  capScope: "system",
@@ -26061,12 +26531,6 @@ Object.freeze({
26061
26531
  addonId: null,
26062
26532
  access: "view"
26063
26533
  },
26064
- "pipelineExecutor.reprobeEngine": {
26065
- capName: "pipeline-executor",
26066
- capScope: "system",
26067
- addonId: null,
26068
- access: "create"
26069
- },
26070
26534
  "pipelineExecutor.runAudioTest": {
26071
26535
  capName: "pipeline-executor",
26072
26536
  capScope: "system",
@@ -26217,6 +26681,12 @@ Object.freeze({
26217
26681
  addonId: null,
26218
26682
  access: "view"
26219
26683
  },
26684
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26685
+ capName: "pipeline-orchestrator",
26686
+ capScope: "system",
26687
+ addonId: null,
26688
+ access: "view"
26689
+ },
26220
26690
  "pipelineOrchestrator.getPipelineAssignment": {
26221
26691
  capName: "pipeline-orchestrator",
26222
26692
  capScope: "system",
@@ -26229,6 +26699,12 @@ Object.freeze({
26229
26699
  addonId: null,
26230
26700
  access: "view"
26231
26701
  },
26702
+ "pipelineOrchestrator.getPipelineDevicePin": {
26703
+ capName: "pipeline-orchestrator",
26704
+ capScope: "system",
26705
+ addonId: null,
26706
+ access: "view"
26707
+ },
26232
26708
  "pipelineOrchestrator.listAgentSettings": {
26233
26709
  capName: "pipeline-orchestrator",
26234
26710
  capScope: "system",
@@ -26271,19 +26747,19 @@ Object.freeze({
26271
26747
  addonId: null,
26272
26748
  access: "create"
26273
26749
  },
26274
- "pipelineOrchestrator.setAgentAddonDefaults": {
26750
+ "pipelineOrchestrator.setAgentCapabilities": {
26275
26751
  capName: "pipeline-orchestrator",
26276
26752
  capScope: "system",
26277
26753
  addonId: null,
26278
26754
  access: "create"
26279
26755
  },
26280
- "pipelineOrchestrator.setAgentCapabilities": {
26756
+ "pipelineOrchestrator.setAgentDetectWeight": {
26281
26757
  capName: "pipeline-orchestrator",
26282
26758
  capScope: "system",
26283
26759
  addonId: null,
26284
26760
  access: "create"
26285
26761
  },
26286
- "pipelineOrchestrator.setAgentDetectWeight": {
26762
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26287
26763
  capName: "pipeline-orchestrator",
26288
26764
  capScope: "system",
26289
26765
  addonId: null,
@@ -26325,6 +26801,12 @@ Object.freeze({
26325
26801
  addonId: null,
26326
26802
  access: "create"
26327
26803
  },
26804
+ "pipelineOrchestrator.setPipelineDevicePin": {
26805
+ capName: "pipeline-orchestrator",
26806
+ capScope: "system",
26807
+ addonId: null,
26808
+ access: "create"
26809
+ },
26328
26810
  "pipelineOrchestrator.unassignAudio": {
26329
26811
  capName: "pipeline-orchestrator",
26330
26812
  capScope: "system",
@@ -27877,32 +28359,6 @@ Object.freeze({
27877
28359
  "network-access": "ingress",
27878
28360
  "smtp-provider": "email"
27879
28361
  });
27880
- var frameworkSwapPackageSchema = object({
27881
- name: string$2(),
27882
- stagedPath: string$2(),
27883
- backupPath: string$2(),
27884
- toVersion: string$2(),
27885
- fromVersion: string$2().nullable()
27886
- });
27887
- object({
27888
- jobId: string$2(),
27889
- taskId: string$2(),
27890
- packages: array(frameworkSwapPackageSchema),
27891
- requestedAtMs: number(),
27892
- schemaVersion: literal(1)
27893
- });
27894
- object({
27895
- jobId: string$2(),
27896
- taskId: string$2(),
27897
- backups: array(object({
27898
- name: string$2(),
27899
- backupPath: string$2(),
27900
- livePath: string$2()
27901
- })),
27902
- appliedAtMs: number(),
27903
- bootAttempts: number(),
27904
- schemaVersion: literal(1)
27905
- });
27906
28362
  //#endregion
27907
28363
  //#region ../../node_modules/@matter/general/dist/esm/net/tcp/TcpConnection.js
27908
28364
  /**