camstack 1.2.35 → 1.2.37

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.
@@ -15602,7 +15602,7 @@ var RecordingBandSchema = external_exports.object({
15602
15602
  postBufferSec: external_exports.number().min(0).optional()
15603
15603
  });
15604
15604
  var DEFAULT_EVENTS_BAND_BUFFER_SEC = {
15605
- preBufferSec: 10,
15605
+ preBufferSec: 15,
15606
15606
  postBufferSec: 30
15607
15607
  };
15608
15608
  var VISIT_MERGE_GAP_MS = DEFAULT_EVENTS_BAND_BUFFER_SEC.postBufferSec * 1e3;
@@ -22016,128 +22016,103 @@ var COCO_TO_MACRO = {
22016
22016
  var AUDIO_MACRO_LABELS = [
22017
22017
  {
22018
22018
  id: "speech",
22019
- name: "Speech",
22020
- icon: "\u{1F5E3}\uFE0F"
22019
+ name: "Speech"
22021
22020
  },
22022
22021
  {
22023
22022
  id: "scream",
22024
- name: "Scream / Shout",
22025
- icon: "\u{1F631}"
22023
+ name: "Scream / Shout"
22026
22024
  },
22027
22025
  {
22028
22026
  id: "crying",
22029
- name: "Crying / Baby",
22030
- icon: "\u{1F622}"
22027
+ name: "Crying / Baby"
22031
22028
  },
22032
22029
  {
22033
22030
  id: "laughter",
22034
- name: "Laughter",
22035
- icon: "\u{1F602}"
22031
+ name: "Laughter"
22036
22032
  },
22037
22033
  {
22038
22034
  id: "music",
22039
- name: "Music",
22040
- icon: "\u{1F3B5}"
22035
+ name: "Music"
22041
22036
  },
22042
22037
  {
22043
22038
  id: "dog",
22044
- name: "Dog",
22045
- icon: "\u{1F415}"
22039
+ name: "Dog"
22046
22040
  },
22047
22041
  {
22048
22042
  id: "cat",
22049
- name: "Cat",
22050
- icon: "\u{1F408}"
22043
+ name: "Cat"
22051
22044
  },
22052
22045
  {
22053
22046
  id: "bird",
22054
- name: "Bird",
22055
- icon: "\u{1F426}"
22047
+ name: "Bird"
22056
22048
  },
22057
22049
  {
22058
22050
  id: "animal",
22059
- name: "Animal (other)",
22060
- icon: "\u{1F43E}"
22051
+ name: "Animal (other)"
22061
22052
  },
22062
22053
  {
22063
22054
  id: "alarm",
22064
- name: "Alarm / Siren",
22065
- icon: "\u{1F6A8}"
22055
+ name: "Alarm / Siren"
22066
22056
  },
22067
22057
  {
22068
22058
  id: "doorbell",
22069
- name: "Doorbell / Knock",
22070
- icon: "\u{1F514}"
22059
+ name: "Doorbell / Knock"
22071
22060
  },
22072
22061
  {
22073
22062
  id: "glass_breaking",
22074
- name: "Glass Breaking",
22075
- icon: "\u{1F4A5}"
22063
+ name: "Glass Breaking"
22076
22064
  },
22077
22065
  {
22078
22066
  id: "gunshot",
22079
- name: "Gunshot / Explosion",
22080
- icon: "\u{1F4A3}"
22067
+ name: "Gunshot / Explosion"
22081
22068
  },
22082
22069
  {
22083
22070
  id: "vehicle",
22084
- name: "Vehicle",
22085
- icon: "\u{1F697}"
22071
+ name: "Vehicle"
22086
22072
  },
22087
22073
  {
22088
22074
  id: "siren",
22089
- name: "Emergency Siren",
22090
- icon: "\u{1F691}"
22075
+ name: "Emergency Siren"
22091
22076
  },
22092
22077
  {
22093
22078
  id: "fire",
22094
- name: "Fire / Smoke",
22095
- icon: "\u{1F525}"
22079
+ name: "Fire / Smoke"
22096
22080
  },
22097
22081
  {
22098
22082
  id: "water",
22099
- name: "Water",
22100
- icon: "\u{1F4A7}"
22083
+ name: "Water"
22101
22084
  },
22102
22085
  {
22103
22086
  id: "wind",
22104
- name: "Wind / Weather",
22105
- icon: "\u{1F32C}\uFE0F"
22087
+ name: "Wind / Weather"
22106
22088
  },
22107
22089
  {
22108
22090
  id: "door",
22109
- name: "Door",
22110
- icon: "\u{1F6AA}"
22091
+ name: "Door"
22111
22092
  },
22112
22093
  {
22113
22094
  id: "footsteps",
22114
- name: "Footsteps",
22115
- icon: "\u{1F463}"
22095
+ name: "Footsteps"
22116
22096
  },
22117
22097
  {
22118
22098
  id: "crowd",
22119
- name: "Crowd / Chatter",
22120
- icon: "\u{1F465}"
22099
+ name: "Crowd / Chatter"
22121
22100
  },
22122
22101
  {
22123
22102
  id: "telephone",
22124
- name: "Telephone",
22125
- icon: "\u{1F4DE}"
22103
+ name: "Telephone"
22126
22104
  },
22127
22105
  {
22128
22106
  id: "engine",
22129
- name: "Engine / Motor",
22130
- icon: "\u2699\uFE0F"
22107
+ name: "Engine / Motor"
22131
22108
  },
22132
22109
  {
22133
22110
  id: "tools",
22134
- name: "Tools / Construction",
22135
- icon: "\u{1F528}"
22111
+ name: "Tools / Construction"
22136
22112
  },
22137
22113
  {
22138
22114
  id: "silence",
22139
- name: "Silence",
22140
- icon: "\u{1F92B}"
22115
+ name: "Silence"
22141
22116
  }
22142
22117
  ];
22143
22118
  var YAMNET_TO_MACRO = {
@@ -24251,6 +24226,35 @@ var TrackSchema = external_exports.object({
24251
24226
  */
24252
24227
  hasFace: external_exports.boolean().optional(),
24253
24228
  /**
24229
+ * This track has a face row IN THE GALLERY: a crop **and** an embedding — a
24230
+ * face an operator could ASSIGN to an identity.
24231
+ *
24232
+ * The STRICT twin of {@link hasFace}, and the pair only earns its keep
24233
+ * because the two disagree. `hasFace` is stamped at the TOP of the face
24234
+ * branch, before every gate, and means no more than "a face detector produced
24235
+ * a face detail". This one is stamped at the single moment the gallery row
24236
+ * LANDS — after `FaceRecognizer.onTrackEnd` successfully persists it, i.e.
24237
+ * past the embedding-magnitude verdict, the `minFacePx` detection gate, the
24238
+ * candidate gate, the imageless-track drop (no crop was ever captured) and
24239
+ * the crop-store drop. Everything between the detector and that insert can
24240
+ * legitimately refuse the face, so a flag written any earlier promises the
24241
+ * operator something to assign and delivers nothing.
24242
+ *
24243
+ * **Independent of recognition.** A face collected but never auto-matched is
24244
+ * still assignable — it is in fact the face an operator most wants to reach —
24245
+ * so this is NOT gated on `recognizedIdentityId`. Recognition lands in
24246
+ * `subLabel`; this says only that the raw material exists.
24247
+ *
24248
+ * **Set once, never cleared.** A track that produced a gallery row produced
24249
+ * one; deleting the row later is the gallery's business, not this flag's.
24250
+ *
24251
+ * **Absent ≠ false**, the same rule as {@link hasFace}: every row written
24252
+ * before the column omits it, and so does every server that predates the
24253
+ * field. A consumer must test `=== true` and render nothing otherwise —
24254
+ * never infer "no assignable face".
24255
+ */
24256
+ hasEmbeddedFace: external_exports.boolean().optional(),
24257
+ /**
24254
24258
  * This subject CONTAINS a folded rider — a person the rider-pairing step
24255
24259
  * ([D34](../decisions/adr-0034.md)) removed from the frame BEFORE the tracker,
24256
24260
  * so the passage is tracked once and as a VEHICLE.
@@ -26011,6 +26015,32 @@ var DetailResultSchema = external_exports.object({
26011
26015
  /** FRAME-space bbox (already mapped back from crop space). */
26012
26016
  bbox: NativeCropBboxSchema.optional(),
26013
26017
  embedding: external_exports.string().optional(),
26018
+ /**
26019
+ * L2 magnitude of the RAW pre-normalization embedding. Additive and optional
26020
+ * so an older runner that does not send it degrades to "unmeasurable", which
26021
+ * the consuming gate treats as accept — never as reject.
26022
+ */
26023
+ embeddingMagnitude: external_exports.number().optional(),
26024
+ /**
26025
+ * Model that produced `embedding` — the SAME contract `labelModelId` has for
26026
+ * `label`, and for the same reason: the producing node is the only side that
26027
+ * knows which model actually ran, and re-deriving it downstream is exactly
26028
+ * the inference this model exists to forbid.
26029
+ *
26030
+ * Additive and optional, so a runner that predates it degrades to
26031
+ * "unmeasurable" rather than to a wrong answer — the consumer falls back to
26032
+ * its previous assumption instead of refusing.
26033
+ *
26034
+ * Its absence was not cosmetic. `FaceRecognizer` needs the probe's model id
26035
+ * to use `face-matcher`'s same-model gate (`sample.modelId !== probe.modelId`);
26036
+ * with nothing on the wire it took the id from the GALLERY, so the gate
26037
+ * compared the gallery against itself and could never fire. That turned the
26038
+ * one guard protecting the face feature space into a tautology, and it is
26039
+ * why swapping `face-embedding`'s model would NOT have stranded the enrolled
26040
+ * gallery as the catalog comment predicts — it would have scored the new
26041
+ * model's vectors against the old model's samples in one cosine space.
26042
+ */
26043
+ embeddingModelId: external_exports.string().optional(),
26014
26044
  label: external_exports.string().optional(),
26015
26045
  /**
26016
26046
  * The tier `label` occupies, copied VERBATIM from the producing step's
@@ -26987,6 +27017,13 @@ var CameraStatusSchema = external_exports.object({
26987
27017
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
26988
27018
  fetchedAt: external_exports.number()
26989
27019
  });
27020
+ var INFERENCE_DEVICE_EXCLUSION_REASONS = [
27021
+ "disabled",
27022
+ "unavailable",
27023
+ "cannot-host-camera-root",
27024
+ "accelerator-preferred"
27025
+ ];
27026
+ var InferenceDeviceExclusionReasonSchema = external_exports.enum(INFERENCE_DEVICE_EXCLUSION_REASONS);
26990
27027
  var NodeInferenceDeviceSchema = external_exports.object({
26991
27028
  /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
26992
27029
  key: external_exports.string(),
@@ -27017,7 +27054,17 @@ var NodeInferenceDeviceSchema = external_exports.object({
27017
27054
  * available per format; this is the stored selection that becomes the
27018
27055
  * default for EVERY camera landing on this accelerator.
27019
27056
  */
27020
- steps: external_exports.record(external_exports.string(), DeviceStepConfigSchema).optional()
27057
+ steps: external_exports.record(external_exports.string(), DeviceStepConfigSchema).optional(),
27058
+ /**
27059
+ * `null` when the device IS a camera-root candidate on this node; otherwise
27060
+ * the reason the dispatcher drops it. Computed by the SAME
27061
+ * `resolveInferenceDeviceEligibility` the dispatcher runs, so this view can
27062
+ * never disagree with the election — deriving it in the UI from
27063
+ * `enabled`/`available` would silently miss `cannot-host-camera-root` (needs
27064
+ * the node's model catalog) and `accelerator-preferred` (needs the node-wide
27065
+ * "an accelerator is serving" predicate).
27066
+ */
27067
+ exclusion: InferenceDeviceExclusionReasonSchema.nullable()
27021
27068
  });
27022
27069
  var NodeInferenceDevicesSchema = external_exports.object({
27023
27070
  nodeId: external_exports.string(),
@@ -27816,6 +27863,7 @@ var snapshotCapability = {
27816
27863
  isBattery: external_exports.boolean(),
27817
27864
  reason: external_exports.enum([
27818
27865
  "disabled",
27866
+ "offline",
27819
27867
  "sleeping",
27820
27868
  "unreachable",
27821
27869
  "waking"
@@ -27906,9 +27954,17 @@ var snapshotCapability = {
27906
27954
  sleeping: external_exports.boolean(),
27907
27955
  /** Current device state rendered over the cached frame. State images
27908
27956
  * remain authoritative even when their photographic background is
27909
- * old; null means the link must carry a current camera frame. */
27957
+ * old; null means the link must carry a current camera frame.
27958
+ *
27959
+ * **This is the ONLY source a surface may derive an inactive tile
27960
+ * from.** A client that reads a device's `online`/`disabled` flags and
27961
+ * draws its own verdict will disagree with the pixels it is painting
27962
+ * — the frame comes from here, and so must the sentence over it
27963
+ * (D190). Pair with `ageMs` for the age of the photograph behind the
27964
+ * state. */
27910
27965
  stateReason: external_exports.enum([
27911
27966
  "disabled",
27967
+ "offline",
27912
27968
  "sleeping",
27913
27969
  "unreachable",
27914
27970
  "waking"
@@ -32018,7 +32074,35 @@ var ConnectionEndpointSchema = external_exports.object({
32018
32074
  */
32019
32075
  priority: external_exports.number()
32020
32076
  });
32021
- var GetConnectionEndpointsResultSchema = external_exports.object({ endpoints: external_exports.array(ConnectionEndpointSchema).readonly() });
32077
+ var LocalPortSourceEnum = external_exports.enum([
32078
+ "server-config",
32079
+ "server-env",
32080
+ "caller-hint",
32081
+ "default"
32082
+ ]);
32083
+ var AdvertisedLocalPortSchema = external_exports.object({
32084
+ port: external_exports.number().int().min(1).max(65535),
32085
+ source: LocalPortSourceEnum
32086
+ });
32087
+ var GetConnectionEndpointsResultSchema = external_exports.object({
32088
+ endpoints: external_exports.array(ConnectionEndpointSchema).readonly(),
32089
+ /**
32090
+ * The port the hub built the LAN/loopback URLs with, and where that number
32091
+ * came from.
32092
+ *
32093
+ * Returned rather than merely applied, because "the URL is right" and "the
32094
+ * client can KNOW the URL is right" are different properties. A client that
32095
+ * only sees a corrected URL cannot distinguish a hub that fixed the port from
32096
+ * a hub that echoed the port the client sent, so it cannot decide whether to
32097
+ * race the candidate or discard it. With `source` it can: anything but
32098
+ * `caller-hint` is the hub's own socket.
32099
+ *
32100
+ * Absent on hubs predating this field — a client that finds it missing is
32101
+ * talking to an echoing hub and must degrade exactly as it does for
32102
+ * `caller-hint`.
32103
+ */
32104
+ localPort: AdvertisedLocalPortSchema
32105
+ });
32022
32106
  var NotificationEndpointSchema = external_exports.object({
32023
32107
  /** The operator's explicit choice, or null for AUTO. */
32024
32108
  baseUrl: external_exports.string().nullable(),
@@ -32060,10 +32144,35 @@ var localNetworkCapability = {
32060
32144
  * Honours `getAllowedAddresses()` when set — addresses outside
32061
32145
  * the allowlist are dropped (the public tunnel + loopback are
32062
32146
  * always included as escape hatches).
32147
+ *
32148
+ * **The port is the hub's, not the caller's** (D62 — a function's fact
32149
+ * belongs to whoever already owns it). This method used to take a `port`
32150
+ * and echo it onto every LAN and loopback URL it advertised, which made
32151
+ * every client a second authority on a socket only the hub binds. A viewer
32152
+ * configured with a port-less public URL (`https://camstack.example.top`)
32153
+ * infers 443 from the scheme, asks with 443, and was handed
32154
+ * `https://192.168.1.9:443` for a hub listening on 4443. That candidate
32155
+ * cannot ever answer, and losing its race reads in the log exactly like
32156
+ * "the LAN was tried and it was slower" — so an operator sitting on his own
32157
+ * WiFi stayed on the public tunnel for weeks, with the LAN candidate born
32158
+ * dead on every single connect.
32159
+ *
32160
+ * The hub now resolves its own listen port and reports it as `localPort`,
32161
+ * with the SOURCE of the number, so a client can tell a fact from an echo.
32162
+ *
32163
+ * Out of scope on purpose: a LAN URL that is not the hub's own socket (a
32164
+ * reverse proxy in front of it on another port) is not this method's to
32165
+ * invent either — pin it with `setNotificationEndpoint` / a configured
32166
+ * origin, which is an operator statement rather than a guess.
32063
32167
  */
32064
32168
  getConnectionEndpoints: method(external_exports.object({
32065
- /** Local hub HTTP port to use in base URLs. */
32066
- port: external_exports.number().int().min(1).max(65535),
32169
+ /**
32170
+ * LEGACY HINT — do not send from new code. Kept optional so clients
32171
+ * written against the echoing contract keep working; the hub uses it
32172
+ * only when it cannot read its own port, and says so via
32173
+ * `localPort.source === 'caller-hint'`.
32174
+ */
32175
+ port: external_exports.number().int().min(1).max(65535).optional(),
32067
32176
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
32068
32177
  * candidate. Default `true`. */
32069
32178
  includeLoopback: external_exports.boolean().optional(),
@@ -36554,6 +36663,7 @@ var BATTERY_DEVICE_PROFILE = {
36554
36663
  settings: {}
36555
36664
  };
36556
36665
  var BATTERY_UNREACHABLE_AFTER_MS = 360 * 6e4;
36666
+ var OPERATOR_WRITTEN_STALE_MS = 10 * 6e4;
36557
36667
  var METHOD_ACCESS_MAP = Object.freeze({
36558
36668
  "accessories.setChildHidden": {
36559
36669
  capName: "accessories",
@@ -43935,7 +44045,6 @@ var NC_AUDIO_DEFAULTS = {
43935
44045
  hitPercent: 60,
43936
44046
  samplingSeconds: 10
43937
44047
  };
43938
- var ICON_BY_ID = new Map(AUDIO_MACRO_LABELS.flatMap((macro2) => macro2.icon === void 0 ? [] : [[macro2.id, macro2.icon]]));
43939
44048
  var NC_BASE_CONDITION_KEYS = ["devices", "classes"];
43940
44049
  var BASE_CONDITION_SET = new Set(NC_BASE_CONDITION_KEYS);
43941
44050
  var NC_AUDIO_SEED = {
@@ -44053,6 +44162,40 @@ var TimelapseRuleSchema = TimelapseRuleInputSchema.extend({
44053
44162
  createdAt: external_exports.number(),
44054
44163
  updatedAt: external_exports.number()
44055
44164
  });
44165
+ var CLUSTER_MODEL_SCOPED_STEPS = [{
44166
+ stepId: "face-embedding",
44167
+ label: "Face recognition model",
44168
+ defaultModelId: "arcface-r100",
44169
+ indexName: "the enrolled face gallery",
44170
+ options: [
44171
+ {
44172
+ id: "arcface-r100",
44173
+ label: "ArcFace (ResNet34)"
44174
+ },
44175
+ {
44176
+ id: "auraface-r100",
44177
+ label: "AuraFace R100"
44178
+ },
44179
+ {
44180
+ id: "inception-resnet-v1",
44181
+ label: "Inception ResNet V1"
44182
+ }
44183
+ ]
44184
+ }, {
44185
+ stepId: "clip-embedding",
44186
+ label: "Semantic search model",
44187
+ defaultModelId: "mobileclip-s1",
44188
+ indexName: "the object semantic-search index",
44189
+ options: [{
44190
+ id: "mobileclip-s1",
44191
+ label: "MobileCLIP S1"
44192
+ }, {
44193
+ id: "mobileclip-s2",
44194
+ label: "MobileCLIP S2"
44195
+ }]
44196
+ }];
44197
+ var DEFAULT_CLUSTER_STEP_MODELS = Object.freeze(Object.fromEntries(CLUSTER_MODEL_SCOPED_STEPS.map((s) => [s.stepId, s.defaultModelId])));
44198
+ var ChosenModelIdSchema = external_exports.string().min(1);
44056
44199
  var DetailCropConventionSchema = external_exports.object({
44057
44200
  /**
44058
44201
  * Fraction of the box's own size added on EACH side before cutting.
@@ -44077,6 +44220,12 @@ var DEFAULT_DETAIL_CROP_CONVENTION = {
44077
44220
  paddingRatio: 0.15,
44078
44221
  square: false
44079
44222
  };
44223
+ var FULL_IMAGE_BBOX = Object.freeze({
44224
+ x: 0,
44225
+ y: 0,
44226
+ w: 1,
44227
+ h: 1
44228
+ });
44080
44229
  var DETAIL_CROP_PADDING_FIELD = {
44081
44230
  min: 0,
44082
44231
  max: 1,
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDiscover
4
- } from "./chunk-CJBTSCQF.js";
4
+ } from "./chunk-OR2CMMOE.js";
5
5
  import "./chunk-LMMQX4CK.js";
6
6
 
7
7
  // src/cli.ts
@@ -38,7 +38,7 @@ async function runServe(args) {
38
38
  ...typeof values.data === "string" ? { data: values.data } : {}
39
39
  };
40
40
  Object.assign(process.env, buildServeEnv(opts));
41
- await import("./launcher-IU5FZCJX.js");
41
+ await import("./launcher-6VDFMPM6.js");
42
42
  }
43
43
 
44
44
  // src/commands/agent.ts
@@ -83,7 +83,7 @@ async function runAgent(args) {
83
83
  ...typeof values.port === "string" ? { port: values.port } : {}
84
84
  };
85
85
  Object.assign(process.env, buildAgentEnv(opts));
86
- await import("./launcher-IU5FZCJX.js");
86
+ await import("./launcher-6VDFMPM6.js");
87
87
  }
88
88
 
89
89
  // src/commands/setup.ts
@@ -1130,7 +1130,7 @@ function isUnknown(_value) {
1130
1130
  return true;
1131
1131
  }
1132
1132
  async function resolveServerInteractive(presetNamespace) {
1133
- const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-HYDSUPIC.js");
1133
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-Y3C7HOBU.js");
1134
1134
  if (presetNamespace) {
1135
1135
  const spinner4 = clack.spinner();
1136
1136
  spinner4.start(`Discovering hub on LAN (namespace "${presetNamespace}")`);
@@ -5,7 +5,7 @@ import {
5
5
  filterHubNodes,
6
6
  resolveHubFromDiscovered,
7
7
  runDiscover
8
- } from "./chunk-CJBTSCQF.js";
8
+ } from "./chunk-OR2CMMOE.js";
9
9
  import "./chunk-LMMQX4CK.js";
10
10
  export {
11
11
  DEFAULT_HUB_HTTPS_PORT,