@camstack/types 1.2.307 → 1.2.309

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 (34) hide show
  1. package/dist/capabilities/custom-model-registry.cap.d.ts +38 -4
  2. package/dist/capabilities/device-manager.cap.d.ts +8 -8
  3. package/dist/capabilities/hub-address.d.ts +76 -0
  4. package/dist/capabilities/index.d.ts +4 -3
  5. package/dist/capabilities/local-network.cap.d.ts +93 -0
  6. package/dist/capabilities/model-convert.cap.d.ts +19 -2
  7. package/dist/capabilities/model-distributor.cap.d.ts +38 -4
  8. package/dist/capabilities/pipeline-executor.cap.d.ts +124 -10
  9. package/dist/capabilities/pipeline-runner.cap.d.ts +13 -0
  10. package/dist/catalogs/frigate-plus-classmap.d.ts +10 -7
  11. package/dist/catalogs/index.d.ts +1 -1
  12. package/dist/catalogs/root-model-supply.d.ts +202 -0
  13. package/dist/client.js +51 -49
  14. package/dist/client.mjs +51 -49
  15. package/dist/device/location-icon.d.ts +4 -4
  16. package/dist/device/site-zone.d.ts +2 -2
  17. package/dist/ffmpeg/pinned-spawn.d.ts +1 -1
  18. package/dist/generated/addon-api.d.ts +14 -0
  19. package/dist/generated/method-access-map.d.ts +1 -1
  20. package/dist/generated/system-proxy.d.ts +1 -1
  21. package/dist/index.d.ts +3 -1
  22. package/dist/index.js +1002 -512
  23. package/dist/index.mjs +970 -500
  24. package/dist/interfaces/event-bus.d.ts +12 -6
  25. package/dist/interfaces/pipeline-executor-capability.d.ts +6 -1
  26. package/dist/node.js +1 -1
  27. package/dist/node.mjs +1 -1
  28. package/dist/pipeline/removed-model-ids.d.ts +20 -0
  29. package/dist/pipeline/root-face-crop.d.ts +31 -0
  30. package/dist/types/detection.d.ts +9 -0
  31. package/dist/types/models.d.ts +69 -8
  32. package/dist/types/pipeline-step.d.ts +6 -0
  33. package/package.json +1 -1
  34. package/dist/catalogs/classifier-fill.d.ts +0 -104
package/dist/index.js CHANGED
@@ -5346,424 +5346,40 @@ function resolveClipSearchMinScore(meta, request) {
5346
5346
  return Math.min(1, Math.round(meta.searchMinScore * factor * 1e3) / 1e3);
5347
5347
  }
5348
5348
  //#endregion
5349
- //#region src/catalogs/coco-classmap.ts
5350
- var COCO_80_LABELS = [
5351
- {
5352
- id: "person",
5353
- name: "Person"
5354
- },
5355
- {
5356
- id: "bicycle",
5357
- name: "Bicycle"
5358
- },
5359
- {
5360
- id: "car",
5361
- name: "Car"
5362
- },
5363
- {
5364
- id: "motorcycle",
5365
- name: "Motorcycle"
5366
- },
5367
- {
5368
- id: "airplane",
5369
- name: "Airplane"
5370
- },
5371
- {
5372
- id: "bus",
5373
- name: "Bus"
5374
- },
5375
- {
5376
- id: "train",
5377
- name: "Train"
5378
- },
5379
- {
5380
- id: "truck",
5381
- name: "Truck"
5382
- },
5383
- {
5384
- id: "boat",
5385
- name: "Boat"
5386
- },
5387
- {
5388
- id: "traffic light",
5389
- name: "Traffic Light"
5390
- },
5391
- {
5392
- id: "fire hydrant",
5393
- name: "Fire Hydrant"
5394
- },
5395
- {
5396
- id: "stop sign",
5397
- name: "Stop Sign"
5398
- },
5399
- {
5400
- id: "parking meter",
5401
- name: "Parking Meter"
5402
- },
5403
- {
5404
- id: "bench",
5405
- name: "Bench"
5406
- },
5407
- {
5408
- id: "bird",
5409
- name: "Bird"
5410
- },
5411
- {
5412
- id: "cat",
5413
- name: "Cat"
5414
- },
5415
- {
5416
- id: "dog",
5417
- name: "Dog"
5418
- },
5419
- {
5420
- id: "horse",
5421
- name: "Horse"
5422
- },
5423
- {
5424
- id: "sheep",
5425
- name: "Sheep"
5426
- },
5427
- {
5428
- id: "cow",
5429
- name: "Cow"
5430
- },
5431
- {
5432
- id: "elephant",
5433
- name: "Elephant"
5434
- },
5435
- {
5436
- id: "bear",
5437
- name: "Bear"
5438
- },
5439
- {
5440
- id: "zebra",
5441
- name: "Zebra"
5442
- },
5443
- {
5444
- id: "giraffe",
5445
- name: "Giraffe"
5446
- },
5447
- {
5448
- id: "backpack",
5449
- name: "Backpack"
5450
- },
5451
- {
5452
- id: "umbrella",
5453
- name: "Umbrella"
5454
- },
5455
- {
5456
- id: "handbag",
5457
- name: "Handbag"
5458
- },
5459
- {
5460
- id: "tie",
5461
- name: "Tie"
5462
- },
5463
- {
5464
- id: "suitcase",
5465
- name: "Suitcase"
5466
- },
5467
- {
5468
- id: "frisbee",
5469
- name: "Frisbee"
5470
- },
5471
- {
5472
- id: "skis",
5473
- name: "Skis"
5474
- },
5475
- {
5476
- id: "snowboard",
5477
- name: "Snowboard"
5478
- },
5479
- {
5480
- id: "sports ball",
5481
- name: "Sports Ball"
5482
- },
5483
- {
5484
- id: "kite",
5485
- name: "Kite"
5486
- },
5487
- {
5488
- id: "baseball bat",
5489
- name: "Baseball Bat"
5490
- },
5491
- {
5492
- id: "baseball glove",
5493
- name: "Baseball Glove"
5494
- },
5495
- {
5496
- id: "skateboard",
5497
- name: "Skateboard"
5498
- },
5499
- {
5500
- id: "surfboard",
5501
- name: "Surfboard"
5502
- },
5503
- {
5504
- id: "tennis racket",
5505
- name: "Tennis Racket"
5506
- },
5507
- {
5508
- id: "bottle",
5509
- name: "Bottle"
5510
- },
5511
- {
5512
- id: "wine glass",
5513
- name: "Wine Glass"
5514
- },
5515
- {
5516
- id: "cup",
5517
- name: "Cup"
5518
- },
5519
- {
5520
- id: "fork",
5521
- name: "Fork"
5522
- },
5523
- {
5524
- id: "knife",
5525
- name: "Knife"
5526
- },
5527
- {
5528
- id: "spoon",
5529
- name: "Spoon"
5530
- },
5531
- {
5532
- id: "bowl",
5533
- name: "Bowl"
5534
- },
5535
- {
5536
- id: "banana",
5537
- name: "Banana"
5538
- },
5539
- {
5540
- id: "apple",
5541
- name: "Apple"
5542
- },
5543
- {
5544
- id: "sandwich",
5545
- name: "Sandwich"
5546
- },
5547
- {
5548
- id: "orange",
5549
- name: "Orange"
5550
- },
5551
- {
5552
- id: "broccoli",
5553
- name: "Broccoli"
5554
- },
5555
- {
5556
- id: "carrot",
5557
- name: "Carrot"
5558
- },
5559
- {
5560
- id: "hot dog",
5561
- name: "Hot Dog"
5562
- },
5563
- {
5564
- id: "pizza",
5565
- name: "Pizza"
5566
- },
5567
- {
5568
- id: "donut",
5569
- name: "Donut"
5570
- },
5571
- {
5572
- id: "cake",
5573
- name: "Cake"
5574
- },
5575
- {
5576
- id: "chair",
5577
- name: "Chair"
5578
- },
5579
- {
5580
- id: "couch",
5581
- name: "Couch"
5582
- },
5583
- {
5584
- id: "potted plant",
5585
- name: "Potted Plant"
5586
- },
5587
- {
5588
- id: "bed",
5589
- name: "Bed"
5590
- },
5591
- {
5592
- id: "dining table",
5593
- name: "Dining Table"
5594
- },
5595
- {
5596
- id: "toilet",
5597
- name: "Toilet"
5598
- },
5599
- {
5600
- id: "tv",
5601
- name: "TV"
5602
- },
5603
- {
5604
- id: "laptop",
5605
- name: "Laptop"
5606
- },
5607
- {
5608
- id: "mouse",
5609
- name: "Mouse"
5610
- },
5611
- {
5612
- id: "remote",
5613
- name: "Remote"
5614
- },
5615
- {
5616
- id: "keyboard",
5617
- name: "Keyboard"
5618
- },
5619
- {
5620
- id: "cell phone",
5621
- name: "Cell Phone"
5622
- },
5623
- {
5624
- id: "microwave",
5625
- name: "Microwave"
5626
- },
5627
- {
5628
- id: "oven",
5629
- name: "Oven"
5630
- },
5631
- {
5632
- id: "toaster",
5633
- name: "Toaster"
5634
- },
5635
- {
5636
- id: "sink",
5637
- name: "Sink"
5638
- },
5639
- {
5640
- id: "refrigerator",
5641
- name: "Refrigerator"
5642
- },
5643
- {
5644
- id: "book",
5645
- name: "Book"
5646
- },
5647
- {
5648
- id: "clock",
5649
- name: "Clock"
5650
- },
5651
- {
5652
- id: "vase",
5653
- name: "Vase"
5654
- },
5655
- {
5656
- id: "scissors",
5657
- name: "Scissors"
5658
- },
5659
- {
5660
- id: "teddy bear",
5661
- name: "Teddy Bear"
5662
- },
5663
- {
5664
- id: "hair drier",
5665
- name: "Hair Drier"
5666
- },
5667
- {
5668
- id: "toothbrush",
5669
- name: "Toothbrush"
5670
- }
5671
- ];
5672
- var MACRO_LABELS = [
5673
- {
5674
- id: "person",
5675
- name: "Person"
5676
- },
5677
- {
5678
- id: "vehicle",
5679
- name: "Vehicle"
5680
- },
5681
- {
5682
- id: "animal",
5683
- name: "Animal"
5684
- },
5685
- {
5686
- id: "package",
5687
- name: "Package"
5688
- }
5689
- ];
5690
- /**
5691
- * The class names a per-class COUNT can ever be keyed on — the macro ids, and
5692
- * only those.
5693
- *
5694
- * `preserveOriginal: false` below is the whole reason this set exists: the
5695
- * executor maps each raw COCO label onto its macro and DROPS everything else,
5696
- * so a tracked detection's `className` is always one of {@link MACRO_LABELS}.
5697
- * Any surface that indexes counts by class name — the ZoneAnalytics occupancy
5698
- * snapshot's `byClass`, and therefore every occupancy rule — can match nothing
5699
- * else. Derived from the catalog, never hand-listed, so a new macro joins it by
5700
- * being declared once.
5701
- *
5702
- * Cost of not having it, 2026-08-12: the notification rule editor offered the
5703
- * full taxonomy for an occupancy class (occupancy is the one condition that
5704
- * does not go through the engine's macro-expanding `expandClassSelector`), two
5705
- * live rules were authored on `car`, and both counters read 0 forever.
5706
- */
5707
- var DETECTION_MACRO_CLASSES = new Set(MACRO_LABELS.map((l) => l.id));
5708
- /** True when `className` is a macro the detector can actually emit (and hence a
5709
- * class a count can be keyed on) — see {@link DETECTION_MACRO_CLASSES}. */
5710
- function isDetectionMacroClass(className) {
5711
- return DETECTION_MACRO_CLASSES.has(className.trim().toLowerCase());
5712
- }
5713
- var COCO_TO_MACRO = {
5714
- mapping: {
5715
- person: "person",
5716
- bicycle: "vehicle",
5717
- car: "vehicle",
5718
- motorcycle: "vehicle",
5719
- airplane: "vehicle",
5720
- bus: "vehicle",
5721
- train: "vehicle",
5722
- truck: "vehicle",
5723
- boat: "vehicle",
5724
- bird: "animal",
5725
- cat: "animal",
5726
- dog: "animal",
5727
- horse: "animal",
5728
- sheep: "animal",
5729
- cow: "animal",
5730
- elephant: "animal",
5731
- bear: "animal",
5732
- zebra: "animal",
5733
- giraffe: "animal",
5734
- suitcase: "package",
5735
- backpack: "package",
5736
- handbag: "package"
5737
- },
5738
- preserveOriginal: false
5739
- };
5740
- //#endregion
5741
- //#region src/catalogs/classifier-fill.ts
5742
- /** Steps a root detector may declare it fills. */
5743
- var FILLABLE_STEP_IDS = [
5349
+ //#region src/catalogs/root-model-supply.ts
5350
+ /** Steps whose effect a root label can BE. */
5351
+ var LABEL_SUPPLY_STEP_IDS = [
5744
5352
  "animal-classifier",
5745
5353
  "vehicle-classifier",
5746
5354
  "package-detection"
5747
5355
  ];
5748
- /** Narrow a step id to a fillable one — type guard, not a cast. */
5749
- function isFillableStepId(value) {
5750
- return FILLABLE_STEP_IDS.some((id) => id === value);
5356
+ /** Steps whose box a root detection can BE. */
5357
+ var CROP_SUPPLY_STEP_IDS = ["plate-detection", "face-detection"];
5358
+ /** Every step a root model can supply. */
5359
+ var ROOT_SUPPLIABLE_STEP_IDS = [...LABEL_SUPPLY_STEP_IDS, ...CROP_SUPPLY_STEP_IDS];
5360
+ /** Narrow a step id to a suppliable one — type guard, not a cast. */
5361
+ function isRootSuppliableStepId(value) {
5362
+ return ROOT_SUPPLIABLE_STEP_IDS.some((id) => id === value);
5363
+ }
5364
+ /** Narrow a step id to a label-kind one. */
5365
+ function isLabelSupplyStepId(value) {
5366
+ return LABEL_SUPPLY_STEP_IDS.some((id) => id === value);
5751
5367
  }
5752
5368
  /**
5753
- * The EFFECT vocabulary of each fillable step: exactly the strings the step
5369
+ * The EFFECT vocabulary of each label-kind step: exactly the strings the step
5754
5370
  * itself emits, in its own spelling. A linked label is one of these and nothing
5755
5371
  * else, so a tier-1 value means the same thing whichever writer produced it.
5756
5372
  *
5757
5373
  * - `animal-classifier`: the PRIMARY model's `-labels.json` (Open Images V7,
5758
5374
  * 8 classes) — also the species allow-list the step offers.
5759
- * - `vehicle-classifier`: `vehicle-type-v1-labels.json`, capitalised as the
5760
- * model emits them (the classifier writes `winner.class` verbatim).
5375
+ * - `vehicle-classifier`: the classifier's labels, capitalised as it emits them
5376
+ * (it writes `winner.class` verbatim).
5761
5377
  * - `package-detection`: its one output class.
5762
5378
  *
5763
- * `scripts/check-label-link-vocabulary.ts` fails the build if a model entry's
5379
+ * `scripts/check-label-link-vocabulary.ts` fails the build if a declared
5764
5380
  * `labelToEffect` names anything outside this table.
5765
5381
  */
5766
- var FILLABLE_STEP_VOCABULARIES = {
5382
+ var LABEL_SUPPLY_VOCABULARIES = {
5767
5383
  "animal-classifier": [
5768
5384
  "bird",
5769
5385
  "cat",
@@ -5786,8 +5402,8 @@ var FILLABLE_STEP_VOCABULARIES = {
5786
5402
  ],
5787
5403
  "package-detection": ["package"]
5788
5404
  };
5789
- /** The macro a detection must carry for the step to apply to it. */
5790
- var FILLABLE_STEP_MACRO = {
5405
+ /** The macro a detection must carry for a label-kind step to apply to it. */
5406
+ var LABEL_SUPPLY_MACRO = {
5791
5407
  "animal-classifier": "animal",
5792
5408
  "vehicle-classifier": "vehicle",
5793
5409
  "package-detection": "package"
@@ -5804,12 +5420,46 @@ var EFFECT_ALIASES = {
5804
5420
  },
5805
5421
  "package-detection": {}
5806
5422
  };
5807
- /** The policy values of a step's `labelLink` setting. */
5808
- var LABEL_LINK_POLICIES = ["run", "skip-when-filled"];
5809
- /** Absent setting ⇒ this. It changes nothing unless the root model declares a fill. */
5810
- var DEFAULT_LABEL_LINK_POLICY = "skip-when-filled";
5811
- /** The step-settings key the policy is stored under (DeviceStepConfig.settings). */
5812
- var LABEL_LINK_SETTING_KEY = "labelLink";
5423
+ var CROP_SUPPLY_SOURCES = {
5424
+ "plate-detection": {
5425
+ rootLabels: ["license_plate"],
5426
+ parentMacro: "vehicle",
5427
+ childClass: "plate",
5428
+ servedChildSteps: ["plate-ocr"],
5429
+ use: "as-output"
5430
+ },
5431
+ "face-detection": {
5432
+ rootLabels: ["face"],
5433
+ parentMacro: "person",
5434
+ childClass: "face",
5435
+ servedChildSteps: ["face-embedding"],
5436
+ use: "refine",
5437
+ minRootInputPx: 640
5438
+ }
5439
+ };
5440
+ /**
5441
+ * Whether an operator intends a step to take the root's output when the
5442
+ * root declares it — the default of the `useRootModel` flag. The label kinds
5443
+ * default ON: the detector's answer is the cheaper one and the classifier
5444
+ * keeps its model for the day the root changes. The crop kinds default OFF: a
5445
+ * root plate box has an uncalibrated OCR margin, and root-face refinement has
5446
+ * not run on live traffic yet.
5447
+ */
5448
+ var USE_ROOT_MODEL_DEFAULTS = {
5449
+ "animal-classifier": true,
5450
+ "vehicle-classifier": true,
5451
+ "package-detection": true,
5452
+ "plate-detection": false,
5453
+ "face-detection": false
5454
+ };
5455
+ /** The step-settings key the flag is stored under (DeviceStepConfig.settings, camera overrides). */
5456
+ var USE_ROOT_MODEL_SETTING_KEY = "useRootModel";
5457
+ /**
5458
+ * The retired D715 policy key. A `skip-when-filled` / `run` value still
5459
+ * stored under it reads as the flag (`true` / `false`) when no flag is stored
5460
+ * — the normal read path, not a migration.
5461
+ */
5462
+ var RETIRED_LABEL_LINK_KEY = "labelLink";
5813
5463
  /** `ScoredLabel.stepId` prefix of a label the detector wrote for a step. */
5814
5464
  var LINKED_LABEL_STEP_PREFIX = "detector-link:";
5815
5465
  /** `detector-link:<stepId>` — the attribution of a linked label. */
@@ -5821,91 +5471,175 @@ function linkedStepOf(attributionStepId) {
5821
5471
  if (attributionStepId === void 0) return void 0;
5822
5472
  if (!attributionStepId.startsWith("detector-link:")) return void 0;
5823
5473
  const stepId = attributionStepId.slice(14);
5824
- return isFillableStepId(stepId) ? stepId : void 0;
5825
- }
5826
- /**
5827
- * A labelmap is COCO when it carries at least half of the COCO-80 classes. A
5828
- * COCO detector NEVER fills a step (operator decision, D715): its `dog` / `car`
5829
- * is the generic class the classifier exists to refine, and its six animal
5830
- * classes would otherwise read as "fills animal-classifier 6/8". Frigate+
5831
- * shares about a dozen COCO names; a COCO-80 or COCO-91 labelmap carries ~80.
5832
- */
5833
- function isCocoLabelmap(labels) {
5834
- const present = new Set(labels);
5835
- return COCO_80_LABELS.filter((l) => present.has(l.id)).length * 2 >= COCO_80_LABELS.length;
5474
+ return isLabelSupplyStepId(stepId) ? stepId : void 0;
5836
5475
  }
5837
5476
  function effectFor(stepId, label) {
5838
5477
  const alias = EFFECT_ALIASES[stepId][label];
5839
5478
  if (alias !== void 0) return alias;
5840
5479
  const folded = label.toLowerCase();
5841
- return FILLABLE_STEP_VOCABULARIES[stepId].find((v) => v.toLowerCase() === folded);
5480
+ return LABEL_SUPPLY_VOCABULARIES[stepId].find((v) => v.toLowerCase() === folded);
5842
5481
  }
5843
5482
  /**
5844
- * Which steps a root detector fills, from its labelmap and classMap. A label
5845
- * counts for a step only when the model's classMap sends it to that step's
5846
- * macro AND it names a vocabulary entry. A step none of the labels reach is
5847
- * not declared; a COCO labelmap declares nothing.
5483
+ * Which steps a root detector can supply, from its labelmap and classMap.
5484
+ *
5485
+ * - label kind: a label counts for a step only when the classMap sends it to
5486
+ * that step's macro AND it names a vocabulary entry. Every root is judged
5487
+ * the same way — a COCO model supplies the animal classifier with the six
5488
+ * species COCO names, exactly as a Frigate+ model supplies seven.
5489
+ * - crop kind: the labelmap carries one of the step's root labels. Those
5490
+ * labels are deliberately left out of the classMap, so they never make a
5491
+ * track of their own.
5492
+ *
5493
+ * No classMap ⇒ no label supply (nothing says which macro a label lives under).
5848
5494
  */
5849
- function deriveClassifierFills(labels, classMap) {
5850
- if (classMap === void 0 || isCocoLabelmap(labels)) return [];
5851
- const fills = [];
5852
- for (const stepId of FILLABLE_STEP_IDS) {
5495
+ function deriveRootSupplies(labels, classMap) {
5496
+ const supplies = [];
5497
+ if (classMap !== void 0) for (const stepId of LABEL_SUPPLY_STEP_IDS) {
5853
5498
  const labelToEffect = {};
5854
5499
  for (const label of labels) {
5855
- if (classMap.mapping[label] !== FILLABLE_STEP_MACRO[stepId]) continue;
5500
+ if (classMap.mapping[label] !== LABEL_SUPPLY_MACRO[stepId]) continue;
5856
5501
  const effect = effectFor(stepId, label);
5857
5502
  if (effect !== void 0) labelToEffect[label] = effect;
5858
5503
  }
5859
5504
  const covered = new Set(Object.values(labelToEffect));
5860
5505
  if (covered.size === 0) continue;
5861
- const uncovered = FILLABLE_STEP_VOCABULARIES[stepId].filter((v) => !covered.has(v));
5862
- fills.push({
5506
+ const uncovered = LABEL_SUPPLY_VOCABULARIES[stepId].filter((v) => !covered.has(v));
5507
+ supplies.push({
5508
+ kind: "label",
5863
5509
  stepId,
5864
5510
  labelToEffect,
5865
5511
  uncovered
5866
5512
  });
5867
5513
  }
5868
- return fills;
5869
- }
5870
- /** The fill a model declares for one step, if any. */
5871
- function fillFor(entry, stepId) {
5872
- return entry?.fillsClassifierEffects?.find((f) => f.stepId === stepId);
5873
- }
5874
- /** Read the `labelLink` policy off a step's settings bag; anything else ⇒ the default. */
5875
- function readLabelLinkPolicy(settings) {
5876
- const raw = settings?.[LABEL_LINK_SETTING_KEY];
5877
- return LABEL_LINK_POLICIES.find((p) => p === raw) ?? "skip-when-filled";
5878
- }
5879
- /**
5880
- * Decide the writer of one filled effect for one camera.
5881
- *
5882
- * - The step is not running (disabled, or not in the camera's tree): the
5883
- * detector is the only writer — authoritative, nothing to skip.
5884
- * - The step runs, the policy is `skip-when-filled` and every coverage gap is
5885
- * switched off in `enabledClasses`: the detector is authoritative and the
5886
- * step is skipped.
5887
- * - Otherwise the step runs and is the writer; the linked label is a score-0
5888
- * fallback.
5889
- */
5890
- function resolveLabelLink(fill, step) {
5891
- const policy = readLabelLinkPolicy(step?.settings);
5892
- const rawEnabled = step?.settings?.["enabledClasses"];
5893
- const allowList = Array.isArray(rawEnabled) && rawEnabled.length > 0 ? rawEnabled.filter((v) => typeof v === "string") : null;
5894
- const openGaps = fill.uncovered.filter((g) => allowList === null || allowList.includes(g));
5895
- if (step === void 0 || !step.enabled) return {
5896
- authoritative: true,
5897
- skip: false,
5898
- policy,
5899
- openGaps
5900
- };
5901
- const skip = policy === "skip-when-filled" && openGaps.length === 0;
5514
+ const present = new Set(labels);
5515
+ for (const stepId of CROP_SUPPLY_STEP_IDS) {
5516
+ const source = CROP_SUPPLY_SOURCES[stepId];
5517
+ const rootLabels = source.rootLabels.filter((l) => present.has(l));
5518
+ if (rootLabels.length === 0) continue;
5519
+ supplies.push({
5520
+ kind: "crop",
5521
+ stepId,
5522
+ rootLabels,
5523
+ parentMacro: source.parentMacro,
5524
+ childClass: source.childClass
5525
+ });
5526
+ }
5527
+ return supplies;
5528
+ }
5529
+ /**
5530
+ * The supplies a root model declares. A row registered with a declaration
5531
+ * carries it (`suppliesSteps`, computed at import from the model's own
5532
+ * labelmap); a row without one — a built-in entry, or a custom row registered
5533
+ * before the field existed — is derived here, on read, from the same inputs.
5534
+ */
5535
+ function rootSuppliesOf(entry, stepDefaults) {
5536
+ const declared = entry?.suppliesSteps ?? deriveRootSupplies(entry !== void 0 && entry.labels.length > 0 ? entry.labels.map((l) => l.id) : stepDefaults.labels, entry?.classMap ?? stepDefaults.classMap);
5537
+ const inputPx = entry !== void 0 ? Math.min(entry.inputSize.width, entry.inputSize.height) : void 0;
5538
+ if (inputPx === void 0) return declared;
5539
+ return declared.map((s) => s.kind === "crop" ? {
5540
+ ...s,
5541
+ rootInputPx: inputPx
5542
+ } : s);
5543
+ }
5544
+ /** The supply a root declares for one step, if any. */
5545
+ function supplyFor(supplies, stepId) {
5546
+ return supplies?.find((s) => s.stepId === stepId);
5547
+ }
5548
+ /**
5549
+ * Read the `useRootModel` flag off a step's settings bag. Absent ⇒ the
5550
+ * retired `labelLink` value if one is stored, else the step's default.
5551
+ */
5552
+ function readUseRootModel(stepId, settings) {
5553
+ const raw = settings?.[USE_ROOT_MODEL_SETTING_KEY];
5554
+ if (typeof raw === "boolean") return raw;
5555
+ const retired = settings?.[RETIRED_LABEL_LINK_KEY];
5556
+ if (retired === "skip-when-filled") return true;
5557
+ if (retired === "run") return false;
5558
+ return USE_ROOT_MODEL_DEFAULTS[stepId];
5559
+ }
5560
+ /** Why a DECLARED supply is still not usable, or `undefined` when it is. */
5561
+ function supplyBlocker(supply) {
5562
+ if (supply.kind !== "crop") return void 0;
5563
+ const min = CROP_SUPPLY_SOURCES[supply.stepId].minRootInputPx;
5564
+ if (min === void 0) return void 0;
5565
+ return supply.rootInputPx !== void 0 && supply.rootInputPx >= min ? void 0 : "root-input-too-small";
5566
+ }
5567
+ /**
5568
+ * THE decision. Effective = the operator intends it AND the current root
5569
+ * declares it. It never looks at, changes or clears the step's `modelId`: a
5570
+ * root that cannot supply the step leaves the step running its own model, and
5571
+ * switching back to a root that can re-activates the supply by itself.
5572
+ */
5573
+ function resolveRootSupply(stepId, settings, rootSupplies) {
5574
+ const supply = supplyFor(rootSupplies, stepId);
5575
+ const intent = readUseRootModel(stepId, settings);
5576
+ const blocker = supply === void 0 ? "root-does-not-declare" : supplyBlocker(supply);
5902
5577
  return {
5903
- authoritative: skip,
5904
- skip,
5905
- policy,
5906
- openGaps
5578
+ stepId,
5579
+ supply,
5580
+ intent,
5581
+ effective: intent && blocker === void 0,
5582
+ inactive: intent && blocker !== void 0,
5583
+ ...intent && blocker !== void 0 ? { inactiveReason: blocker } : {}
5907
5584
  };
5908
5585
  }
5586
+ /**
5587
+ * The fine label a supplied root class becomes for a step whose supply is
5588
+ * effective, or `undefined` when the step's `enabledClasses` switched it off —
5589
+ * the detection then stays at its macro (`animal`). Empty / absent allow-list
5590
+ * = every class.
5591
+ */
5592
+ function allowedSuppliedEffect(effect, settings) {
5593
+ const raw = settings?.["enabledClasses"];
5594
+ if (!Array.isArray(raw) || raw.length === 0) return true;
5595
+ return raw.some((v) => v === effect);
5596
+ }
5597
+ /** The child steps of a crop-kind step that still run on the root's box. */
5598
+ function rootSupplyServes(stepId) {
5599
+ return CROP_SUPPLY_SOURCES[stepId].servedChildSteps;
5600
+ }
5601
+ /** Minimum fraction of a child box's area that must lie inside its parent. */
5602
+ var ROOT_CHILD_CONTAINMENT_MIN = .9;
5603
+ /**
5604
+ * The parent a root child box belongs to: among `parents`, the SMALLEST whose
5605
+ * box holds at least {@link ROOT_CHILD_CONTAINMENT_MIN} of the child's area
5606
+ * (a plate inside the car, not inside the bus behind it). `-1` when none does
5607
+ * — the box then belongs to nobody and makes nothing.
5608
+ */
5609
+ function containingParentIndex(child, parents) {
5610
+ const childArea = child.w * child.h;
5611
+ if (!(childArea > 0)) return -1;
5612
+ let best = -1;
5613
+ let bestArea = Number.POSITIVE_INFINITY;
5614
+ parents.forEach((p, i) => {
5615
+ if (Math.max(0, Math.min(child.x + child.w, p.x + p.w) - Math.max(child.x, p.x)) * Math.max(0, Math.min(child.y + child.h, p.y + p.h) - Math.max(child.y, p.y)) / childArea < .9) return;
5616
+ const area = p.w * p.h;
5617
+ if (area < bestArea) {
5618
+ best = i;
5619
+ bestArea = area;
5620
+ }
5621
+ });
5622
+ return best;
5623
+ }
5624
+ var SUPPLY_NOUN = {
5625
+ "animal-classifier": "animals",
5626
+ "vehicle-classifier": "vehicles",
5627
+ "package-detection": "packages",
5628
+ "plate-detection": "plates",
5629
+ "face-detection": "faces"
5630
+ };
5631
+ /** One short phrase per supply — `animals 6/8`, `plates`. */
5632
+ function describeRootSupply(supply) {
5633
+ const noun = SUPPLY_NOUN[supply.stepId];
5634
+ if (supply.kind === "crop") return noun;
5635
+ const total = LABEL_SUPPLY_VOCABULARIES[supply.stepId].length;
5636
+ if (total <= 1) return noun;
5637
+ return `${noun} ${String(total - supply.uncovered.length)}/${String(total)}`;
5638
+ }
5639
+ /** `animals 6/8 · vehicles 5/8 · plates · faces` — empty string for none. */
5640
+ function describeRootSupplies(supplies) {
5641
+ return (supplies ?? []).map(describeRootSupply).join(" · ");
5642
+ }
5909
5643
  //#endregion
5910
5644
  //#region src/types/models.ts
5911
5645
  var MODEL_FORMATS = [
@@ -6062,12 +5796,35 @@ var ModelLicenseRecordSchema = zod.z.object({
6062
5796
  * `camstack/docs` → `/docs/detection/models`.
6063
5797
  */
6064
5798
  var ModelLicenseSchema = zod.z.preprocess((value) => typeof value === "string" ? { weights: value } : value, ModelLicenseRecordSchema);
6065
- /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
6066
- var FillsClassifierEffectSchema = zod.z.object({
6067
- stepId: zod.z.enum(FILLABLE_STEP_IDS),
5799
+ /**
5800
+ * One step a ROOT detector can supply from its own output (D730) — see
5801
+ * `ModelCatalogEntry.suppliesSteps`.
5802
+ *
5803
+ * - `label`: the root's raw class IS the step's answer. `labelToEffect` maps
5804
+ * the root's label to the step's vocabulary; `uncovered` is the vocabulary
5805
+ * the root cannot produce (shown as unavailable, never a blocker).
5806
+ * - `crop`: the root draws the box the step would have found (`license_plate`
5807
+ * for plate-detection, `face` for face-detection). The box becomes a detail
5808
+ * child of the `parentMacro` detection that contains it — never a track.
5809
+ */
5810
+ var RootStepSupplySchema = zod.z.discriminatedUnion("kind", [zod.z.object({
5811
+ kind: zod.z.literal("label"),
5812
+ stepId: zod.z.enum(LABEL_SUPPLY_STEP_IDS),
6068
5813
  labelToEffect: zod.z.record(zod.z.string(), zod.z.string()),
6069
5814
  uncovered: zod.z.array(zod.z.string()).readonly()
6070
- });
5815
+ }), zod.z.object({
5816
+ kind: zod.z.literal("crop"),
5817
+ stepId: zod.z.enum(CROP_SUPPLY_STEP_IDS),
5818
+ rootLabels: zod.z.array(zod.z.string()).readonly(),
5819
+ parentMacro: zod.z.enum(["vehicle", "person"]),
5820
+ childClass: zod.z.enum(["plate", "face"]),
5821
+ /**
5822
+ * The root's smaller input side, stamped on read by `rootSuppliesOf` from
5823
+ * the model entry — what a step's `minRootInputPx` gate judges. Never
5824
+ * stored by an import.
5825
+ */
5826
+ rootInputPx: zod.z.number().int().positive().optional()
5827
+ })]);
6071
5828
  var ModelCatalogEntrySchema = zod.z.object({
6072
5829
  id: zod.z.string(),
6073
5830
  name: zod.z.string(),
@@ -6194,15 +5951,15 @@ var ModelCatalogEntrySchema = zod.z.object({
6194
5951
  */
6195
5952
  classMap: DetectionCatalogClassMapSchema.optional(),
6196
5953
  /**
6197
- * The pipeline steps this ROOT detector already does the work of (D715):
6198
- * its labels name the effect the step exists to produce (`deer` for
6199
- * `animal-classifier`, `package` for `package-detection`). Derived from the
6200
- * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
6201
- * declares none. Whether a declaration is honoured is the step's own
6202
- * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
6203
- * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
5954
+ * The pipeline steps this ROOT detector can supply from its own output
5955
+ * (D730): its labels name a step's effect (`deer` for `animal-classifier`)
5956
+ * or draw a step's box (`license_plate` for `plate-detection`). Computed at
5957
+ * import from THIS model's labelmap by `deriveRootSupplies`, never written
5958
+ * by hand and never assumed per family; a row without it is derived on read
5959
+ * (`rootSuppliesOf`). Whether a camera uses it is the step's own
5960
+ * `useRootModel` flag (`resolveRootSupply`).
6204
5961
  */
6205
- fillsClassifierEffects: zod.z.array(FillsClassifierEffectSchema).readonly().optional(),
5962
+ suppliesSteps: zod.z.array(RootStepSupplySchema).readonly().optional(),
6206
5963
  /**
6207
5964
  * The model's CLIP feature-space contract (text encoder, dimension, vector
6208
5965
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
@@ -10995,7 +10752,7 @@ function unavailableFor(tf, role, mode, cap, at) {
10995
10752
  };
10996
10753
  return {
10997
10754
  ok: false,
10998
- problem: problem("not-replaceable", at, `\`${cap}.${tf.path}\` reads a source but can say neither null nor 'unknown', and an ADDED capability has no native reading to fall back to (D393, D663)`)
10755
+ problem: problem("not-replaceable", at, `\`${cap}.${tf.path}\` reads a source but can say neither null nor 'unknown', and an ADDED capability has no native reading to fall back to`)
10999
10756
  };
11000
10757
  }
11001
10758
  //#endregion
@@ -16359,6 +16116,151 @@ var filesystemBrowseCapability = {
16359
16116
  }
16360
16117
  };
16361
16118
  //#endregion
16119
+ //#region src/capabilities/hub-address.ts
16120
+ var IPV4_LITERAL = /^\d{1,3}(?:\.\d{1,3}){3}$/;
16121
+ function hostnameOf(baseUrl) {
16122
+ try {
16123
+ const host = new URL(baseUrl).hostname;
16124
+ return host.length > 0 ? host : null;
16125
+ } catch {
16126
+ return null;
16127
+ }
16128
+ }
16129
+ function isMesh(endpoint) {
16130
+ return endpoint.kind === "public" && endpoint.interfaceKind === "vpn";
16131
+ }
16132
+ function isTunnel(endpoint) {
16133
+ return endpoint.kind === "public" && endpoint.interfaceKind === "public";
16134
+ }
16135
+ function isPlausibleLan(endpoint) {
16136
+ return (endpoint.kind === "lan-ipv4" || endpoint.kind === "lan-ipv6") && endpoint.plausible;
16137
+ }
16138
+ function isLanIpv4Literal(endpoint) {
16139
+ if (endpoint.kind !== "lan-ipv4" || !endpoint.plausible) return false;
16140
+ const host = hostnameOf(endpoint.baseUrl);
16141
+ return host !== null && IPV4_LITERAL.test(host);
16142
+ }
16143
+ /** Lower = better; `null` = never this audience's answer. */
16144
+ function rankFor(audience, endpoint) {
16145
+ if (endpoint.kind === "loopback" || endpoint.kind === "app-link") return null;
16146
+ if (hostnameOf(endpoint.baseUrl) === null) return null;
16147
+ if (audience === "cluster") {
16148
+ if (isLanIpv4Literal(endpoint)) return 0;
16149
+ if (isPlausibleLan(endpoint)) return 1;
16150
+ if (isMesh(endpoint)) return 2;
16151
+ return null;
16152
+ }
16153
+ if (isTunnel(endpoint)) return 0;
16154
+ if (isMesh(endpoint)) return 1;
16155
+ if (isLanIpv4Literal(endpoint)) return 2;
16156
+ if (isPlausibleLan(endpoint)) return 3;
16157
+ return null;
16158
+ }
16159
+ var LOOPBACK_HOSTS = new Set([
16160
+ "localhost",
16161
+ "0.0.0.0",
16162
+ "::1",
16163
+ "[::1]",
16164
+ "::",
16165
+ "[::]"
16166
+ ]);
16167
+ function isLoopbackHost(hostname) {
16168
+ const h = hostname.toLowerCase();
16169
+ if (LOOPBACK_HOSTS.has(h) || h.endsWith(".localhost")) return true;
16170
+ return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(h);
16171
+ }
16172
+ /**
16173
+ * Validate an operator-typed override: an http(s) URL with a host, no
16174
+ * credentials, no path, and never loopback (it would name whoever dials it).
16175
+ * Answers the normalised origin (`scheme://host[:port]`).
16176
+ */
16177
+ function validateHubAddressOverride(raw) {
16178
+ const trimmed = raw.trim();
16179
+ if (trimmed === "") return {
16180
+ ok: false,
16181
+ reason: "Enter an address, e.g. https://192.168.1.50:4443."
16182
+ };
16183
+ let parsed;
16184
+ try {
16185
+ parsed = new URL(trimmed);
16186
+ } catch {
16187
+ return {
16188
+ ok: false,
16189
+ reason: "Not a URL — include http:// or https://."
16190
+ };
16191
+ }
16192
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return {
16193
+ ok: false,
16194
+ reason: "Use an http:// or https:// address."
16195
+ };
16196
+ if (parsed.username !== "" || parsed.password !== "") return {
16197
+ ok: false,
16198
+ reason: "The address must not carry a user name or password."
16199
+ };
16200
+ if (parsed.hostname === "") return {
16201
+ ok: false,
16202
+ reason: "The address has no host."
16203
+ };
16204
+ if (isLoopbackHost(parsed.hostname)) return {
16205
+ ok: false,
16206
+ reason: "A loopback address names whoever dials it, never this hub — use an address other machines reach."
16207
+ };
16208
+ if (parsed.pathname !== "/" || parsed.search !== "" || parsed.hash !== "") return {
16209
+ ok: false,
16210
+ reason: "Enter only the address (scheme, host and port), without a path."
16211
+ };
16212
+ return {
16213
+ ok: true,
16214
+ baseUrl: parsed.origin
16215
+ };
16216
+ }
16217
+ /**
16218
+ * The hub's base URL for `audience`, without a trailing slash, or `null` when
16219
+ * the palette holds nothing that audience can reach. A valid operator
16220
+ * `override` wins outright; an empty one means automatic. Ties inside a rank
16221
+ * go to the palette's own `priority` (its preferred interface first).
16222
+ */
16223
+ function pickHubBaseUrl(endpoints, audience, override = null) {
16224
+ return resolveHubAddress(endpoints, audience, override).resolved;
16225
+ }
16226
+ /** {@link pickHubBaseUrl}, saying where the answer came from. */
16227
+ function resolveHubAddress(endpoints, audience, override) {
16228
+ if (override !== null && override !== "") {
16229
+ const check = validateHubAddressOverride(override);
16230
+ if (check.ok) return {
16231
+ override,
16232
+ resolved: check.baseUrl,
16233
+ source: "override"
16234
+ };
16235
+ }
16236
+ const auto = pickFromPalette(endpoints, audience);
16237
+ return {
16238
+ override: override === null || override === "" ? null : override,
16239
+ resolved: auto,
16240
+ source: auto === null ? "none" : "auto"
16241
+ };
16242
+ }
16243
+ function pickFromPalette(endpoints, audience) {
16244
+ const best = endpoints.flatMap((endpoint) => {
16245
+ const rank = rankFor(audience, endpoint);
16246
+ return rank === null ? [] : [{
16247
+ rank,
16248
+ priority: endpoint.priority,
16249
+ endpoint
16250
+ }];
16251
+ }).toSorted((a, b) => a.rank - b.rank || a.priority - b.priority)[0];
16252
+ return best === void 0 ? null : best.endpoint.baseUrl.replace(/\/+$/, "");
16253
+ }
16254
+ /** The bare hostname of {@link pickHubBaseUrl}'s answer, or `null`. */
16255
+ function pickHubHostname(endpoints, audience, override = null) {
16256
+ const baseUrl = pickHubBaseUrl(endpoints, audience, override);
16257
+ return baseUrl === null ? null : hostnameOf(baseUrl);
16258
+ }
16259
+ /** The bare hostname of a base URL, or `null` when it does not parse. */
16260
+ function hubAddressHostname(baseUrl) {
16261
+ return baseUrl === null ? null : hostnameOf(baseUrl);
16262
+ }
16263
+ //#endregion
16362
16264
  //#region src/capabilities/ai-cap-timeouts.ts
16363
16265
  /**
16364
16266
  * Transport bounds for AI capability methods.
@@ -18591,6 +18493,398 @@ var notificationOutputCapability = {
18591
18493
  }
18592
18494
  };
18593
18495
  //#endregion
18496
+ //#region src/catalogs/coco-classmap.ts
18497
+ var COCO_80_LABELS = [
18498
+ {
18499
+ id: "person",
18500
+ name: "Person"
18501
+ },
18502
+ {
18503
+ id: "bicycle",
18504
+ name: "Bicycle"
18505
+ },
18506
+ {
18507
+ id: "car",
18508
+ name: "Car"
18509
+ },
18510
+ {
18511
+ id: "motorcycle",
18512
+ name: "Motorcycle"
18513
+ },
18514
+ {
18515
+ id: "airplane",
18516
+ name: "Airplane"
18517
+ },
18518
+ {
18519
+ id: "bus",
18520
+ name: "Bus"
18521
+ },
18522
+ {
18523
+ id: "train",
18524
+ name: "Train"
18525
+ },
18526
+ {
18527
+ id: "truck",
18528
+ name: "Truck"
18529
+ },
18530
+ {
18531
+ id: "boat",
18532
+ name: "Boat"
18533
+ },
18534
+ {
18535
+ id: "traffic light",
18536
+ name: "Traffic Light"
18537
+ },
18538
+ {
18539
+ id: "fire hydrant",
18540
+ name: "Fire Hydrant"
18541
+ },
18542
+ {
18543
+ id: "stop sign",
18544
+ name: "Stop Sign"
18545
+ },
18546
+ {
18547
+ id: "parking meter",
18548
+ name: "Parking Meter"
18549
+ },
18550
+ {
18551
+ id: "bench",
18552
+ name: "Bench"
18553
+ },
18554
+ {
18555
+ id: "bird",
18556
+ name: "Bird"
18557
+ },
18558
+ {
18559
+ id: "cat",
18560
+ name: "Cat"
18561
+ },
18562
+ {
18563
+ id: "dog",
18564
+ name: "Dog"
18565
+ },
18566
+ {
18567
+ id: "horse",
18568
+ name: "Horse"
18569
+ },
18570
+ {
18571
+ id: "sheep",
18572
+ name: "Sheep"
18573
+ },
18574
+ {
18575
+ id: "cow",
18576
+ name: "Cow"
18577
+ },
18578
+ {
18579
+ id: "elephant",
18580
+ name: "Elephant"
18581
+ },
18582
+ {
18583
+ id: "bear",
18584
+ name: "Bear"
18585
+ },
18586
+ {
18587
+ id: "zebra",
18588
+ name: "Zebra"
18589
+ },
18590
+ {
18591
+ id: "giraffe",
18592
+ name: "Giraffe"
18593
+ },
18594
+ {
18595
+ id: "backpack",
18596
+ name: "Backpack"
18597
+ },
18598
+ {
18599
+ id: "umbrella",
18600
+ name: "Umbrella"
18601
+ },
18602
+ {
18603
+ id: "handbag",
18604
+ name: "Handbag"
18605
+ },
18606
+ {
18607
+ id: "tie",
18608
+ name: "Tie"
18609
+ },
18610
+ {
18611
+ id: "suitcase",
18612
+ name: "Suitcase"
18613
+ },
18614
+ {
18615
+ id: "frisbee",
18616
+ name: "Frisbee"
18617
+ },
18618
+ {
18619
+ id: "skis",
18620
+ name: "Skis"
18621
+ },
18622
+ {
18623
+ id: "snowboard",
18624
+ name: "Snowboard"
18625
+ },
18626
+ {
18627
+ id: "sports ball",
18628
+ name: "Sports Ball"
18629
+ },
18630
+ {
18631
+ id: "kite",
18632
+ name: "Kite"
18633
+ },
18634
+ {
18635
+ id: "baseball bat",
18636
+ name: "Baseball Bat"
18637
+ },
18638
+ {
18639
+ id: "baseball glove",
18640
+ name: "Baseball Glove"
18641
+ },
18642
+ {
18643
+ id: "skateboard",
18644
+ name: "Skateboard"
18645
+ },
18646
+ {
18647
+ id: "surfboard",
18648
+ name: "Surfboard"
18649
+ },
18650
+ {
18651
+ id: "tennis racket",
18652
+ name: "Tennis Racket"
18653
+ },
18654
+ {
18655
+ id: "bottle",
18656
+ name: "Bottle"
18657
+ },
18658
+ {
18659
+ id: "wine glass",
18660
+ name: "Wine Glass"
18661
+ },
18662
+ {
18663
+ id: "cup",
18664
+ name: "Cup"
18665
+ },
18666
+ {
18667
+ id: "fork",
18668
+ name: "Fork"
18669
+ },
18670
+ {
18671
+ id: "knife",
18672
+ name: "Knife"
18673
+ },
18674
+ {
18675
+ id: "spoon",
18676
+ name: "Spoon"
18677
+ },
18678
+ {
18679
+ id: "bowl",
18680
+ name: "Bowl"
18681
+ },
18682
+ {
18683
+ id: "banana",
18684
+ name: "Banana"
18685
+ },
18686
+ {
18687
+ id: "apple",
18688
+ name: "Apple"
18689
+ },
18690
+ {
18691
+ id: "sandwich",
18692
+ name: "Sandwich"
18693
+ },
18694
+ {
18695
+ id: "orange",
18696
+ name: "Orange"
18697
+ },
18698
+ {
18699
+ id: "broccoli",
18700
+ name: "Broccoli"
18701
+ },
18702
+ {
18703
+ id: "carrot",
18704
+ name: "Carrot"
18705
+ },
18706
+ {
18707
+ id: "hot dog",
18708
+ name: "Hot Dog"
18709
+ },
18710
+ {
18711
+ id: "pizza",
18712
+ name: "Pizza"
18713
+ },
18714
+ {
18715
+ id: "donut",
18716
+ name: "Donut"
18717
+ },
18718
+ {
18719
+ id: "cake",
18720
+ name: "Cake"
18721
+ },
18722
+ {
18723
+ id: "chair",
18724
+ name: "Chair"
18725
+ },
18726
+ {
18727
+ id: "couch",
18728
+ name: "Couch"
18729
+ },
18730
+ {
18731
+ id: "potted plant",
18732
+ name: "Potted Plant"
18733
+ },
18734
+ {
18735
+ id: "bed",
18736
+ name: "Bed"
18737
+ },
18738
+ {
18739
+ id: "dining table",
18740
+ name: "Dining Table"
18741
+ },
18742
+ {
18743
+ id: "toilet",
18744
+ name: "Toilet"
18745
+ },
18746
+ {
18747
+ id: "tv",
18748
+ name: "TV"
18749
+ },
18750
+ {
18751
+ id: "laptop",
18752
+ name: "Laptop"
18753
+ },
18754
+ {
18755
+ id: "mouse",
18756
+ name: "Mouse"
18757
+ },
18758
+ {
18759
+ id: "remote",
18760
+ name: "Remote"
18761
+ },
18762
+ {
18763
+ id: "keyboard",
18764
+ name: "Keyboard"
18765
+ },
18766
+ {
18767
+ id: "cell phone",
18768
+ name: "Cell Phone"
18769
+ },
18770
+ {
18771
+ id: "microwave",
18772
+ name: "Microwave"
18773
+ },
18774
+ {
18775
+ id: "oven",
18776
+ name: "Oven"
18777
+ },
18778
+ {
18779
+ id: "toaster",
18780
+ name: "Toaster"
18781
+ },
18782
+ {
18783
+ id: "sink",
18784
+ name: "Sink"
18785
+ },
18786
+ {
18787
+ id: "refrigerator",
18788
+ name: "Refrigerator"
18789
+ },
18790
+ {
18791
+ id: "book",
18792
+ name: "Book"
18793
+ },
18794
+ {
18795
+ id: "clock",
18796
+ name: "Clock"
18797
+ },
18798
+ {
18799
+ id: "vase",
18800
+ name: "Vase"
18801
+ },
18802
+ {
18803
+ id: "scissors",
18804
+ name: "Scissors"
18805
+ },
18806
+ {
18807
+ id: "teddy bear",
18808
+ name: "Teddy Bear"
18809
+ },
18810
+ {
18811
+ id: "hair drier",
18812
+ name: "Hair Drier"
18813
+ },
18814
+ {
18815
+ id: "toothbrush",
18816
+ name: "Toothbrush"
18817
+ }
18818
+ ];
18819
+ var MACRO_LABELS = [
18820
+ {
18821
+ id: "person",
18822
+ name: "Person"
18823
+ },
18824
+ {
18825
+ id: "vehicle",
18826
+ name: "Vehicle"
18827
+ },
18828
+ {
18829
+ id: "animal",
18830
+ name: "Animal"
18831
+ },
18832
+ {
18833
+ id: "package",
18834
+ name: "Package"
18835
+ }
18836
+ ];
18837
+ /**
18838
+ * The class names a per-class COUNT can ever be keyed on — the macro ids, and
18839
+ * only those.
18840
+ *
18841
+ * `preserveOriginal: false` below is the whole reason this set exists: the
18842
+ * executor maps each raw COCO label onto its macro and DROPS everything else,
18843
+ * so a tracked detection's `className` is always one of {@link MACRO_LABELS}.
18844
+ * Any surface that indexes counts by class name — the ZoneAnalytics occupancy
18845
+ * snapshot's `byClass`, and therefore every occupancy rule — can match nothing
18846
+ * else. Derived from the catalog, never hand-listed, so a new macro joins it by
18847
+ * being declared once.
18848
+ *
18849
+ * Cost of not having it, 2026-08-12: the notification rule editor offered the
18850
+ * full taxonomy for an occupancy class (occupancy is the one condition that
18851
+ * does not go through the engine's macro-expanding `expandClassSelector`), two
18852
+ * live rules were authored on `car`, and both counters read 0 forever.
18853
+ */
18854
+ var DETECTION_MACRO_CLASSES = new Set(MACRO_LABELS.map((l) => l.id));
18855
+ /** True when `className` is a macro the detector can actually emit (and hence a
18856
+ * class a count can be keyed on) — see {@link DETECTION_MACRO_CLASSES}. */
18857
+ function isDetectionMacroClass(className) {
18858
+ return DETECTION_MACRO_CLASSES.has(className.trim().toLowerCase());
18859
+ }
18860
+ var COCO_TO_MACRO = {
18861
+ mapping: {
18862
+ person: "person",
18863
+ bicycle: "vehicle",
18864
+ car: "vehicle",
18865
+ motorcycle: "vehicle",
18866
+ airplane: "vehicle",
18867
+ bus: "vehicle",
18868
+ train: "vehicle",
18869
+ truck: "vehicle",
18870
+ boat: "vehicle",
18871
+ bird: "animal",
18872
+ cat: "animal",
18873
+ dog: "animal",
18874
+ horse: "animal",
18875
+ sheep: "animal",
18876
+ cow: "animal",
18877
+ elephant: "animal",
18878
+ bear: "animal",
18879
+ zebra: "animal",
18880
+ giraffe: "animal",
18881
+ suitcase: "package",
18882
+ backpack: "package",
18883
+ handbag: "package"
18884
+ },
18885
+ preserveOriginal: false
18886
+ };
18887
+ //#endregion
18594
18888
  //#region src/catalogs/audio-classmap.ts
18595
18889
  var AUDIO_MACRO_LABELS = [
18596
18890
  {
@@ -21248,7 +21542,7 @@ var NC_CONDITION_CATALOG = [
21248
21542
  operator: "in",
21249
21543
  appliesTo: ["immediate", "track-end"],
21250
21544
  phase: "P1",
21251
- description: "Only recognised people. Selecting NOBODY means every identity in the face gallery; selecting some narrows to those. Matched on the gallery id, so renaming a person does not break the rule. On Immediate delivery the name must already be known when an event is written — choose Immediate, grouped to wait for it (D692)."
21545
+ description: "Only recognised people. Selecting NOBODY means every identity in the face gallery; selecting some narrows to those. Matched on the gallery id, so renaming a person does not break the rule. On Immediate delivery the name must already be known when an event is written — choose Immediate, grouped to wait for it."
21252
21546
  },
21253
21547
  {
21254
21548
  id: "plates",
@@ -25848,6 +26142,34 @@ var pipelineAnalyticsCapability = {
25848
26142
  //#endregion
25849
26143
  //#region src/capabilities/pipeline-executor.cap.ts
25850
26144
  /**
26145
+ * A root model's boxes standing in for one crop-kind step's own inference
26146
+ * (D730) — see `runPipeline.suppliedRoot`.
26147
+ */
26148
+ var SuppliedRootOutputSchema = zod.z.object({
26149
+ stepId: zod.z.string(),
26150
+ /** The root model that drew the boxes — stamped on the result. */
26151
+ modelId: zod.z.string(),
26152
+ detections: zod.z.array(zod.z.object({
26153
+ /** `[x1, y1, x2, y2]` in the pixels of the call's image. */
26154
+ bbox: zod.z.tuple([
26155
+ zod.z.number(),
26156
+ zod.z.number(),
26157
+ zod.z.number(),
26158
+ zod.z.number()
26159
+ ]),
26160
+ score: zod.z.number(),
26161
+ /**
26162
+ * Five facial landmarks in the same pixels — a face the step's own
26163
+ * detector already re-found inside a root face box (D730), so its
26164
+ * embedder child aligns it exactly as it aligns any detected face.
26165
+ */
26166
+ landmarks: zod.z.array(zod.z.object({
26167
+ x: zod.z.number(),
26168
+ y: zod.z.number()
26169
+ })).optional()
26170
+ })).min(1)
26171
+ });
26172
+ /**
25851
26173
  * Reference to the frame's retained NATIVE surface + the parent crop's placement
25852
26174
  * within the frame, so the executor can re-cut a leaf child ROI at native
25853
26175
  * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
@@ -25979,7 +26301,7 @@ var PipelineModelOptionSchema = zod.z.object({
25979
26301
  legacy: zod.z.boolean().optional(),
25980
26302
  provider: ModelProviderIdSchema.optional(),
25981
26303
  defaultConfidence: zod.z.number().optional(),
25982
- fillsClassifierEffects: zod.z.array(FillsClassifierEffectSchema).readonly().optional()
26304
+ suppliesSteps: zod.z.array(RootStepSupplySchema).readonly().optional()
25983
26305
  });
25984
26306
  var ConfigFieldBridge = zod.z.custom();
25985
26307
  var PipelineAddonSchemaSchema = zod.z.object({
@@ -26383,7 +26705,16 @@ var pipelineExecutorCapability = {
26383
26705
  * `device-not-servable`), and nothing reaches the camera's live
26384
26706
  * trace stream. Absent ⇒ unchanged behaviour.
26385
26707
  */
26386
- replay: zod.z.literal(true).optional()
26708
+ replay: zod.z.literal(true).optional(),
26709
+ /**
26710
+ * Root-supplied detections for the tree's ROOT step (D730). Set by
26711
+ * `runDetailSubtree` when the camera's root model supplies a crop-kind
26712
+ * step (a Frigate+ `license_plate` for `plate-detection`): the step is
26713
+ * NOT inferred, these boxes are its output, and its children (the plate
26714
+ * reader) run on them through their own crop policy. Boxes are in the
26715
+ * PIXELS of the image this call carries. Absent ⇒ the root step runs.
26716
+ */
26717
+ suppliedRoot: SuppliedRootOutputSchema.optional()
26387
26718
  }), PipelineRunResultBridge, { kind: "mutation" }),
26388
26719
  /**
26389
26720
  * Batched run — N raw frames packed into one cap call. The provider
@@ -27896,7 +28227,22 @@ var pipelineRunnerCapability = {
27896
28227
  */
27897
28228
  cropJpeg: zod.z.string().optional(),
27898
28229
  parent: DetailParentSchema,
27899
- steps: zod.z.array(zod.z.string()).optional()
28230
+ steps: zod.z.array(zod.z.string()).optional(),
28231
+ /**
28232
+ * The camera's root model already drew this step's boxes (D730): a
28233
+ * `license_plate` inside the parent vehicle. The named step is NOT
28234
+ * inferred — these FRAME-space boxes are its output — and its
28235
+ * requested children (the plate reader) run on them. Absent ⇒ every
28236
+ * requested step infers as before.
28237
+ */
28238
+ supplied: zod.z.object({
28239
+ stepId: zod.z.string(),
28240
+ modelId: zod.z.string(),
28241
+ boxes: zod.z.array(zod.z.object({
28242
+ bbox: NativeCropBboxSchema,
28243
+ score: zod.z.number()
28244
+ })).min(1)
28245
+ }).optional()
27900
28246
  }), zod.z.object({ details: zod.z.array(DetailResultSchema) }).nullable(), { kind: "mutation" }),
27901
28247
  /**
27902
28248
  * Run ONE enrichment step against caller-supplied pixels, with NO camera
@@ -37596,6 +37942,27 @@ var ViewerEndpointsSchema = zod.z.object({
37596
37942
  /** What the ranking currently resolves to (may be empty if nothing is up). */
37597
37943
  resolved: zod.z.array(zod.z.string()).readonly()
37598
37944
  });
37945
+ /**
37946
+ * One audience's hub address (see `hub-address.ts`): the operator's stored
37947
+ * override, the address in use, and where it came from.
37948
+ */
37949
+ var HubAddressSnapshotSchema = zod.z.object({
37950
+ /** The operator's override, or null for automatic. */
37951
+ override: zod.z.string().nullable(),
37952
+ /** The address in use, or null when nothing qualifies (never loopback). */
37953
+ resolved: zod.z.string().nullable(),
37954
+ source: zod.z.enum([
37955
+ "override",
37956
+ "auto",
37957
+ "none"
37958
+ ])
37959
+ });
37960
+ var HubAddressesSchema = zod.z.object({
37961
+ /** "Hub address for agents" — agents' bundle/model pulls, LAN devices. */
37962
+ cluster: HubAddressSnapshotSchema,
37963
+ /** "Public address for sign-in links" — e-mail links, OIDC, WebAuthn, OAuth2. */
37964
+ browser: HubAddressSnapshotSchema
37965
+ });
37599
37966
  var AllowedAddressesSchema = zod.z.object({
37600
37967
  /**
37601
37968
  * Allowlist of interface addresses operators have explicitly opted
@@ -37728,6 +38095,26 @@ var localNetworkCapability = {
37728
38095
  */
37729
38096
  setViewerEndpoints: require_sleep.method(zod.z.object({ baseUrls: zod.z.array(zod.z.string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }),
37730
38097
  /**
38098
+ * The hub's address for each audience — agents (`cluster`) and sign-in
38099
+ * links (`browser`) — as every consumer must read it: the operator's
38100
+ * override when set, else the automatic pick from this cap's palette,
38101
+ * never loopback. The ONE answer to "at which address is this hub
38102
+ * reached?"; there is no environment variable for it.
38103
+ */
38104
+ getHubAddresses: require_sleep.method(zod.z.void(), HubAddressesSchema),
38105
+ /**
38106
+ * Set or clear (`baseUrl: null`) one audience's override. Validated: an
38107
+ * http(s) origin with a host, no credentials, no path, never loopback —
38108
+ * an invalid value is refused with the reason, nothing is stored.
38109
+ */
38110
+ setHubAddress: require_sleep.method(zod.z.object({
38111
+ audience: zod.z.enum(["cluster", "browser"]),
38112
+ baseUrl: zod.z.string().nullable()
38113
+ }), HubAddressesSchema, {
38114
+ kind: "mutation",
38115
+ auth: "admin"
38116
+ }),
38117
+ /**
37731
38118
  * Read the operator's allowlist. Empty = "auto" (no filter). Used
37732
38119
  * by the admin UI's address selector to seed its checkbox state.
37733
38120
  */
@@ -47869,7 +48256,9 @@ var FRIGATE_PLUS_TO_MACRO = {
47869
48256
  * - `attribute`: Frigate+ emits these INSIDE a parent box (a face inside a
47870
48257
  * person, a plate or a carrier logo on a vehicle). Mapping one to its
47871
48258
  * parent's macro would spawn a second, overlapping track for the same
47872
- * subject; CamStack derives faces and plates with its own detail steps.
48259
+ * subject. `face` and `license_plate` are instead declared as CROP supplies
48260
+ * (D730): the box becomes a detail child of the person / vehicle containing
48261
+ * it, when the face / plate step uses the root model.
47873
48262
  * - `no-macro`: an object with no detection macro to live under.
47874
48263
  */
47875
48264
  var FRIGATE_PLUS_UNMAPPED_LABELS = {
@@ -47915,17 +48304,18 @@ function buildFrigateClassMap(labels) {
47915
48304
  };
47916
48305
  }
47917
48306
  /**
47918
- * Everything a Frigate / Frigate+ entry derives from its labelmap: the classMap
47919
- * and the steps it fills (D715). Every Frigate builder spreads this, so the two
47920
- * cannot be derived from different label lists. A COCO labelmap gets its map
47921
- * and no fill.
48307
+ * Everything a Frigate / Frigate+ entry derives from ITS OWN labelmap: the
48308
+ * classMap and the steps it can supply (D730) — label and crop kinds alike.
48309
+ * Every Frigate builder spreads this at import, so the two cannot be derived
48310
+ * from different label lists, and no family is assumed to carry a label it
48311
+ * does not list.
47922
48312
  */
47923
48313
  function frigateLabelFields(labels) {
47924
48314
  const classMap = buildFrigateClassMap(labels);
47925
- const fills = deriveClassifierFills(labels, classMap);
47926
- return fills.length > 0 ? {
48315
+ const supplies = deriveRootSupplies(labels, classMap);
48316
+ return supplies.length > 0 ? {
47927
48317
  classMap,
47928
- fillsClassifierEffects: fills
48318
+ suppliesSteps: supplies
47929
48319
  } : { classMap };
47930
48320
  }
47931
48321
  //#endregion
@@ -53385,6 +53775,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
53385
53775
  addonId: null,
53386
53776
  access: "view"
53387
53777
  },
53778
+ "localNetwork.getHubAddresses": {
53779
+ capName: "local-network",
53780
+ capScope: "system",
53781
+ addonId: null,
53782
+ access: "view"
53783
+ },
53388
53784
  "localNetwork.getNotificationEndpoint": {
53389
53785
  capName: "local-network",
53390
53786
  capScope: "system",
@@ -53439,6 +53835,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
53439
53835
  addonId: null,
53440
53836
  access: "create"
53441
53837
  },
53838
+ "localNetwork.setHubAddress": {
53839
+ capName: "local-network",
53840
+ capScope: "system",
53841
+ addonId: null,
53842
+ access: "create"
53843
+ },
53442
53844
  "localNetwork.setNotificationEndpoint": {
53443
53845
  capName: "local-network",
53444
53846
  capScope: "system",
@@ -66001,6 +66403,8 @@ function createSystemProxy(api) {
66001
66403
  setNotificationEndpoint: (input) => dispatch("localNetwork", "setNotificationEndpoint", "mutation", input),
66002
66404
  getViewerEndpoints: (input) => dispatch("localNetwork", "getViewerEndpoints", "query", input),
66003
66405
  setViewerEndpoints: (input) => dispatch("localNetwork", "setViewerEndpoints", "mutation", input),
66406
+ getHubAddresses: (input) => dispatch("localNetwork", "getHubAddresses", "query", input),
66407
+ setHubAddress: (input) => dispatch("localNetwork", "setHubAddress", "mutation", input),
66004
66408
  getAllowedAddresses: (input) => dispatch("localNetwork", "getAllowedAddresses", "query", input),
66005
66409
  setAllowedAddresses: (input) => dispatch("localNetwork", "setAllowedAddresses", "mutation", input),
66006
66410
  resetAllowlistToBestMatch: (input) => dispatch("localNetwork", "resetAllowlistToBestMatch", "mutation", input),
@@ -68962,7 +69366,7 @@ var STATE_SUMMARY_VARS = [
68962
69366
  {
68963
69367
  name: "summarySection",
68964
69368
  label: "Summary: this section",
68965
- description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
69369
+ description: "The section a per-section summary row is about; on a summary sent as one message, every section it reports, comma-separated.",
68966
69370
  example: "Batterie scariche",
68967
69371
  group: "system",
68968
69372
  families: ["rule"],
@@ -71005,6 +71409,72 @@ function stepModelRunsOnFormat(models, modelId, format) {
71005
71409
  return models.some((m) => m.legacy !== true && hasBuild(m, format));
71006
71410
  }
71007
71411
  //#endregion
71412
+ //#region src/pipeline/removed-model-ids.ts
71413
+ /**
71414
+ * Model ids DELETED from a step's catalog (D703, D710, D719), per step — and
71415
+ * the one question asked of them: is a stored pin to this id a pin to a model
71416
+ * that no longer exists? (D725)
71417
+ *
71418
+ * This is NOT a resolver input. `resolveModelForFormat` still returns an
71419
+ * unknown id unchanged (a custom model), and a bulk pass pinned to one still
71420
+ * refuses rather than substitutes (D54). The ONE reader is the orchestrator's
71421
+ * stored-pin reset (`removed-model-pin-reset.ts`), which clears such a pin from
71422
+ * the store so the step follows its default again — unless a registered custom
71423
+ * model carries the same id.
71424
+ *
71425
+ * `removed-model-ids.spec.ts` (addon-pipeline) pins that every id here is
71426
+ * really absent from its step's catalog. A model deleted from a catalog is
71427
+ * added here in the same change, or its stored pins stay behind as custom ids.
71428
+ */
71429
+ /** `stepId → ids deleted from that step's catalog`. */
71430
+ var REMOVED_MODEL_IDS = {
71431
+ "object-detection": ["efficientdet-lite0-edgetpu", "ssdlite-mobiledet-coco-edgetpu"],
71432
+ "face-detection": [
71433
+ "scrypted-yolov9t-face",
71434
+ "scrfd-2.5g",
71435
+ "ssd-mobilenet-v2-face-edgetpu"
71436
+ ],
71437
+ "face-embedding": ["arcface-r100", "inception-resnet-v1"],
71438
+ "plate-detection": ["yolov8n-plate"],
71439
+ "plate-ocr": ["vgg-english-g2"],
71440
+ "clip-embedding": ["mobileclip-s1", "mobileclip-s2"],
71441
+ "package-detection": ["yolov8n-package"],
71442
+ "bird-classifier": ["bird-classifier-aiy-edgetpu", "bird-nabirds-404"],
71443
+ "animal-classifier": ["animals-10"],
71444
+ "vehicle-classifier": ["vehicle-type-efficientnet"]
71445
+ };
71446
+ /** True when `modelId` was deleted from `stepId`'s catalog. */
71447
+ function isRemovedModelId(stepId, modelId) {
71448
+ return REMOVED_MODEL_IDS[stepId]?.includes(modelId) ?? false;
71449
+ }
71450
+ //#endregion
71451
+ //#region src/pipeline/root-face-crop.ts
71452
+ /** Side of the square, as a multiple of the face box's longer side. */
71453
+ var ROOT_FACE_REFINE_SCALE = 1.6;
71454
+ /**
71455
+ * The input the face detector sees the square at, in pixels. A face that
71456
+ * fills ~60% of a 160 px input is in the detector's measured sweet spot; the
71457
+ * same square fed at 640 puts a ~400 px face in front of a detector whose
71458
+ * largest anchors are far smaller.
71459
+ */
71460
+ var ROOT_FACE_REFINE_INPUT_PX = 160;
71461
+ /**
71462
+ * The square (frame-space pixels) a root face box is refined in: centred on
71463
+ * the box, side `ROOT_FACE_REFINE_SCALE ×` its longer side, slid inside the
71464
+ * frame, and shrunk only when the frame's shorter side is smaller. Pure.
71465
+ */
71466
+ function deriveRootFaceRefineRect(face, frameWidth, frameHeight) {
71467
+ const side = Math.min(Math.max(face.w, face.h) * ROOT_FACE_REFINE_SCALE, Math.min(frameWidth, frameHeight));
71468
+ const cx = face.x + face.w / 2;
71469
+ const cy = face.y + face.h / 2;
71470
+ return {
71471
+ x: Math.min(Math.max(0, cx - side / 2), frameWidth - side),
71472
+ y: Math.min(Math.max(0, cy - side / 2), frameHeight - side),
71473
+ w: side,
71474
+ h: side
71475
+ };
71476
+ }
71477
+ //#endregion
71008
71478
  //#region src/pipeline/detail-crop.ts
71009
71479
  /**
71010
71480
  * THE detail-crop convention — the single derivation of the rectangle a
@@ -73284,6 +73754,8 @@ exports.CONNECTION_TEST_TIMEOUT_MS = CONNECTION_TEST_TIMEOUT_MS;
73284
73754
  exports.CONTAINER_CHILD_PRIORITY = CONTAINER_CHILD_PRIORITY;
73285
73755
  exports.CORE_BLOCKS_ADDON_ID = CORE_BLOCKS_ADDON_ID;
73286
73756
  exports.CORE_BLOCK_ADDON_PREFIX = CORE_BLOCK_ADDON_PREFIX;
73757
+ exports.CROP_SUPPLY_SOURCES = CROP_SUPPLY_SOURCES;
73758
+ exports.CROP_SUPPLY_STEP_IDS = CROP_SUPPLY_STEP_IDS;
73287
73759
  exports.CUSTOMIZATION_BLOCK_NAME_PREFIX = require_composition.CUSTOMIZATION_BLOCK_NAME_PREFIX;
73288
73760
  exports.CalendarColorSchema = CalendarColorSchema;
73289
73761
  exports.CalendarEntrySchema = CalendarEntrySchema;
@@ -73476,7 +73948,6 @@ exports.DEFAULT_EVENTS_BAND_BUFFER_SEC = DEFAULT_EVENTS_BAND_BUFFER_SEC;
73476
73948
  exports.DEFAULT_EVENT_COLOR = DEFAULT_EVENT_COLOR;
73477
73949
  exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
73478
73950
  exports.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = require_composition.DEFAULT_FIRST_SIGHTING_FRESHNESS_MS;
73479
- exports.DEFAULT_LABEL_LINK_POLICY = DEFAULT_LABEL_LINK_POLICY;
73480
73951
  exports.DEFAULT_MIN_LANDMARK_FACE_SIZE_PX = DEFAULT_MIN_LANDMARK_FACE_SIZE_PX;
73481
73952
  exports.DEFAULT_NATIVE_LEASE_SETTINGS = DEFAULT_NATIVE_LEASE_SETTINGS;
73482
73953
  exports.DEFAULT_OVERLAY_LAYERS = DEFAULT_OVERLAY_LAYERS;
@@ -73653,9 +74124,6 @@ exports.ExtensionSourceSchema = ExtensionSourceSchema;
73653
74124
  exports.FEEDER_EXAMPLE_ADDON_ID = FEEDER_EXAMPLE_ADDON_ID;
73654
74125
  exports.FEEDER_EXAMPLE_HA_DEVICE_ID = FEEDER_EXAMPLE_HA_DEVICE_ID;
73655
74126
  exports.FFMPEG_PATH_ENV = require_composition.FFMPEG_PATH_ENV;
73656
- exports.FILLABLE_STEP_IDS = FILLABLE_STEP_IDS;
73657
- exports.FILLABLE_STEP_MACRO = FILLABLE_STEP_MACRO;
73658
- exports.FILLABLE_STEP_VOCABULARIES = FILLABLE_STEP_VOCABULARIES;
73659
74127
  exports.FIRST_LEVEL_MACRO_CLASSES = FIRST_LEVEL_MACRO_CLASSES;
73660
74128
  exports.FRIGATE_PLUS_TO_MACRO = FRIGATE_PLUS_TO_MACRO;
73661
74129
  exports.FRIGATE_PLUS_UNMAPPED_LABELS = FRIGATE_PLUS_UNMAPPED_LABELS;
@@ -73669,7 +74137,6 @@ exports.FeatureManifestSchema = FeatureManifestSchema;
73669
74137
  exports.FeatureProbeStatusSchema = FeatureProbeStatusSchema;
73670
74138
  exports.FieldClaimModeSchema = FieldClaimModeSchema;
73671
74139
  exports.FieldClaimSchema = FieldClaimSchema;
73672
- exports.FillsClassifierEffectSchema = FillsClassifierEffectSchema;
73673
74140
  exports.FloodStatusSchema = FloodStatusSchema;
73674
74141
  exports.Fmp4BoxSplitter = require_composition.Fmp4BoxSplitter;
73675
74142
  exports.FrameHandleFormatSchema = require_sleep.FrameHandleFormatSchema;
@@ -73718,8 +74185,9 @@ exports.IntercomAbilitySchema = IntercomAbilitySchema;
73718
74185
  exports.IntercomStatusSchema = IntercomStatusSchema;
73719
74186
  exports.KNOWN_CAP_NAMES = KNOWN_CAP_NAMES;
73720
74187
  exports.KeyEventSchema = KeyEventSchema;
73721
- exports.LABEL_LINK_POLICIES = LABEL_LINK_POLICIES;
73722
- exports.LABEL_LINK_SETTING_KEY = LABEL_LINK_SETTING_KEY;
74188
+ exports.LABEL_SUPPLY_MACRO = LABEL_SUPPLY_MACRO;
74189
+ exports.LABEL_SUPPLY_STEP_IDS = LABEL_SUPPLY_STEP_IDS;
74190
+ exports.LABEL_SUPPLY_VOCABULARIES = LABEL_SUPPLY_VOCABULARIES;
73723
74191
  exports.LEGACY_READ_ONLY_CONFIG_KEY = LEGACY_READ_ONLY_CONFIG_KEY;
73724
74192
  exports.LINKED_DEVICES_SLOT = LINKED_DEVICES_SLOT;
73725
74193
  exports.LINKED_LABEL_STEP_PREFIX = LINKED_LABEL_STEP_PREFIX;
@@ -74235,6 +74703,7 @@ exports.RECORDING_SOURCE_CAMSTACK = RECORDING_SOURCE_CAMSTACK;
74235
74703
  exports.RECORDING_SOURCE_CAMSTACK_ADDON = RECORDING_SOURCE_CAMSTACK_ADDON;
74236
74704
  exports.RECORDING_TIMELINE_BATCH_MAX = RECORDING_TIMELINE_BATCH_MAX;
74237
74705
  exports.REDACTED_SECRET = REDACTED_SECRET;
74706
+ exports.REMOVED_MODEL_IDS = REMOVED_MODEL_IDS;
74238
74707
  exports.RESERVED_BINDING_NAMES = require_composition.RESERVED_BINDING_NAMES;
74239
74708
  exports.RESERVED_COLLECTION_SOURCES = RESERVED_COLLECTION_SOURCES;
74240
74709
  exports.RESTORED_CAP_NAMES = RESTORED_CAP_NAMES;
@@ -74242,6 +74711,10 @@ exports.ROOM_EXAMPLE_MOTION_SOURCES = ROOM_EXAMPLE_MOTION_SOURCES;
74242
74711
  exports.ROOM_EXAMPLE_TEMPERATURE_SOURCES = ROOM_EXAMPLE_TEMPERATURE_SOURCES;
74243
74712
  exports.ROOM_OCCUPANCY_WINDOW_MS = ROOM_OCCUPANCY_WINDOW_MS;
74244
74713
  exports.ROOT_BUCKET_KEY = ROOT_BUCKET_KEY;
74714
+ exports.ROOT_CHILD_CONTAINMENT_MIN = ROOT_CHILD_CONTAINMENT_MIN;
74715
+ exports.ROOT_FACE_REFINE_INPUT_PX = ROOT_FACE_REFINE_INPUT_PX;
74716
+ exports.ROOT_FACE_REFINE_SCALE = ROOT_FACE_REFINE_SCALE;
74717
+ exports.ROOT_SUPPLIABLE_STEP_IDS = ROOT_SUPPLIABLE_STEP_IDS;
74245
74718
  exports.RUNTIME_DEFAULTS = RUNTIME_DEFAULTS;
74246
74719
  exports.RUNTIME_STATE_POLICY = RUNTIME_STATE_POLICY;
74247
74720
  exports.RUNTIME_STATE_REFRESH_MISS_COOLDOWN_MS = RUNTIME_STATE_REFRESH_MISS_COOLDOWN_MS;
@@ -74326,6 +74799,7 @@ exports.RetrainStatusSchema = RetrainStatusSchema;
74326
74799
  exports.RetrainTrackSchema = RetrainTrackSchema;
74327
74800
  exports.RetrainTransitionResultSchema = RetrainTransitionResultSchema;
74328
74801
  exports.RingBuffer = RingBuffer;
74802
+ exports.RootStepSupplySchema = RootStepSupplySchema;
74329
74803
  exports.RtpSourceSchema = RtpSourceSchema;
74330
74804
  exports.RtspRestreamEntrySchema = RtspRestreamEntrySchema;
74331
74805
  exports.RunnerCameraConfigSchema = RunnerCameraConfigSchema;
@@ -74477,6 +74951,7 @@ exports.SubscribeAudioChunksInputSchema = require_sleep.SubscribeAudioChunksInpu
74477
74951
  exports.SubscribeAudioChunksResultSchema = require_sleep.SubscribeAudioChunksResultSchema;
74478
74952
  exports.SubscribeFramesInputSchema = require_sleep.SubscribeFramesInputSchema;
74479
74953
  exports.SubscribeFramesResultSchema = require_sleep.SubscribeFramesResultSchema;
74954
+ exports.SuppliedRootOutputSchema = SuppliedRootOutputSchema;
74480
74955
  exports.SwitchStatusSchema = SwitchStatusSchema;
74481
74956
  exports.SystemMetricsSchema = SystemMetricsSchema;
74482
74957
  exports.SystemMirror = SystemMirror;
@@ -74534,6 +75009,8 @@ exports.TransportPlaneSchema = TransportPlaneSchema;
74534
75009
  exports.TurnServerSchema = TurnServerSchema;
74535
75010
  exports.UNATTRIBUTED_BUCKET_KEY = UNATTRIBUTED_BUCKET_KEY;
74536
75011
  exports.UNIT_TABLE = UNIT_TABLE;
75012
+ exports.USE_ROOT_MODEL_DEFAULTS = USE_ROOT_MODEL_DEFAULTS;
75013
+ exports.USE_ROOT_MODEL_SETTING_KEY = USE_ROOT_MODEL_SETTING_KEY;
74537
75014
  exports.UnifiedBrokerInfoSchema = BrokerInfoSchema;
74538
75015
  exports.UnitConversionError = UnitConversionError;
74539
75016
  exports.UnstampedEventMediaCountSchema = UnstampedEventMediaCountSchema;
@@ -74628,6 +75105,7 @@ exports.alarmPatchLanded = alarmPatchLanded;
74628
75105
  exports.alarmProfileById = alarmProfileById;
74629
75106
  exports.alertsCapability = alertsCapability;
74630
75107
  exports.allDoActions = allDoActions;
75108
+ exports.allowedSuppliedEffect = allowedSuppliedEffect;
74631
75109
  exports.ambientLightSensorCapability = ambientLightSensorCapability;
74632
75110
  exports.applyBlockingEdit = applyBlockingEdit;
74633
75111
  exports.applyModeDelaysEdits = applyModeDelaysEdits;
@@ -74734,6 +75212,7 @@ exports.connectivityCapability = connectivityCapability;
74734
75212
  exports.consumableLowPercentOf = consumableLowPercentOf;
74735
75213
  exports.consumablesCapability = consumablesCapability;
74736
75214
  exports.contactCapability = contactCapability;
75215
+ exports.containingParentIndex = containingParentIndex;
74737
75216
  exports.controlCapability = controlCapability;
74738
75217
  exports.convertPresetFeature = convertPresetFeature;
74739
75218
  exports.convertUnit = convertUnit;
@@ -74777,15 +75256,18 @@ exports.defineExtensionSlotProvider = defineExtensionSlotProvider;
74777
75256
  exports.deleteAlarmProfile = deleteAlarmProfile;
74778
75257
  exports.deriveBatteryPresence = deriveBatteryPresence;
74779
75258
  exports.deriveCameraSwitches = deriveCameraSwitches;
74780
- exports.deriveClassifierFills = deriveClassifierFills;
74781
75259
  exports.deriveDetailCropRect = deriveDetailCropRect;
74782
75260
  exports.derivePostTriggeredAction = derivePostTriggeredAction;
74783
75261
  exports.deriveRecordingMode = deriveRecordingMode;
75262
+ exports.deriveRootFaceRefineRect = deriveRootFaceRefineRect;
75263
+ exports.deriveRootSupplies = deriveRootSupplies;
74784
75264
  exports.describeComposableCaps = describeComposableCaps;
74785
75265
  exports.describeCustomActions = require_sleep.describeCustomActions;
74786
75266
  exports.describeModelVariant = describeModelVariant;
74787
75267
  exports.describeOnboardClamp = describeOnboardClamp;
74788
75268
  exports.describeOnboardRefusal = describeOnboardRefusal;
75269
+ exports.describeRootSupplies = describeRootSupplies;
75270
+ exports.describeRootSupply = describeRootSupply;
74789
75271
  exports.describeStateField = describeStateField;
74790
75272
  exports.describeSystemEventDeliveryProblem = describeSystemEventDeliveryProblem;
74791
75273
  exports.describeSystemEventFamilyProblem = describeSystemEventFamilyProblem;
@@ -74869,7 +75351,6 @@ exports.feederExampleSources = feederExampleSources;
74869
75351
  exports.ffmpegRate = ffmpegRate;
74870
75352
  exports.fieldReads = require_composition.fieldReads;
74871
75353
  exports.filesystemBrowseCapability = filesystemBrowseCapability;
74872
- exports.fillFor = fillFor;
74873
75354
  exports.findCandidateCycles = findCandidateCycles;
74874
75355
  exports.findCompositionCycles = findCompositionCycles;
74875
75356
  exports.findTimezone = findTimezone;
@@ -74894,6 +75375,7 @@ exports.gifFromMp4Args = gifFromMp4Args;
74894
75375
  exports.hasMotionTrigger = hasMotionTrigger;
74895
75376
  exports.hfModelUrl = hfModelUrl;
74896
75377
  exports.htmlToText = htmlToText;
75378
+ exports.hubAddressHostname = hubAddressHostname;
74897
75379
  exports.hubMotionNativeProvider = hubMotionNativeProvider;
74898
75380
  exports.humidifierCapability = humidifierCapability;
74899
75381
  exports.humiditySensorCapability = humiditySensorCapability;
@@ -74920,7 +75402,6 @@ exports.isAudioRule = isAudioRule;
74920
75402
  exports.isBaseConditionKey = isBaseConditionKey;
74921
75403
  exports.isBatteryPresenceFault = isBatteryPresenceFault;
74922
75404
  exports.isClusterScopedStep = isClusterScopedStep;
74923
- exports.isCocoLabelmap = isCocoLabelmap;
74924
75405
  exports.isCollectionArrayMethod = isCollectionArrayMethod;
74925
75406
  exports.isDefaultAlarmProfileId = isDefaultAlarmProfileId;
74926
75407
  exports.isDeployableToAgent = isDeployableToAgent;
@@ -74934,19 +75415,21 @@ exports.isEmbeddingModelFailed = isEmbeddingModelFailed;
74934
75415
  exports.isEvent = require_sleep.isEvent;
74935
75416
  exports.isEventKindLabelKey = isEventKindLabelKey;
74936
75417
  exports.isEventOwnerType = isEventOwnerType;
74937
- exports.isFillableStepId = isFillableStepId;
74938
75418
  exports.isFirstLevelMacroClass = isFirstLevelMacroClass;
74939
75419
  exports.isHeldBackTemplateVar = isHeldBackTemplateVar;
74940
75420
  exports.isIsolatedBuiltin = isIsolatedBuiltin;
74941
75421
  exports.isKnownTemplateVar = isKnownTemplateVar;
75422
+ exports.isLabelSupplyStepId = isLabelSupplyStepId;
74942
75423
  exports.isLocationEnabled = isLocationEnabled;
74943
75424
  exports.isMediaOwnerType = isMediaOwnerType;
74944
75425
  exports.isNode = isNode;
74945
75426
  exports.isObjectInput = isObjectInput;
74946
75427
  exports.isOccupancyRule = isOccupancyRule;
74947
75428
  exports.isOwnerOnlyEventCategory = require_event_category.isOwnerOnlyEventCategory;
75429
+ exports.isRemovedModelId = isRemovedModelId;
74948
75430
  exports.isRestoredCap = isRestoredCap;
74949
75431
  exports.isRetiredClearKey = isRetiredClearKey;
75432
+ exports.isRootSuppliableStepId = isRootSuppliableStepId;
74950
75433
  exports.isSameAddonId = isSameAddonId;
74951
75434
  exports.isScheduleActive = isScheduleActive;
74952
75435
  exports.isSecretConfigField = isSecretConfigField;
@@ -75066,6 +75549,8 @@ exports.pickAppLinkHub = pickAppLinkHub;
75066
75549
  exports.pickClusterStepModels = pickClusterStepModels;
75067
75550
  exports.pickClusterStepSettings = pickClusterStepSettings;
75068
75551
  exports.pickDetailCropConvention = pickDetailCropConvention;
75552
+ exports.pickHubBaseUrl = pickHubBaseUrl;
75553
+ exports.pickHubHostname = pickHubHostname;
75069
75554
  exports.pickInvalidClusterStepModels = pickInvalidClusterStepModels;
75070
75555
  exports.pickNativeLeaseOverride = pickNativeLeaseOverride;
75071
75556
  exports.pickPreferredRtspEntry = pickPreferredRtspEntry;
@@ -75102,11 +75587,11 @@ exports.readDetailCropConvention = readDetailCropConvention;
75102
75587
  exports.readDeviceStateFrom = readDeviceStateFrom;
75103
75588
  exports.readHubMotionDetected = readHubMotionDetected;
75104
75589
  exports.readHubMotionStatus = readHubMotionStatus;
75105
- exports.readLabelLinkPolicy = readLabelLinkPolicy;
75106
75590
  exports.readMotionTriggeredBy = readMotionTriggeredBy;
75107
75591
  exports.readNativeLeaseOverride = readNativeLeaseOverride;
75108
75592
  exports.readNodePin = require_sleep.readNodePin;
75109
75593
  exports.readTimelapseGeneratedAt = readTimelapseGeneratedAt;
75594
+ exports.readUseRootModel = readUseRootModel;
75110
75595
  exports.readinessKey = require_sleep.readinessKey;
75111
75596
  exports.rebootCapability = rebootCapability;
75112
75597
  exports.reconcileBlockDevices = reconcileBlockDevices;
@@ -75139,8 +75624,8 @@ exports.resolveDeviceProfile = resolveDeviceProfile;
75139
75624
  exports.resolveEgressDecodeHwAccel = resolveEgressDecodeHwAccel;
75140
75625
  exports.resolveExportProfiles = resolveExportProfiles;
75141
75626
  exports.resolveFormat = resolveFormat;
75627
+ exports.resolveHubAddress = resolveHubAddress;
75142
75628
  exports.resolveHydratedFieldValue = require_sleep.resolveHydratedFieldValue;
75143
- exports.resolveLabelLink = resolveLabelLink;
75144
75629
  exports.resolveLocationIcon = resolveLocationIcon;
75145
75630
  exports.resolveLocationMode = resolveLocationMode;
75146
75631
  exports.resolveMethodAuth = resolveMethodAuth;
@@ -75149,12 +75634,15 @@ exports.resolveModeNotifyPolicy = resolveModeNotifyPolicy;
75149
75634
  exports.resolveMutate = resolveMutate;
75150
75635
  exports.resolvePoolMemoryPolicy = resolvePoolMemoryPolicy;
75151
75636
  exports.resolveRecordingProfiles = resolveRecordingProfiles;
75637
+ exports.resolveRootSupply = resolveRootSupply;
75152
75638
  exports.resolveRunnerId = resolveRunnerId;
75153
75639
  exports.resolveStreamMaps = require_composition.resolveStreamMaps;
75154
75640
  exports.resolveVariantModelId = resolveVariantModelId;
75155
75641
  exports.resolveViewableDeviceIds = resolveViewableDeviceIds;
75156
75642
  exports.roleSpec = roleSpec;
75157
75643
  exports.roomCompositionExample = roomCompositionExample;
75644
+ exports.rootSuppliesOf = rootSuppliesOf;
75645
+ exports.rootSupplyServes = rootSupplyServes;
75158
75646
  exports.ruleAutoTriggersAlarm = ruleAutoTriggersAlarm;
75159
75647
  exports.ruleBelongsToAlarm = ruleBelongsToAlarm;
75160
75648
  exports.ruleDeviceCompatCapNames = ruleDeviceCompatCapNames;
@@ -75224,6 +75712,7 @@ exports.strippedOfLegacyReadOnly = strippedOfLegacyReadOnly;
75224
75712
  exports.subKindsOf = subKindsOf;
75225
75713
  exports.summarisePrivacyAudio = summarisePrivacyAudio;
75226
75714
  exports.summarizeEffectiveScope = summarizeEffectiveScope;
75715
+ exports.supplyFor = supplyFor;
75227
75716
  exports.supportedRuntimes = supportedRuntimes;
75228
75717
  exports.switchCapability = switchCapability;
75229
75718
  exports.switchedOffIds = switchedOffIds;
@@ -75275,6 +75764,7 @@ exports.userPasskeysCapability = userPasskeysCapability;
75275
75764
  exports.vacuumControlCapability = vacuumControlCapability;
75276
75765
  exports.validateComposition = validateComposition;
75277
75766
  exports.validateExpressionSource = require_composition.validateExpressionSource;
75767
+ exports.validateHubAddressOverride = validateHubAddressOverride;
75278
75768
  exports.validateRecipeBounds = validateRecipeBounds;
75279
75769
  exports.valveCapability = valveCapability;
75280
75770
  exports.vectorDimFromBase64 = vectorDimFromBase64;