@camstack/system 1.2.364 → 1.2.366

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 (72) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/addon-utils.d.ts +1 -1
  4. package/dist/addon-utils.js +3 -1
  5. package/dist/addon-utils.mjs +2 -2
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  7. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  9. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  10. package/dist/builtins/alerts/alerts.addon.js +1 -1
  11. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  12. package/dist/builtins/autotrack/index.js +1 -1
  13. package/dist/builtins/autotrack/index.mjs +1 -1
  14. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  15. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  16. package/dist/builtins/calendars/calendars.addon.js +1 -1
  17. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  18. package/dist/builtins/camera-grid/index.js +1 -1
  19. package/dist/builtins/camera-grid/index.mjs +1 -1
  20. package/dist/builtins/composer/composer.addon.js +2 -2
  21. package/dist/builtins/composer/composer.addon.mjs +2 -2
  22. package/dist/builtins/console-logging/index.js +1 -1
  23. package/dist/builtins/console-logging/index.mjs +1 -1
  24. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  25. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  26. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  27. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  28. package/dist/builtins/hub-forwarder/index.js +1 -1
  29. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  30. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  31. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  32. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  33. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  34. package/dist/builtins/local-network/local-network.addon.js +1 -1
  35. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  36. package/dist/builtins/loki-logging/index.js +1 -1
  37. package/dist/builtins/loki-logging/index.mjs +1 -1
  38. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  39. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  40. package/dist/builtins/platform-probe/index.js +1 -1
  41. package/dist/builtins/platform-probe/index.mjs +1 -1
  42. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  43. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  44. package/dist/builtins/snapshot/index.js +1 -1
  45. package/dist/builtins/snapshot/index.mjs +1 -1
  46. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  47. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  48. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  49. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  50. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  51. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  52. package/dist/builtins/system-config/system-config.addon.js +1 -1
  53. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  54. package/dist/builtins/winston-logging/index.js +1 -1
  55. package/dist/builtins/winston-logging/index.mjs +1 -1
  56. package/dist/{child-cap-dispatch-B79ITdeA.js → child-cap-dispatch-D9uoEW2A.js} +1 -1
  57. package/dist/{child-cap-dispatch-CtBHqm2J.mjs → child-cap-dispatch-tHbRfy_7.mjs} +1 -1
  58. package/dist/{composition-sources-CNVBIV_9.js → composition-sources-AHfMboGi.js} +1 -1
  59. package/dist/{composition-sources-Dj84elbu.mjs → composition-sources-GjJ1QxMC.mjs} +1 -1
  60. package/dist/{dist-C-IdBSWx.mjs → dist-BUfYKaXx.mjs} +321 -14
  61. package/dist/{dist-DiScyAO6.js → dist-ub3muPSW.js} +338 -13
  62. package/dist/download/hosted-model-revisions.d.ts +10 -0
  63. package/dist/download/model-download-service.d.ts +8 -14
  64. package/dist/download/model-downloader.d.ts +44 -2
  65. package/dist/{event-loop-stall-monitor-NFG6boF5.mjs → event-loop-stall-monitor-CPI1xIcd.mjs} +300 -126
  66. package/dist/{event-loop-stall-monitor-CuTt1wq7.js → event-loop-stall-monitor-j0DRBkuI.js} +317 -125
  67. package/dist/index.d.ts +2 -2
  68. package/dist/index.js +6 -3
  69. package/dist/index.mjs +4 -4
  70. package/dist/{retired-settings-keys-CJpnYIp1.js → retired-settings-keys-DNCxYHe1.js} +1 -1
  71. package/dist/{retired-settings-keys-DIzyi9Jf.mjs → retired-settings-keys-Du41eTrH.mjs} +1 -1
  72. package/package.json +1 -1
@@ -7917,16 +7917,53 @@ var ModelFormatEntrySchema = zod.z.object({
7917
7917
  /** Runtime(s) that can use this format. If omitted, inferred from ModelFormat key */
7918
7918
  runtimes: zod.z.array(zod.z.enum(["python"])).readonly().optional(),
7919
7919
  /**
7920
- * Content revision of the hosted artefact. Set it, or change it, whenever
7921
- * the bytes at `url` are replaced in place (same path, new content). A node
7922
- * records the revision it downloaded next to the file
7920
+ * Content revision of the artefact, for one hosted OFF the CamStack mirror.
7921
+ * A format on the mirror leaves it unset: its revision (the sha256 of its
7922
+ * weight file) comes from the downloader's generated table, kept in step
7923
+ * with the mirror by `scripts/check-hosted-model-revisions.ts` (D744). A
7924
+ * node records the revision it downloaded next to the file
7923
7925
  * (`<file>.revision`); a copy with no record or a different one is stale
7924
- * and is downloaded again, the old copy serving until the new one is
7925
- * complete. Omitted ⇒ a file on disk is current, whatever it holds (D743).
7926
+ * unless its weight file hashes to the revision, and a stale copy is
7927
+ * downloaded again, the old one serving until the new one is complete. No
7928
+ * revision at all ⇒ a file on disk is current, whatever it holds (D743).
7926
7929
  */
7927
7930
  revision: zod.z.string().min(1).optional()
7928
7931
  });
7929
7932
  /**
7933
+ * What a node holds for one (model, format) (D746). `current` is a complete
7934
+ * copy at its catalog revision — exactly what `downloaded: true` means.
7935
+ * `stale` is bytes on disk that are not (yet) proven current under D743/D744:
7936
+ * no or a different revision record, or a missing sibling. `missing` is no
7937
+ * copy. `downloaded` alone folds `stale` into "not downloaded", which hid
7938
+ * reclaimable bytes and a copy about to be replaced.
7939
+ */
7940
+ var ModelOnDiskStateSchema = zod.z.enum([
7941
+ "current",
7942
+ "stale",
7943
+ "missing"
7944
+ ]);
7945
+ /**
7946
+ * The numeric precision of one format's BUILD (D746) — reported only when the
7947
+ * build states it (file-name token, an INT8 variant, an EdgeTPU compile, a
7948
+ * CamStack Core ML export). Absent means "not stated", never "fp32".
7949
+ */
7950
+ var ModelFormatPrecisionSchema = zod.z.enum([
7951
+ "fp32",
7952
+ "fp16",
7953
+ "int8"
7954
+ ]);
7955
+ /**
7956
+ * One format of one model as a node's `pipelineExecutor.getSchema` reports it.
7957
+ * `onDisk` / `precision` are optional for version skew: a runner that predates
7958
+ * them omits them, and a reader falls back to `downloaded`.
7959
+ */
7960
+ var PipelineModelFormatStatusSchema = zod.z.object({
7961
+ downloaded: zod.z.boolean(),
7962
+ sizeMB: zod.z.number(),
7963
+ onDisk: ModelOnDiskStateSchema.optional(),
7964
+ precision: ModelFormatPrecisionSchema.optional()
7965
+ });
7966
+ /**
7930
7967
  * Extra file that must be downloaded alongside the model (e.g., labels JSON, dict.txt).
7931
7968
  * The downloader fetches from `url` and saves to `{modelsDir}/{filename}`.
7932
7969
  */
@@ -25966,7 +26003,7 @@ var FrameRefSchema = zod.z.object({
25966
26003
  timestamp: zod.z.number(),
25967
26004
  capturedAt: zod.z.number().optional()
25968
26005
  });
25969
- var ModelFormatSchema$1 = zod.z.enum([
26006
+ var ModelFormatSchema$2 = zod.z.enum([
25970
26007
  "onnx",
25971
26008
  "coreml",
25972
26009
  "openvino",
@@ -25984,7 +26021,7 @@ var PipelineSlotSchema = zod.z.enum([
25984
26021
  var PipelineEngineChoiceSchema = zod.z.object({
25985
26022
  runtime: zod.z.literal("python"),
25986
26023
  backend: zod.z.string(),
25987
- format: ModelFormatSchema$1,
26024
+ format: ModelFormatSchema$2,
25988
26025
  device: zod.z.string().optional()
25989
26026
  });
25990
26027
  /**
@@ -26042,10 +26079,7 @@ var PipelineTemplateSchema$1 = zod.z.object({
26042
26079
  var PipelineModelOptionSchema = zod.z.object({
26043
26080
  id: zod.z.string(),
26044
26081
  name: zod.z.string(),
26045
- formats: zod.z.record(zod.z.string(), zod.z.object({
26046
- downloaded: zod.z.boolean(),
26047
- sizeMB: zod.z.number()
26048
- })),
26082
+ formats: zod.z.record(zod.z.string(), PipelineModelFormatStatusSchema),
26049
26083
  group: ModelVariantGroupSchema.optional(),
26050
26084
  legacy: zod.z.boolean().optional(),
26051
26085
  provider: ModelProviderIdSchema.optional(),
@@ -26260,6 +26294,32 @@ var pipelineExecutorCapability = {
26260
26294
  auth: "admin"
26261
26295
  }),
26262
26296
  /**
26297
+ * Best settings (D745): the MODEL-BOUND thresholds (`bindsToModel` keys of
26298
+ * the object-detection root, and their binding keys) stored in THIS node's
26299
+ * per-camera detector settings — and, unless `dryRun`, remove them so the
26300
+ * running model's own defaults apply. Every other key of a camera's store
26301
+ * is kept. `nodeId` is the ROUTING key. `deviceIds` absent ⇒ every camera
26302
+ * with a store. A camera whose store could not be read is `refused`, never
26303
+ * reported as clean.
26304
+ */
26305
+ clearModelBoundDeviceOverrides: method(zod.z.object({
26306
+ nodeId: zod.z.string(),
26307
+ deviceIds: zod.z.array(zod.z.number()).readonly().optional(),
26308
+ dryRun: zod.z.boolean()
26309
+ }), zod.z.object({
26310
+ entries: zod.z.array(zod.z.object({
26311
+ deviceId: zod.z.number(),
26312
+ keys: zod.z.array(zod.z.string()).readonly()
26313
+ })).readonly(),
26314
+ refused: zod.z.array(zod.z.object({
26315
+ deviceId: zod.z.number(),
26316
+ reason: zod.z.string()
26317
+ })).readonly()
26318
+ }), {
26319
+ kind: "mutation",
26320
+ auth: "admin"
26321
+ }),
26322
+ /**
26263
26323
  * Which of THIS node's inference devices the executor currently refuses,
26264
26324
  * and why. `nodeId` is the ROUTING key (stripped by the generated router).
26265
26325
  *
@@ -26354,12 +26414,12 @@ var pipelineExecutorCapability = {
26354
26414
  downloadModel: method(zod.z.object({
26355
26415
  addonId: zod.z.string(),
26356
26416
  modelId: zod.z.string(),
26357
- format: ModelFormatSchema$1
26417
+ format: ModelFormatSchema$2
26358
26418
  }), DownloadModelResultSchema, { kind: "mutation" }),
26359
26419
  deleteModel: method(zod.z.object({
26360
26420
  addonId: zod.z.string(),
26361
26421
  modelId: zod.z.string(),
26362
- format: ModelFormatSchema$1
26422
+ format: ModelFormatSchema$2
26363
26423
  }), zod.z.object({ success: zod.z.literal(true) }), { kind: "mutation" }),
26364
26424
  /**
26365
26425
  * Stateless single-frame execution. Callers (runner, benchmark) pass
@@ -26605,6 +26665,204 @@ var pipelineExecutorCapability = {
26605
26665
  getDetectionConfigSchema: method(zod.z.void(), ConfigUISchemaNullableBridge)
26606
26666
  }
26607
26667
  };
26668
+ /**
26669
+ * The wire shapes of the Best settings plan and apply (D745), used by the
26670
+ * `pipeline-orchestrator` cap. The recommender's own types
26671
+ * (`recommend.ts`, `demand.ts`) are the TS face of the same data; these
26672
+ * schemas are what crosses the cap boundary.
26673
+ */
26674
+ var ModelFormatSchema$1 = zod.z.enum(MODEL_FORMATS);
26675
+ var HardwareClassIdSchema = zod.z.enum([
26676
+ "intel-core-ultra",
26677
+ "intel-n-series",
26678
+ "apple-m-base",
26679
+ "apple-m-pro",
26680
+ "unknown"
26681
+ ]);
26682
+ var AcceleratorKindSchema = zod.z.enum([
26683
+ "intel-npu",
26684
+ "intel-igpu",
26685
+ "x86-cpu",
26686
+ "arm-cpu",
26687
+ "apple-ane",
26688
+ "coral"
26689
+ ]);
26690
+ var RecommendationReasonSchema = zod.z.discriminatedUnion("kind", [
26691
+ zod.z.object({
26692
+ kind: zod.z.literal("fits"),
26693
+ utilisation: zod.z.number()
26694
+ }),
26695
+ zod.z.object({
26696
+ kind: zod.z.literal("tie-faster"),
26697
+ over: zod.z.string(),
26698
+ recallDelta: zod.z.number()
26699
+ }),
26700
+ zod.z.object({
26701
+ kind: zod.z.literal("stepped-down"),
26702
+ from: zod.z.string(),
26703
+ to: zod.z.string(),
26704
+ limitedBy: zod.z.string()
26705
+ }),
26706
+ zod.z.object({
26707
+ kind: zod.z.literal("no-fit-lightest"),
26708
+ utilisation: zod.z.number()
26709
+ }),
26710
+ zod.z.object({
26711
+ kind: zod.z.literal("derived-latency"),
26712
+ modelId: zod.z.string()
26713
+ }),
26714
+ zod.z.object({
26715
+ kind: zod.z.literal("estimated-load"),
26716
+ observedForMs: zod.z.number().nullable()
26717
+ }),
26718
+ zod.z.object({ kind: zod.z.literal("cpu-device") }),
26719
+ zod.z.object({ kind: zod.z.literal("coral-untouched") }),
26720
+ zod.z.object({ kind: zod.z.literal("device-disabled") }),
26721
+ zod.z.object({ kind: zod.z.literal("device-unavailable") }),
26722
+ zod.z.object({ kind: zod.z.literal("node-offline") }),
26723
+ zod.z.object({ kind: zod.z.literal("no-hardware-facts") }),
26724
+ zod.z.object({
26725
+ kind: zod.z.literal("no-measured-data"),
26726
+ hardwareClass: HardwareClassIdSchema
26727
+ }),
26728
+ zod.z.object({
26729
+ kind: zod.z.literal("no-family-build"),
26730
+ format: ModelFormatSchema$1
26731
+ })
26732
+ ]);
26733
+ var DeviceDemandSchema = zod.z.object({
26734
+ nodeId: zod.z.string(),
26735
+ deviceKey: zod.z.string(),
26736
+ demandFps: zod.z.number(),
26737
+ maxCameraFps: zod.z.number(),
26738
+ alwaysOnCameras: zod.z.number(),
26739
+ onMotionSessions: zod.z.number(),
26740
+ onMotionSource: zod.z.enum([
26741
+ "observed-24h",
26742
+ "estimate",
26743
+ "none"
26744
+ ]),
26745
+ observedForMs: zod.z.number().nullable()
26746
+ });
26747
+ var DeviceModelChoiceSchema = zod.z.object({
26748
+ modelId: zod.z.string(),
26749
+ p50Ms: zod.z.number(),
26750
+ fps: zod.z.number(),
26751
+ measured: zod.z.boolean(),
26752
+ utilisation: zod.z.number(),
26753
+ personRecall: zod.z.number()
26754
+ });
26755
+ var DeviceRecommendationSchema = zod.z.object({
26756
+ deviceKey: zod.z.string(),
26757
+ accelerator: AcceleratorKindSchema.nullable(),
26758
+ enabled: zod.z.boolean(),
26759
+ available: zod.z.boolean(),
26760
+ demand: DeviceDemandSchema.nullable(),
26761
+ chosen: DeviceModelChoiceSchema.nullable(),
26762
+ reasons: zod.z.array(RecommendationReasonSchema).readonly()
26763
+ });
26764
+ var NodeRecommendationSchema = zod.z.object({
26765
+ nodeId: zod.z.string(),
26766
+ reachable: zod.z.boolean(),
26767
+ hardwareClass: HardwareClassIdSchema.nullable(),
26768
+ cpuModel: zod.z.string().nullable(),
26769
+ skipped: zod.z.boolean(),
26770
+ acceleratorModelId: zod.z.string().nullable(),
26771
+ devices: zod.z.array(DeviceRecommendationSchema).readonly(),
26772
+ reasons: zod.z.array(RecommendationReasonSchema).readonly()
26773
+ });
26774
+ var ModelPinChangeSchema = zod.z.object({
26775
+ stepId: zod.z.string(),
26776
+ before: zod.z.string().nullable(),
26777
+ after: zod.z.string().nullable()
26778
+ });
26779
+ var NodeDeviceChangeSchema = zod.z.object({
26780
+ nodeId: zod.z.string(),
26781
+ deviceKey: zod.z.string(),
26782
+ madeExplicit: zod.z.boolean(),
26783
+ modelPins: zod.z.array(ModelPinChangeSchema).readonly(),
26784
+ thresholds: zod.z.array(zod.z.object({
26785
+ stepId: zod.z.string(),
26786
+ keys: zod.z.array(zod.z.string()).readonly()
26787
+ })).readonly()
26788
+ });
26789
+ var CameraOverrideClearSchema = zod.z.object({
26790
+ deviceId: zod.z.number(),
26791
+ source: zod.z.enum(["step-override", "wholesale"]),
26792
+ nodeId: zod.z.string(),
26793
+ deviceKey: zod.z.string().nullable(),
26794
+ stepId: zod.z.string(),
26795
+ modelIdBefore: zod.z.string().nullable(),
26796
+ keys: zod.z.array(zod.z.string()).readonly()
26797
+ });
26798
+ var DetectorStoreClearSchema = zod.z.object({
26799
+ deviceId: zod.z.number(),
26800
+ keys: zod.z.array(zod.z.string()).readonly()
26801
+ });
26802
+ var BestSettingsWarningSchema = zod.z.discriminatedUnion("kind", [
26803
+ zod.z.object({
26804
+ kind: zod.z.literal("detector-store-cluster-wide"),
26805
+ skippedNodes: zod.z.array(zod.z.string()).readonly()
26806
+ }),
26807
+ zod.z.object({
26808
+ kind: zod.z.literal("detector-store-unreadable"),
26809
+ error: zod.z.string()
26810
+ }),
26811
+ zod.z.object({
26812
+ kind: zod.z.literal("coral-enabled"),
26813
+ nodeId: zod.z.string(),
26814
+ deviceKey: zod.z.string()
26815
+ })
26816
+ ]);
26817
+ var BestSettingsOptionsSchema = zod.z.object({
26818
+ /** Share of each accelerator's throughput kept free (0.3–0.5). */
26819
+ headroom: zod.z.number().min(.3).max(.5).default(.4) });
26820
+ var BestSettingsPlanSchema = zod.z.object({
26821
+ /** Hash of everything the apply will write — the apply refuses a different one. */
26822
+ planHash: zod.z.string(),
26823
+ family: zod.z.literal("yolov9"),
26824
+ headroom: zod.z.number(),
26825
+ generatedAt: zod.z.number(),
26826
+ nodes: zod.z.array(NodeRecommendationSchema).readonly(),
26827
+ nodeChanges: zod.z.array(NodeDeviceChangeSchema).readonly(),
26828
+ cameraClears: zod.z.array(CameraOverrideClearSchema).readonly(),
26829
+ detectorStoreClears: zod.z.array(DetectorStoreClearSchema).readonly(),
26830
+ warnings: zod.z.array(BestSettingsWarningSchema).readonly()
26831
+ });
26832
+ var BestSettingsApplyInputSchema = zod.z.object({
26833
+ planHash: zod.z.string(),
26834
+ headroom: zod.z.number().min(.3).max(.5).default(.4)
26835
+ });
26836
+ var BestSettingsPhaseResultSchema = zod.z.object({
26837
+ phase: zod.z.enum([
26838
+ "download",
26839
+ "camera-overrides",
26840
+ "detector-thresholds",
26841
+ "node-models",
26842
+ "redispatch"
26843
+ ]),
26844
+ ok: zod.z.boolean(),
26845
+ detail: zod.z.string()
26846
+ });
26847
+ var BestSettingsApplyResultSchema = zod.z.discriminatedUnion("kind", [
26848
+ zod.z.object({
26849
+ kind: zod.z.literal("applied"),
26850
+ planHash: zod.z.string(),
26851
+ phases: zod.z.array(BestSettingsPhaseResultSchema).readonly()
26852
+ }),
26853
+ zod.z.object({
26854
+ kind: zod.z.literal("aborted"),
26855
+ phases: zod.z.array(BestSettingsPhaseResultSchema).readonly()
26856
+ }),
26857
+ zod.z.object({
26858
+ kind: zod.z.literal("stale"),
26859
+ plan: BestSettingsPlanSchema
26860
+ }),
26861
+ zod.z.object({
26862
+ kind: zod.z.literal("refused"),
26863
+ reason: zod.z.enum(["apply-in-progress"])
26864
+ })
26865
+ ]);
26608
26866
  zod.z.object({
26609
26867
  activeCameras: zod.z.number(),
26610
26868
  throttledCameras: zod.z.number(),
@@ -28825,6 +29083,27 @@ var pipelineOrchestratorCapability = {
28825
29083
  kind: "mutation",
28826
29084
  auth: "admin"
28827
29085
  }),
29086
+ /**
29087
+ * Best settings (D745) — DRY RUN. Recommends ONE detector family (YOLOv9)
29088
+ * for the whole cluster from each node's static hardware class, the
29089
+ * measured latency table and the detection demand, and lists every write
29090
+ * the apply would make: the node model pins set, the enrichment pins and
29091
+ * model-bound thresholds removed (node level and per camera), and the
29092
+ * per-camera detector thresholds cleared. Writes nothing. Step
29093
+ * enablement, device enablement, pins, recording, notifications, zones and
29094
+ * rules are never part of it. `planHash` names exactly this diff.
29095
+ */
29096
+ planBestSettings: method(BestSettingsOptionsSchema, BestSettingsPlanSchema, { auth: "admin" }),
29097
+ /**
29098
+ * Best settings (D745) — APPLY the plan the operator confirmed. Recomputes
29099
+ * the plan and refuses (`stale`, with the fresh plan) when its hash is not
29100
+ * `planHash`, so what is written is exactly the confirmed diff. Offline
29101
+ * nodes are skipped; there is no undo.
29102
+ */
29103
+ applyBestSettings: method(BestSettingsApplyInputSchema, BestSettingsApplyResultSchema, {
29104
+ kind: "mutation",
29105
+ auth: "admin"
29106
+ }),
28828
29107
  /** Read one camera's settings. Null when never touched (inherits agent defaults fully). */
28829
29108
  getCameraSettings: method(zod.z.object({ deviceId: zod.z.number() }), CameraPipelineSettingsSchema.nullable()),
28830
29109
  /** Set or clear the 3-state toggle for one (camera, addonId). Pass `enabled: null` to clear and revert to agent default. */
@@ -45922,6 +46201,8 @@ Object.freeze({
45922
46201
  vehicle: .65,
45923
46202
  animal: .65
45924
46203
  });
46204
+ var HF_REPO = "camstack/camstack-models";
46205
+ `${HF_REPO}`;
45925
46206
  /**
45926
46207
  * Runtime defaults -- used by ConfigManager.get() for backward compatibility
45927
46208
  * until Plan B wires all runtime settings to the system_settings SQL table.
@@ -51783,6 +52064,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
51783
52064
  addonId: null,
51784
52065
  access: "delete"
51785
52066
  },
52067
+ "pipelineExecutor.clearModelBoundDeviceOverrides": {
52068
+ capName: "pipeline-executor",
52069
+ capScope: "system",
52070
+ addonId: null,
52071
+ access: "delete"
52072
+ },
51786
52073
  "pipelineExecutor.deleteModel": {
51787
52074
  capName: "pipeline-executor",
51788
52075
  capScope: "system",
@@ -51999,6 +52286,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
51999
52286
  addonId: null,
52000
52287
  access: "view"
52001
52288
  },
52289
+ "pipelineOrchestrator.applyBestSettings": {
52290
+ capName: "pipeline-orchestrator",
52291
+ capScope: "system",
52292
+ addonId: null,
52293
+ access: "create"
52294
+ },
52002
52295
  "pipelineOrchestrator.applyDeviceSettingsPatch": {
52003
52296
  capName: "pipeline-orchestrator",
52004
52297
  capScope: "system",
@@ -52173,6 +52466,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
52173
52466
  addonId: null,
52174
52467
  access: "create"
52175
52468
  },
52469
+ "pipelineOrchestrator.planBestSettings": {
52470
+ capName: "pipeline-orchestrator",
52471
+ capScope: "system",
52472
+ addonId: null,
52473
+ access: "view"
52474
+ },
52176
52475
  "pipelineOrchestrator.rebalance": {
52177
52476
  capName: "pipeline-orchestrator",
52178
52477
  capScope: "system",
@@ -57850,6 +58149,11 @@ Object.freeze({
57850
58149
  form: "single",
57851
58150
  optional: false
57852
58151
  }],
58152
+ "pipelineExecutor.clearModelBoundDeviceOverrides": [{
58153
+ name: "deviceIds",
58154
+ form: "array",
58155
+ optional: true
58156
+ }],
57853
58157
  "pipelineExecutor.runPipeline": [{
57854
58158
  name: "deviceId",
57855
58159
  form: "single",
@@ -60200,6 +60504,9 @@ var ADDON_ID_PREFIX = "addon:";
60200
60504
  function bareAddonId(id) {
60201
60505
  return id.startsWith(ADDON_ID_PREFIX) ? id.slice(6) : id;
60202
60506
  }
60507
+ function hfModelUrl(repo, path) {
60508
+ return `https://huggingface.co/${repo}/resolve/main/${path}`;
60509
+ }
60203
60510
  var MB = 1024 * 1024;
60204
60511
  1024 * MB, 3072 * MB;
60205
60512
  /**
@@ -60532,6 +60839,12 @@ Object.defineProperty(exports, "FieldClaimSchema", {
60532
60839
  return FieldClaimSchema;
60533
60840
  }
60534
60841
  });
60842
+ Object.defineProperty(exports, "HF_REPO", {
60843
+ enumerable: true,
60844
+ get: function() {
60845
+ return HF_REPO;
60846
+ }
60847
+ });
60535
60848
  Object.defineProperty(exports, "LOG_LEVEL_RANK", {
60536
60849
  enumerable: true,
60537
60850
  get: function() {
@@ -60562,6 +60875,12 @@ Object.defineProperty(exports, "MINUTES_PER_DAY", {
60562
60875
  return MINUTES_PER_DAY;
60563
60876
  }
60564
60877
  });
60878
+ Object.defineProperty(exports, "MODEL_FORMATS", {
60879
+ enumerable: true,
60880
+ get: function() {
60881
+ return MODEL_FORMATS;
60882
+ }
60883
+ });
60565
60884
  Object.defineProperty(exports, "MOTION_CLOSE_AFTER_MS", {
60566
60885
  enumerable: true,
60567
60886
  get: function() {
@@ -61042,6 +61361,12 @@ Object.defineProperty(exports, "gbToBytes", {
61042
61361
  return gbToBytes;
61043
61362
  }
61044
61363
  });
61364
+ Object.defineProperty(exports, "hfModelUrl", {
61365
+ enumerable: true,
61366
+ get: function() {
61367
+ return hfModelUrl;
61368
+ }
61369
+ });
61045
61370
  Object.defineProperty(exports, "hydrateSchema", {
61046
61371
  enumerable: true,
61047
61372
  get: function() {
@@ -0,0 +1,10 @@
1
+ /**
2
+ * GENERATED by `scripts/check-hosted-model-revisions.ts --write` — DO NOT EDIT.
3
+ *
4
+ * The revision of every artefact on the CamStack model mirror, keyed by its
5
+ * path under `https://huggingface.co/camstack/camstack-models/resolve/main/`: the sha256 (`lfs.oid`)
6
+ * of its weight file (`revisionWeightUrl`). `resolveFormatRevision` reads
7
+ * it for every catalog format hosted there (D743, D744). Regenerate after
8
+ * any upload to the mirror; the script without `--write` says when it is due.
9
+ */
10
+ export declare const HOSTED_MODEL_REVISIONS: Readonly<Record<string, string>>;
@@ -1,10 +1,12 @@
1
1
  import { ModelCatalogEntry, ModelFormat, IAddonModelManager } from '@camstack/types';
2
2
  /**
3
- * Unified model download service.
3
+ * A catalog-bound face over the shared downloader.
4
4
  *
5
- * Handles downloading model files and extra files (labels, dicts) from a
6
- * catalog of ModelCatalogEntry items. Supports single-file models and
7
- * directory bundles (e.g., .mlpackage for CoreML).
5
+ * Downloading, completeness and the revision contract (D743) are
6
+ * `ensureModel` / `isModelDownloaded`'s — this class only resolves a model id
7
+ * (and a default format) against its catalog and keys progress by model id.
8
+ * It used to carry its own copy of the download loop, which never learnt the
9
+ * revision; one rule now lives in one place.
8
10
  *
9
11
  * Addons use this via `context.models.ensure(modelId, format)`.
10
12
  */
@@ -14,7 +16,7 @@ export declare class ModelDownloadService implements IAddonModelManager {
14
16
  private readonly catalog;
15
17
  constructor(modelsDir: string, catalog: readonly ModelCatalogEntry[], onProgress?: ((modelId: string, downloaded: number, total: number) => void) | undefined);
16
18
  /**
17
- * Ensure a model (and its extra files) is downloaded.
19
+ * Ensure a model (and its extra files) is downloaded and current.
18
20
  * Returns the local filesystem path to the model file/directory.
19
21
  */
20
22
  ensure(modelId: string, format?: ModelFormat): Promise<string>;
@@ -25,17 +27,9 @@ export declare class ModelDownloadService implements IAddonModelManager {
25
27
  ensureExtraFiles(modelId: string): Promise<readonly string[]>;
26
28
  /** Absolute path to the shared models directory. */
27
29
  getModelsDir(): string;
28
- /** Check if a model file is already present on disk. */
30
+ /** True when the model is on disk, complete, and at its revision (D743). */
29
31
  isDownloaded(modelId: string, format?: ModelFormat): boolean;
30
32
  /** Get the catalog entry for a model by ID. */
31
33
  getEntry(modelId: string): ModelCatalogEntry | undefined;
32
34
  private pickDefaultFormat;
33
- private modelFilePath;
34
- /**
35
- * Download a directory bundle (e.g., .mlpackage) from HuggingFace.
36
- * ATOMIC: downloads to temp dir, renames only on complete success.
37
- */
38
- private downloadDirectory;
39
- /** Recursively list all files in a HuggingFace directory via API. */
40
- private listHfFiles;
41
35
  }
@@ -79,18 +79,60 @@ export type DownloadProgressCallback = (downloaded: number, total: number | unde
79
79
  * bundle, so a `.mlpackage` keeps exactly the hosted files.
80
80
  */
81
81
  export declare function revisionRecordPath(modelPath: string): string;
82
+ /** The CamStack model mirror. Every artefact under it has a generated revision. */
83
+ export declare const HOSTED_MODEL_MIRROR_PREFIX: string;
84
+ /**
85
+ * The revision a format must be at — the ONE rule every model download path
86
+ * reads (D743, D744). An inline `revision` wins; otherwise a format hosted on
87
+ * the CamStack mirror takes the revision generated for its path from the
88
+ * mirror's LFS metadata (`hosted-model-revisions.ts`); anything else has none.
89
+ */
90
+ export declare function resolveFormatRevision(formatEntry: ModelFormatEntry): string | undefined;
91
+ /**
92
+ * The file whose sha256 IS a format's revision: a Core ML package's
93
+ * `weight.bin`, an OpenVINO IR's `.bin` sibling, otherwise the file itself.
94
+ * `null` for a bundle that is not a Core ML package (nothing to hash).
95
+ */
96
+ export type RevisionWeightFile = {
97
+ readonly in: 'bundle';
98
+ readonly member: string;
99
+ } | {
100
+ readonly in: 'sibling';
101
+ readonly name: string;
102
+ } | {
103
+ readonly in: 'main';
104
+ };
105
+ export declare function revisionWeightFile(formatEntry: ModelFormatEntry): RevisionWeightFile | null;
106
+ /** Where the revision's weight file is hosted — what the mirror's `lfs.oid` describes. */
107
+ export declare function revisionWeightUrl(formatEntry: ModelFormatEntry): string | null;
82
108
  /**
83
109
  * Resolve a `ModelCatalogEntry` against `modelsDir`: download model file
84
110
  * (or directory bundle) + extra files (labels JSON, charset dict, …),
85
111
  * skip if already on disk. Returns the local model path.
86
112
  */
87
113
  export declare function ensureModel(modelsDir: string, entry: ModelCatalogEntry, format: ModelFormat, onProgress?: DownloadProgressCallback): Promise<string>;
114
+ /** What {@link adoptModelRevisions} found: `<modelId>/<format>` keys. */
115
+ export interface ModelRevisionAdoption {
116
+ /** Copies proven current by hash and recorded — no download needed. */
117
+ readonly adopted: readonly string[];
118
+ /** Complete copies holding other bytes — `ensureModel` fetches them again. */
119
+ readonly stale: readonly string[];
120
+ }
121
+ /**
122
+ * Walk `entries` and record the revision of every complete copy on disk that
123
+ * hashes to it, so a node's listing reports present models as downloaded
124
+ * without waiting for something to `ensureModel` them. Offline: it reads
125
+ * files and never fetches. A copy already recorded current is not re-hashed.
126
+ */
127
+ export declare function adoptModelRevisions(modelsDir: string, entries: readonly ModelCatalogEntry[]): Promise<ModelRevisionAdoption>;
88
128
  /** Compute the on-disk path for a given model + format, even when not yet downloaded. */
89
129
  export declare function getModelFilePath(modelsDir: string, entry: ModelCatalogEntry, format: ModelFormat): string | null;
90
130
  /**
91
131
  * True iff the model file (or `Manifest.json` for directory bundles) exists and
92
- * is non-empty, and — when the catalog names a `revision` — the node recorded
93
- * that same revision for it (D743).
132
+ * is non-empty, and — when the format has a revision ({@link
133
+ * resolveFormatRevision}) — the node recorded that same revision for it
134
+ * (D743). Synchronous, so it never hashes: a copy not yet proven current
135
+ * answers false until `ensureModel` or {@link adoptModelRevisions} records it.
94
136
  */
95
137
  export declare function isModelDownloaded(modelsDir: string, entry: ModelCatalogEntry, format: ModelFormat): boolean;
96
138
  /** Remove the on-disk model file/directory. Returns true if something was deleted. */