@camstack/addon-post-analysis 1.1.27 → 1.1.29

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.
@@ -4308,6 +4308,14 @@ function object(shape, params) {
4308
4308
  ...normalizeParams(params)
4309
4309
  });
4310
4310
  }
4311
+ function looseObject(shape, params) {
4312
+ return new ZodObject({
4313
+ type: "object",
4314
+ shape,
4315
+ catchall: unknown(),
4316
+ ...normalizeParams(params)
4317
+ });
4318
+ }
4311
4319
  var ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => {
4312
4320
  $ZodUnion.init(inst, def);
4313
4321
  ZodType.init(inst, def);
@@ -4649,7 +4657,7 @@ function _instanceof(cls, params = {}) {
4649
4657
  return inst;
4650
4658
  }
4651
4659
  //#endregion
4652
- //#region ../types/dist/sleep-Baang_XW.mjs
4660
+ //#region ../types/dist/sleep-_sv7WKkq.mjs
4653
4661
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4654
4662
  EventCategory["SystemBoot"] = "system.boot";
4655
4663
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -5059,10 +5067,51 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
5059
5067
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
5060
5068
  EventCategory["EnrichmentSceneStateChanged"] = "enrichment.scene.state-changed";
5061
5069
  EventCategory["EnrichmentActivitySummary"] = "enrichment.activity.summary";
5070
+ /**
5071
+ * Unified track-lifecycle event: ONE category carrying `phase:
5072
+ * 'start' | 'update' | 'end'` with a rich, typed
5073
+ * `PipelineAnalyticsTrackLifecyclePayload`. Supersedes the thin
5074
+ * `PipelineAnalyticsTrackStarted` / `PipelineAnalyticsTrackEnded`
5075
+ * pair — a consumer subscribes once and branches on `phase`.
5076
+ */
5077
+ EventCategory["PipelineAnalyticsTrackLifecycle"] = "pipeline-analytics.track-lifecycle";
5078
+ /**
5079
+ * @deprecated Superseded by {@link PipelineAnalyticsTrackLifecycle}
5080
+ * (`phase:'start'`). Kept as a soft alias — no known subscribers.
5081
+ */
5062
5082
  EventCategory["PipelineAnalyticsTrackStarted"] = "pipeline-analytics.track-started";
5083
+ /**
5084
+ * @deprecated Superseded by {@link PipelineAnalyticsTrackLifecycle}
5085
+ * (`phase:'end'`). Kept as a soft alias — no known subscribers.
5086
+ */
5063
5087
  EventCategory["PipelineAnalyticsTrackEnded"] = "pipeline-analytics.track-ended";
5064
5088
  EventCategory["PipelineAnalyticsDetectionEvent"] = "pipeline-analytics.detection-event";
5065
5089
  EventCategory["PipelineAnalyticsFrameTracked"] = "pipeline-analytics.frame-tracked";
5090
+ /**
5091
+ * Fired by `addon-post-analysis` when a parked (stationary) object appears
5092
+ * (a track was promoted to a stationary-registry entry) or departs (the
5093
+ * object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
5094
+ * the dedicated "Stationary" section — never the live event feed. Payload:
5095
+ * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
5096
+ */
5097
+ EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
5098
+ /**
5099
+ * Fired by `addon-post-analysis` whenever a gallery face row changes:
5100
+ * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
5101
+ * `'unassigned'` its identity link changed, `'deleted'` the row was
5102
+ * removed. Telemetry semantics (D8): a lost event only delays a refresh,
5103
+ * never a correctness issue. Payload `PipelineAnalyticsFaceGalleryChangedPayload`.
5104
+ */
5105
+ EventCategory["PipelineAnalyticsFaceGalleryChanged"] = "pipeline-analytics.face-gallery-changed";
5106
+ /**
5107
+ * Fired by `addon-post-analysis` whenever a gallery plate row changes:
5108
+ * `kind:'buffered'` a new read was persisted (`PlateRecognizer.onTrackEnd`),
5109
+ * `'assigned'` / `'unassigned'` its vehicle link changed
5110
+ * (`PlateGalleryProvider`), `'deleted'` the row was removed. Telemetry
5111
+ * semantics (D8): a lost event only delays a refresh, never a correctness
5112
+ * issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
5113
+ */
5114
+ EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
5066
5115
  EventCategory["FrigateLiveEvent"] = "frigate.live-event";
5067
5116
  EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
5068
5117
  /**
@@ -6380,11 +6429,6 @@ var ProfileRtspEntrySchema = object({
6380
6429
  codec: string().optional(),
6381
6430
  resolution: CamStreamResolutionSchema.optional()
6382
6431
  });
6383
- /** Narrow an unknown value to a plain `Record<string, unknown>` or return null. */
6384
- function asJsonObject(value) {
6385
- if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
6386
- return { ...value };
6387
- }
6388
6432
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
6389
6433
  DeviceType["Camera"] = "camera";
6390
6434
  DeviceType["Hub"] = "hub";
@@ -6908,7 +6952,8 @@ var MODEL_FORMATS = [
6908
6952
  "coreml",
6909
6953
  "openvino",
6910
6954
  "tflite",
6911
- "pt"
6955
+ "pt",
6956
+ "gguf"
6912
6957
  ];
6913
6958
  /**
6914
6959
  * Multi-file format payload.
@@ -6952,7 +6997,8 @@ var ModelFormatsSchema = object({
6952
6997
  coreml: ModelFormatEntrySchema.optional(),
6953
6998
  openvino: ModelFormatEntrySchema.optional(),
6954
6999
  tflite: ModelFormatEntrySchema.optional(),
6955
- pt: ModelFormatEntrySchema.optional()
7000
+ pt: ModelFormatEntrySchema.optional(),
7001
+ gguf: ModelFormatEntrySchema.optional()
6956
7002
  });
6957
7003
  /**
6958
7004
  * Variant-selector grouping axes. Shared by the full `ModelCatalogEntry` and by
@@ -6993,6 +7039,15 @@ var ModelCatalogEntrySchema = object({
6993
7039
  width: number(),
6994
7040
  height: number()
6995
7041
  }),
7042
+ /**
7043
+ * Channel count of the model input tensor. Omit ⇒ 3 (RGB), the default for
7044
+ * every detector / classifier / embedder. Set to 1 for a grayscale CTC text
7045
+ * recognizer (EasyOCR VGG plate-OCR: input `[N,1,H,W]`) so the preprocess
7046
+ * feeds a single-channel, EasyOCR-normalized tensor instead of the default
7047
+ * 3-channel RGB one. Threaded through `PoolModelConfig.inputChannels` to the
7048
+ * Python inference pool.
7049
+ */
7050
+ inputChannels: number().int().positive().optional(),
6996
7051
  labels: array(LabelDefinitionSchema).readonly(),
6997
7052
  inputLayout: _enum(["nchw", "nhwc"]).optional(),
6998
7053
  inputNormalization: _enum([
@@ -7002,6 +7057,16 @@ var ModelCatalogEntrySchema = object({
7002
7057
  ]).optional(),
7003
7058
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7004
7059
  /**
7060
+ * Per-MODEL postprocessor override. Absent ⇒ the step's own
7061
+ * `StepDefinition.postprocessor` applies (the normal case — every model in a
7062
+ * step shares its decode). Set it when a step hosts models with DIFFERENT raw
7063
+ * output layouts under one slot: e.g. object-detection is `'yolo'` by default,
7064
+ * but a Coral SSD MobileNet build emits the `TFLite_Detection_PostProcess`
7065
+ * 4-tensor layout and needs `'ssd'`. Threaded into `PoolModelConfig.postprocessor`
7066
+ * by the engine factory (`modelEntry.postprocessor ?? def.postprocessor`).
7067
+ */
7068
+ postprocessor: custom().optional(),
7069
+ /**
7005
7070
  * When true, the executor produces a landmark-aligned crop (similarity warp
7006
7071
  * onto the canonical template) before this step runs, instead of a plain
7007
7072
  * axis-aligned bbox crop. Required for face-recognition embedders (ArcFace):
@@ -10542,7 +10607,8 @@ var ModelFormatSchema$1 = _enum([
10542
10607
  "coreml",
10543
10608
  "openvino",
10544
10609
  "tflite",
10545
- "pt"
10610
+ "pt",
10611
+ "gguf"
10546
10612
  ]);
10547
10613
  var PipelineSlotSchema = _enum([
10548
10614
  "detector",
@@ -10636,7 +10702,8 @@ var EngineProvisioningSchema = object({
10636
10702
  runtimeId: _enum([
10637
10703
  "onnx",
10638
10704
  "openvino",
10639
- "coreml"
10705
+ "coreml",
10706
+ "edgetpu"
10640
10707
  ]).nullable(),
10641
10708
  device: string().nullable(),
10642
10709
  state: _enum([
@@ -11848,6 +11915,140 @@ DeviceType.Camera, method(object({ deviceId: number() }), PtzAutotrackStatusSche
11848
11915
  deviceId: number(),
11849
11916
  status: PtzAutotrackStatusSchema
11850
11917
  });
11918
+ /**
11919
+ * scene-monitor — device-scoped reference-region state cap. An operator marks
11920
+ * a rect ROI on a camera frame and names one or more states; the engine
11921
+ * (pipeline-analytics, designated post-processing node) reports which state is
11922
+ * active on an ongoing basis. Two operator-selectable check modes share every-
11923
+ * thing except the comparator: `similarity` (CLIP cosine at the same ROI coords
11924
+ * vs condition-tagged references) and `llm` (vision-LLM judgment over the crop).
11925
+ *
11926
+ * D14 device-config archetype (`deviceConfig.ui.kind:'widget'`) — the framework
11927
+ * derives the device-detail contribution; the provider carries NO hand-written
11928
+ * settings-contribution methods. `status.kind:'push'` — the engine pushes on
11929
+ * every hysteresis flip / availability change; consumers never poll.
11930
+ */
11931
+ /** Extensible condition tag. Seeded 'day' | 'night'; open by design so more can
11932
+ * be added without a wire break (matching falls back to any-condition refs). */
11933
+ var SceneConditionSchema = string();
11934
+ /** One captured reference — condition-tagged, model-version-gated. `embedding`
11935
+ * is `number[]` (Float32Array does NOT survive MsgPack/UDS). */
11936
+ var SceneReferenceSchema = object({
11937
+ embedding: array(number()),
11938
+ modelId: string(),
11939
+ condition: SceneConditionSchema,
11940
+ capturedAt: number(),
11941
+ thumbnailMediaId: string().optional()
11942
+ });
11943
+ var SceneMonitorStateSchema = object({
11944
+ id: string(),
11945
+ label: string(),
11946
+ references: array(SceneReferenceSchema),
11947
+ textPrompts: array(string()).optional(),
11948
+ referenceCount: number(),
11949
+ currentlyMatched: boolean()
11950
+ });
11951
+ /** Per-mode comparator params in a discriminated union so an `llm` scene never
11952
+ * carries similarity knobs and vice-versa. */
11953
+ var SceneCheckSchema = discriminatedUnion("mode", [object({
11954
+ mode: literal("similarity"),
11955
+ threshold: number().min(0).max(1),
11956
+ hysteresisCount: number().int().positive()
11957
+ }), object({
11958
+ mode: literal("llm"),
11959
+ prompt: string(),
11960
+ profileId: string().optional(),
11961
+ hysteresisCount: number().int().positive()
11962
+ })]);
11963
+ var SceneMonitorSchema = object({
11964
+ id: string(),
11965
+ label: string(),
11966
+ roi: MaskRectShapeSchema,
11967
+ enabled: boolean(),
11968
+ triggerMode: _enum([
11969
+ "periodic",
11970
+ "on-motion",
11971
+ "both"
11972
+ ]),
11973
+ checkIntervalSec: number().optional(),
11974
+ check: SceneCheckSchema,
11975
+ states: array(SceneMonitorStateSchema),
11976
+ currentStateId: string().nullable(),
11977
+ lastCheckedAt: number().nullable(),
11978
+ lastConfidence: number().nullable(),
11979
+ currentCondition: SceneConditionSchema.nullable(),
11980
+ availability: _enum(["ok", "unavailable"]),
11981
+ unavailableReason: string().nullable()
11982
+ });
11983
+ var SceneMonitorStatusSchema = object({
11984
+ monitors: array(SceneMonitorSchema),
11985
+ lastFetchedAt: number()
11986
+ });
11987
+ DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({
11988
+ deviceId: number(),
11989
+ label: string(),
11990
+ roi: MaskRectShapeSchema,
11991
+ check: SceneCheckSchema,
11992
+ triggerMode: _enum([
11993
+ "periodic",
11994
+ "on-motion",
11995
+ "both"
11996
+ ]).optional(),
11997
+ checkIntervalSec: number().optional()
11998
+ }), SceneMonitorSchema, {
11999
+ kind: "mutation",
12000
+ auth: "admin"
12001
+ }), method(object({
12002
+ deviceId: number(),
12003
+ monitorId: string(),
12004
+ patch: object({
12005
+ label: string().optional(),
12006
+ roi: MaskRectShapeSchema.optional(),
12007
+ enabled: boolean().optional(),
12008
+ triggerMode: _enum([
12009
+ "periodic",
12010
+ "on-motion",
12011
+ "both"
12012
+ ]).optional(),
12013
+ checkIntervalSec: number().optional(),
12014
+ check: SceneCheckSchema.optional()
12015
+ })
12016
+ }), _void(), {
12017
+ kind: "mutation",
12018
+ auth: "admin"
12019
+ }), method(object({
12020
+ deviceId: number(),
12021
+ monitorId: string()
12022
+ }), _void(), {
12023
+ kind: "mutation",
12024
+ auth: "admin"
12025
+ }), method(object({
12026
+ deviceId: number(),
12027
+ monitorId: string(),
12028
+ stateId: string().optional(),
12029
+ label: string().optional(),
12030
+ condition: SceneConditionSchema.optional()
12031
+ }), object({
12032
+ stateId: string(),
12033
+ referenceCount: number()
12034
+ }), {
12035
+ kind: "mutation",
12036
+ auth: "admin"
12037
+ }), method(object({
12038
+ deviceId: number(),
12039
+ monitorId: string(),
12040
+ stateId: string(),
12041
+ index: number()
12042
+ }), _void(), {
12043
+ kind: "mutation",
12044
+ auth: "admin"
12045
+ }), method(object({
12046
+ deviceId: number(),
12047
+ monitorId: string()
12048
+ }), _void(), {
12049
+ kind: "mutation",
12050
+ auth: "admin"
12051
+ });
11851
12052
  object({
11852
12053
  /** Whether the script is currently executing. */
11853
12054
  isRunning: boolean(),
@@ -12255,6 +12456,36 @@ var ZoneScopeBreakdownSchema = PerScopeBreakdownSchema.extend({
12255
12456
  * with the per-track detail panel and live overlay. */
12256
12457
  trackIds: array(string()).readonly()
12257
12458
  });
12459
+ /**
12460
+ * A parked ("stationary") object surfaced alongside occupancy — an object that
12461
+ * settled and stopped moving. It is NO LONGER a tracked object (the tracker was
12462
+ * told to forget it so it stops re-spawning tracks/events), but it IS still
12463
+ * physically present, so it keeps counting toward `frame` occupancy and is
12464
+ * listed here so the UI can show it in a dedicated "Stationary" section instead
12465
+ * of flooding the live event feed.
12466
+ */
12467
+ var StationaryObjectSchema = object({
12468
+ id: string(),
12469
+ className: string(),
12470
+ bbox: object({
12471
+ x: number(),
12472
+ y: number(),
12473
+ w: number(),
12474
+ h: number()
12475
+ }),
12476
+ frameWidth: number().int().nonnegative(),
12477
+ frameHeight: number().int().nonnegative(),
12478
+ /** When the source track was first seen. */
12479
+ firstSeenAt: number().int(),
12480
+ /** When the object was recognised as parked (promotion time). */
12481
+ becameStationaryAt: number().int(),
12482
+ /** Last frame a detection confirmed the object is still there. */
12483
+ lastConfirmedAt: number().int(),
12484
+ /** Enrichment label carried from the source track (identity / plate). */
12485
+ label: string().optional(),
12486
+ /** Native-resolution key-frame media key for the parked object's best image. */
12487
+ keyFrameMediaKey: string().optional()
12488
+ });
12258
12489
  var CameraOccupancySnapshotSchema = object({
12259
12490
  /** Frame timestamp of the inference result that produced this snapshot. */
12260
12491
  ts: number().int(),
@@ -12263,10 +12494,15 @@ var CameraOccupancySnapshotSchema = object({
12263
12494
  frameHeight: number().int().nonnegative(),
12264
12495
  /** Per-zone breakdown — one entry per defined zone (user + onboard). */
12265
12496
  zones: array(ZoneScopeBreakdownSchema).readonly(),
12266
- /** Frame-wide aggregate (everywhere, regardless of zone membership). */
12497
+ /** Frame-wide aggregate (everywhere, regardless of zone membership).
12498
+ * INCLUDES currently-confirmed stationary objects (they are still present). */
12267
12499
  frame: PerScopeBreakdownSchema,
12268
12500
  /** Detections that landed outside every zone. Empty when no zones defined. */
12269
- unzoned: PerScopeBreakdownSchema
12501
+ unzoned: PerScopeBreakdownSchema,
12502
+ /** Parked objects on this camera (additive — absent on legacy snapshots).
12503
+ * Surfaced separately so the UI shows them in a dedicated section rather
12504
+ * than as repeated tracks/events. */
12505
+ stationaryObjects: array(StationaryObjectSchema).readonly().optional()
12270
12506
  });
12271
12507
  /**
12272
12508
  * Time-series resolution. The history methods return one bucket per
@@ -12924,7 +13160,12 @@ var NotificationRuleConditionsSchema = object({
12924
13160
  clipDescription: object({
12925
13161
  text: string().min(1),
12926
13162
  minSimilarity: number().min(0).max(1)
12927
- }).optional()
13163
+ }).optional(),
13164
+ /** Match events whose recognized-entity label (face identity name or plate
13165
+ * vehicle name, propagated onto `event.data.label`) is one of these values.
13166
+ * Empty/absent → unaffected (back-compat). Enables "notify me when <named
13167
+ * vehicle/person> is seen". */
13168
+ labels: array(string()).readonly().optional()
12928
13169
  });
12929
13170
  var NotificationRuleTemplateSchema = object({
12930
13171
  title: string(),
@@ -13182,11 +13423,19 @@ method(object({
13182
13423
  * login page needs NO change.
13183
13424
  *
13184
13425
  * - `widget` — a Module-Federation widget the login page mounts (via
13185
- * `loadRemoteBundle`) for an in-page ceremony. Covers the passkey
13186
- * login ceremony, which must run `@simplewebauthn/browser` INSIDE the
13187
- * addon bundle. The referenced widget also declares `preAuth: true` in
13188
- * its `addon-widgets-source` catalog entry. `auth.listLoginMethods`
13189
- * stamps a public `bundleUrl` from `addonId` + `bundle`.
13426
+ * `loadRemoteBundle`) for an in-page ceremony. `auth.listLoginMethods`
13427
+ * stamps a public `bundleUrl` from `addonId` + `bundle`. Generic
13428
+ * mechanism kept for future use; no shipped addon uses it on the login
13429
+ * page (the passkey ceremony below runs natively in the shell instead).
13430
+ *
13431
+ * - `passkey` — a declarative WebAuthn ceremony the shell renders
13432
+ * natively (`@simplewebauthn/browser` lives in `addon-admin-ui`, not in
13433
+ * a remotely-loaded bundle). Carries the addon's effective `rpId` /
13434
+ * `origin` (from its `resolveRpID()` / `resolveOrigin()`) so the shell
13435
+ * can gate visibility (IP-literal origin, hostname/rpId mismatch) WITHOUT
13436
+ * fetching any remote code pre-auth. Contribution stays unconditional —
13437
+ * enrollment state is never leaked pre-auth; visibility is a shell
13438
+ * decision.
13190
13439
  *
13191
13440
  * Every contribution carries a `stage`:
13192
13441
  * - `primary` — shown on the first credentials screen (OIDC /
@@ -13200,30 +13449,45 @@ method(object({
13200
13449
  */
13201
13450
  /** When a login method renders in the two-phase login flow. */
13202
13451
  var LoginStageEnum = _enum(["primary", "second-factor"]);
13203
- /** One login-method contribution — redirect button OR pre-auth widget. */
13204
- var LoginMethodContributionSchema = discriminatedUnion("kind", [object({
13205
- kind: literal("redirect"),
13206
- /** Stable id within the login-method set (e.g. `auth-oidc/google`). */
13207
- id: string(),
13208
- /** Operator-facing button label. */
13209
- label: string(),
13210
- /** lucide-react icon name. */
13211
- icon: string().optional(),
13212
- /** Addon-owned HTTP route the button navigates to (GET). */
13213
- startUrl: string(),
13214
- stage: LoginStageEnum
13215
- }), object({
13216
- kind: literal("widget"),
13217
- /** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
13218
- id: string(),
13219
- /** Owning addon id drives the public bundle URL + the MF namespace. */
13220
- addonId: string(),
13221
- /** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
13222
- bundle: string(),
13223
- /** MF remote descriptor `{ remoteName, exposedModule, componentKey }`. */
13224
- remote: WidgetRemoteSchema,
13225
- stage: LoginStageEnum
13226
- })]);
13452
+ /** One login-method contribution — redirect button, pre-auth widget, or native passkey ceremony. */
13453
+ var LoginMethodContributionSchema = discriminatedUnion("kind", [
13454
+ object({
13455
+ kind: literal("redirect"),
13456
+ /** Stable id within the login-method set (e.g. `auth-oidc/google`). */
13457
+ id: string(),
13458
+ /** Operator-facing button label. */
13459
+ label: string(),
13460
+ /** lucide-react icon name. */
13461
+ icon: string().optional(),
13462
+ /** Addon-owned HTTP route the button navigates to (GET). */
13463
+ startUrl: string(),
13464
+ stage: LoginStageEnum
13465
+ }),
13466
+ object({
13467
+ kind: literal("widget"),
13468
+ /** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
13469
+ id: string(),
13470
+ /** Owning addon id — drives the public bundle URL + the MF namespace. */
13471
+ addonId: string(),
13472
+ /** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
13473
+ bundle: string(),
13474
+ /** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
13475
+ remote: WidgetRemoteSchema,
13476
+ stage: LoginStageEnum
13477
+ }),
13478
+ object({
13479
+ kind: literal("passkey"),
13480
+ /** Stable id within the login-method set (e.g. `auth-webauthn/passkey-direct-login`). */
13481
+ id: string(),
13482
+ /** Operator-facing button label. */
13483
+ label: string(),
13484
+ stage: LoginStageEnum,
13485
+ /** Effective WebAuthn RP ID (`resolveRpID()`) — the shell gates visibility on it. */
13486
+ rpId: string(),
13487
+ /** Effective expected origin (`resolveOrigin()`), null when unconfigured. */
13488
+ origin: string().nullable()
13489
+ })
13490
+ ]);
13227
13491
  method(_void(), array(LoginMethodContributionSchema).readonly());
13228
13492
  /**
13229
13493
  * Orchestrator-side destination metadata. The orchestrator computes
@@ -15061,14 +15325,14 @@ var TargetKindCapsSchema = object({
15061
15325
  * the union is large and not meant for runtime validation here; the exported
15062
15326
  * `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
15063
15327
  */
15064
- var ConfigSchemaPassthrough = unknown();
15328
+ var ConfigSchemaPassthrough$1 = unknown();
15065
15329
  var TargetKindSchema = object({
15066
15330
  kind: string(),
15067
15331
  label: string(),
15068
15332
  icon: string(),
15069
15333
  /** Stamped by each provider so the concat-fanned catalog stays routable. */
15070
15334
  addonId: string(),
15071
- configSchema: ConfigSchemaPassthrough,
15335
+ configSchema: ConfigSchemaPassthrough$1,
15072
15336
  supportsDiscovery: boolean(),
15073
15337
  caps: TargetKindCapsSchema
15074
15338
  });
@@ -15121,6 +15385,298 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
15121
15385
  enabled: boolean()
15122
15386
  }), _void(), { kind: "mutation" });
15123
15387
  /**
15388
+ * Shared LLM generate contracts — imported by BOTH `llm.cap.ts` (consumer
15389
+ * surface) and `llm-runtime.cap.ts` (node-side managed executor) so the two
15390
+ * caps stay wire-compatible without a circular cap→cap import.
15391
+ *
15392
+ * Errors are a discriminated-union RESULT, never thrown: the shape survives
15393
+ * every transport tier structurally, and failed calls still write usage rows.
15394
+ * Token counts only in v1 — no costUsd (operator decision, 2026-07-15).
15395
+ */
15396
+ var LlmUsageSchema = object({
15397
+ inputTokens: number(),
15398
+ outputTokens: number()
15399
+ });
15400
+ var LlmErrorCodeSchema = _enum([
15401
+ "timeout",
15402
+ "rate-limited",
15403
+ "auth",
15404
+ "refusal",
15405
+ "bad-request",
15406
+ "unavailable",
15407
+ "no-profile",
15408
+ "budget-exceeded",
15409
+ "adapter-error"
15410
+ ]);
15411
+ var LlmGenerateResultSchema = discriminatedUnion("ok", [object({
15412
+ ok: literal(true),
15413
+ text: string(),
15414
+ model: string(),
15415
+ usage: LlmUsageSchema,
15416
+ truncated: boolean(),
15417
+ latencyMs: number()
15418
+ }), object({
15419
+ ok: literal(false),
15420
+ code: LlmErrorCodeSchema,
15421
+ message: string(),
15422
+ retryAfterMs: number().optional()
15423
+ })]);
15424
+ /**
15425
+ * `Uint8Array` is the sanctioned binary convention — superjson + the UDS
15426
+ * MsgPack channel round-trip typed arrays (embedding-encoder.cap.ts:29,
15427
+ * notification-output.cap.ts:27-31 precedents).
15428
+ */
15429
+ var LlmImageSchema = object({
15430
+ bytes: _instanceof(Uint8Array),
15431
+ mimeType: string()
15432
+ });
15433
+ var LlmGenerateBaseInputSchema = object({
15434
+ /** Collection routing (the notification-output posture). */
15435
+ addonId: string().optional(),
15436
+ /** Explicit profile; else the resolution chain (spec §3). */
15437
+ profileId: string().optional(),
15438
+ /** MANDATORY usage tag: 'ai-summary', 'notifier-rules', 'adhoc-ui', … */
15439
+ consumer: string(),
15440
+ system: string().optional(),
15441
+ /** v1: single-turn. `messages[]` is a v2 additive field. */
15442
+ prompt: string(),
15443
+ /** Structured output — adapter-mapped (response_format / forced tool / responseSchema). */
15444
+ jsonSchema: record(string(), unknown()).optional(),
15445
+ /** Per-call override of the profile default. */
15446
+ maxTokens: number().int().positive().optional(),
15447
+ temperature: number().optional()
15448
+ });
15449
+ /**
15450
+ * `llm-runtime` — node-side managed llama.cpp executor (spec §4). Registered
15451
+ * on EVERY node where `addon-ai` is installed; the hub `llm` provider reaches
15452
+ * a specific node's runtime with `nodePin(profile.runtime.nodeId)` — normal
15453
+ * cap routing, zero bespoke plumbing. `internal: true`: the operator reaches
15454
+ * this only through the `llm` cap's methods.
15455
+ *
15456
+ * One running llama-server child per node in v1 (models are RAM-heavy).
15457
+ * Resource ceiling = llama-server flags + idleStopMinutes ONLY (no RSS
15458
+ * watchdog — operator decision #3).
15459
+ */
15460
+ var ManagedModelRefSchema = discriminatedUnion("kind", [
15461
+ object({
15462
+ kind: literal("catalog"),
15463
+ catalogId: string()
15464
+ }),
15465
+ object({
15466
+ kind: literal("url"),
15467
+ url: string(),
15468
+ sha256: string().optional()
15469
+ }),
15470
+ object({
15471
+ kind: literal("path"),
15472
+ path: string()
15473
+ })
15474
+ ]);
15475
+ var ManagedRuntimeConfigSchema = object({
15476
+ /** WHERE the runtime lives — hub or any agent. */
15477
+ nodeId: string(),
15478
+ /** Closed for v1; 'ollama' is a v2 candidate. */
15479
+ engine: _enum(["llama-cpp"]),
15480
+ model: ManagedModelRefSchema,
15481
+ contextSize: number().int().default(4096),
15482
+ /** 0 = CPU-only. */
15483
+ gpuLayers: number().int().default(0),
15484
+ /** Default: cpus-2, clamped ≥1 (resolved node-side). */
15485
+ threads: number().int().optional(),
15486
+ /** Concurrent slots. */
15487
+ parallel: number().int().default(1),
15488
+ /** Else lazy: first generate boots it. */
15489
+ autoStart: boolean().default(false),
15490
+ /** 0 = never; frees RAM after quiet periods. */
15491
+ idleStopMinutes: number().int().default(30)
15492
+ });
15493
+ var LlmRuntimeStatusSchema = object({
15494
+ /** Status is ALWAYS node-qualified. */
15495
+ nodeId: string(),
15496
+ state: _enum([
15497
+ "stopped",
15498
+ "downloading",
15499
+ "starting",
15500
+ "ready",
15501
+ "crashed",
15502
+ "failed"
15503
+ ]),
15504
+ pid: number().optional(),
15505
+ port: number().optional(),
15506
+ modelPath: string().optional(),
15507
+ modelId: string().optional(),
15508
+ downloadProgress: number().min(0).max(1).optional(),
15509
+ lastError: string().optional(),
15510
+ crashesInWindow: number(),
15511
+ /** Child RSS (sampled best-effort). */
15512
+ memoryBytes: number().optional(),
15513
+ vramBytes: number().optional()
15514
+ });
15515
+ var LlmNodeModelSchema = object({
15516
+ file: string(),
15517
+ sizeBytes: number(),
15518
+ catalogId: string().optional(),
15519
+ installedAt: number().optional()
15520
+ });
15521
+ var LlmRuntimeDiskUsageSchema = object({
15522
+ nodeId: string(),
15523
+ modelsBytes: number(),
15524
+ freeBytes: number().optional()
15525
+ });
15526
+ method(LlmGenerateBaseInputSchema.extend({
15527
+ images: array(LlmImageSchema).optional(),
15528
+ runtime: ManagedRuntimeConfigSchema,
15529
+ /** The managed profile's timeout, threaded by the hub provider. */
15530
+ timeoutMs: number().int().positive().optional()
15531
+ }), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
15532
+ kind: "mutation",
15533
+ auth: "admin"
15534
+ }), method(object({}), _void(), {
15535
+ kind: "mutation",
15536
+ auth: "admin"
15537
+ }), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
15538
+ kind: "mutation",
15539
+ auth: "admin"
15540
+ }), method(object({ file: string() }), _void(), {
15541
+ kind: "mutation",
15542
+ auth: "admin"
15543
+ }), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
15544
+ /**
15545
+ * `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
15546
+ * methods concat-fan across providers; single-row methods route to ONE
15547
+ * provider by the `addonId` in the call input (the notification-output
15548
+ * posture, notification-output.cap.ts:215-250). Provided by `addon-ai`
15549
+ * (hub-placed); the cap stays open for future providers.
15550
+ *
15551
+ * Profiles are ROWS (data), not addons: one row = one usable model endpoint.
15552
+ * `apiKey` is a password field — providers REDACT it on read and merge on
15553
+ * write; a stored key NEVER round-trips to a client.
15554
+ */
15555
+ var LlmProfileKindSchema = _enum([
15556
+ "openai-compatible",
15557
+ "openai",
15558
+ "anthropic",
15559
+ "google",
15560
+ "managed-local"
15561
+ ]);
15562
+ var LlmProfileSchema = object({
15563
+ id: string(),
15564
+ name: string(),
15565
+ kind: LlmProfileKindSchema,
15566
+ /** Stamped by the provider — keeps the fanned catalog routable. */
15567
+ addonId: string(),
15568
+ enabled: boolean(),
15569
+ /** Vendor model id, or the managed runtime's loaded model. */
15570
+ model: string(),
15571
+ /** Required for openai-compatible; override for cloud kinds. */
15572
+ baseUrl: string().optional(),
15573
+ /** ConfigUISchema type:'password' — never round-trips (spec §5). */
15574
+ apiKey: string().optional(),
15575
+ supportsVision: boolean(),
15576
+ temperature: number().min(0).max(2).optional(),
15577
+ maxTokens: number().int().positive().optional(),
15578
+ timeoutMs: number().int().positive().default(6e4),
15579
+ extraHeaders: record(string(), string()).optional(),
15580
+ /** kind === 'managed-local' only (spec §4). */
15581
+ runtime: ManagedRuntimeConfigSchema.optional()
15582
+ });
15583
+ /** ConfigUISchema tree passed through untyped on the wire (the
15584
+ * notification-output `ConfigSchemaPassthrough` precedent at
15585
+ * notification-output.cap.ts:151); the exported TS type re-tightens it. */
15586
+ var ConfigSchemaPassthrough = unknown();
15587
+ var LlmProfileKindDescriptorSchema = object({
15588
+ kind: LlmProfileKindSchema,
15589
+ label: string(),
15590
+ icon: string(),
15591
+ /** Stamped by each provider so the concat-fanned catalog stays routable. */
15592
+ addonId: string(),
15593
+ configSchema: ConfigSchemaPassthrough
15594
+ });
15595
+ var LlmDefaultSelectorSchema = union([object({ consumer: string() }), object({ purpose: _enum(["text", "vision"]) })]);
15596
+ var LlmDefaultSchema = object({
15597
+ selector: LlmDefaultSelectorSchema,
15598
+ profileId: string()
15599
+ });
15600
+ /** Server-side rollup row — getUsage never dumps raw call rows (spec §6). */
15601
+ var LlmUsageRollupSchema = object({
15602
+ day: string(),
15603
+ consumer: string(),
15604
+ profileId: string(),
15605
+ calls: number(),
15606
+ okCalls: number(),
15607
+ errorCalls: number(),
15608
+ inputTokens: number(),
15609
+ outputTokens: number(),
15610
+ avgLatencyMs: number()
15611
+ });
15612
+ /** LLM-facing view over the reused ModelCatalogEntry mechanism (spec §4.2). */
15613
+ var ManagedModelCatalogEntrySchema = object({
15614
+ id: string(),
15615
+ label: string(),
15616
+ family: string(),
15617
+ purpose: _enum(["text", "vision"]),
15618
+ url: string(),
15619
+ sha256: string(),
15620
+ sizeBytes: number(),
15621
+ quantization: string(),
15622
+ /** Load-time guidance shown in the picker. */
15623
+ minRamBytes: number(),
15624
+ contextSizeDefault: number().int(),
15625
+ /** Vision models: companion projector file. */
15626
+ mmprojUrl: string().optional()
15627
+ });
15628
+ var LlmRuntimeNodeSchema = object({
15629
+ nodeId: string(),
15630
+ reachable: boolean(),
15631
+ status: LlmRuntimeStatusSchema.optional(),
15632
+ disk: LlmRuntimeDiskUsageSchema.optional(),
15633
+ error: string().optional()
15634
+ });
15635
+ var GenerateVisionInputSchema = LlmGenerateBaseInputSchema.extend({ images: array(LlmImageSchema).min(1) });
15636
+ var ProfileRefInputSchema = object({
15637
+ addonId: string(),
15638
+ profileId: string()
15639
+ });
15640
+ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }), method(GenerateVisionInputSchema, LlmGenerateResultSchema, { kind: "mutation" }), method(object({}), array(LlmProfileKindDescriptorSchema)), method(object({}), array(LlmProfileSchema)), method(object({ profile: LlmProfileSchema }), LlmProfileSchema, {
15641
+ kind: "mutation",
15642
+ auth: "admin"
15643
+ }), method(ProfileRefInputSchema, _void(), {
15644
+ kind: "mutation",
15645
+ auth: "admin"
15646
+ }), method(ProfileRefInputSchema, LlmGenerateResultSchema, {
15647
+ kind: "mutation",
15648
+ auth: "admin"
15649
+ }), method(ProfileRefInputSchema, array(string())), method(object({}), array(LlmDefaultSchema)), method(object({
15650
+ selector: LlmDefaultSelectorSchema,
15651
+ profileId: string().nullable()
15652
+ }), _void(), {
15653
+ kind: "mutation",
15654
+ auth: "admin"
15655
+ }), method(object({
15656
+ since: number().optional(),
15657
+ until: number().optional(),
15658
+ consumer: string().optional(),
15659
+ profileId: string().optional()
15660
+ }), array(LlmUsageRollupSchema)), method(object({}), array(ManagedModelCatalogEntrySchema)), method(object({}), array(LlmRuntimeNodeSchema)), method(object({ nodeId: string() }), array(LlmNodeModelSchema)), method(object({
15661
+ nodeId: string(),
15662
+ model: ManagedModelRefSchema
15663
+ }), _void(), {
15664
+ kind: "mutation",
15665
+ auth: "admin"
15666
+ }), method(object({
15667
+ nodeId: string(),
15668
+ file: string()
15669
+ }), _void(), {
15670
+ kind: "mutation",
15671
+ auth: "admin"
15672
+ }), method(ProfileRefInputSchema, LlmRuntimeStatusSchema), method(ProfileRefInputSchema, LlmRuntimeStatusSchema, {
15673
+ kind: "mutation",
15674
+ auth: "admin"
15675
+ }), method(ProfileRefInputSchema, _void(), {
15676
+ kind: "mutation",
15677
+ auth: "admin"
15678
+ });
15679
+ /**
15124
15680
  * Zod schemas for persisted record types.
15125
15681
  *
15126
15682
  * These schemas serve as the single source of truth for types that are
@@ -15322,6 +15878,22 @@ var TrackSnapshotSchema = object({
15322
15878
  /** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
15323
15879
  mediaKey: string()
15324
15880
  });
15881
+ /**
15882
+ * One audio-classification label heard on the track's camera while the
15883
+ * track was alive, aggregated per label. An "episode" is one persisted
15884
+ * audio event (the confident-classification path: score ≥ the device's
15885
+ * `classificationMinScore`, class-change-or-heartbeat coalesced) — NOT
15886
+ * one 32 ms inference chunk, so counts stay human-scaled.
15887
+ */
15888
+ var TrackAudioLabelSchema = object({
15889
+ label: string(),
15890
+ /** Highest classification score observed across the label's episodes. */
15891
+ peakScore: number(),
15892
+ /** Number of coalesced audio-event episodes carrying this label. */
15893
+ count: number(),
15894
+ firstAt: number(),
15895
+ lastAt: number()
15896
+ });
15325
15897
  var TrackSchema = object({
15326
15898
  trackId: string(),
15327
15899
  deviceId: number(),
@@ -15336,6 +15908,10 @@ var TrackSchema = object({
15336
15908
  snapshots: array(TrackSnapshotSchema).readonly(),
15337
15909
  /** Deduplicated zones the track has entered at least once. */
15338
15910
  zonesVisited: array(string()).readonly(),
15911
+ /** Deduplicated set of detector classes observed for this track over its
15912
+ * life (a track may be reclassified, e.g. person→vehicle). Absent on
15913
+ * legacy rows written before class accumulation shipped. */
15914
+ classes: array(string()).readonly().optional(),
15339
15915
  /** Cumulative normalized distance travelled (0..1 units = full frame width). */
15340
15916
  totalDistance: number(),
15341
15917
  state: TrackStateSchema,
@@ -15349,7 +15925,11 @@ var TrackSchema = object({
15349
15925
  bestEventId: string().optional(),
15350
15926
  /** Tag of the importance sub-signal that dominated the score
15351
15927
  * (identity|dwell|proximity|class|confidence|travel|zone). */
15352
- importanceReason: string().optional()
15928
+ importanceReason: string().optional(),
15929
+ /** Audio-classification labels heard on the camera during the track's
15930
+ * life (score ≥ device `classificationMinScore`), aggregated per label.
15931
+ * Absent on legacy rows / tracks with no confident audio. */
15932
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional()
15353
15933
  });
15354
15934
  var BaseEventFields = {
15355
15935
  id: string(),
@@ -15497,7 +16077,7 @@ var KeyEventSchema = object({
15497
16077
  /** Track lifetime in ms (lastSeen - firstSeen). */
15498
16078
  windowMs: number().optional()
15499
16079
  });
15500
- var TrackedDetectionSchema = object({
16080
+ object({
15501
16081
  trackId: string(),
15502
16082
  className: string(),
15503
16083
  confidence: number(),
@@ -15505,6 +16085,23 @@ var TrackedDetectionSchema = object({
15505
16085
  zones: array(string()).readonly(),
15506
16086
  state: TrackStateSchema
15507
16087
  });
16088
+ var OverlayDetectionSchema = looseObject({
16089
+ id: string(),
16090
+ kind: _enum(["first-level", "detail"]),
16091
+ macroClass: string(),
16092
+ score: number(),
16093
+ bbox: object({
16094
+ x: number(),
16095
+ y: number(),
16096
+ width: number(),
16097
+ height: number()
16098
+ }),
16099
+ labels: array(looseObject({
16100
+ label: string(),
16101
+ score: number()
16102
+ })).readonly(),
16103
+ parentId: string().optional()
16104
+ });
15508
16105
  var ScoredObjectEventSchema = ObjectEventSchema.extend({ score: number() });
15509
16106
  var SearchObjectEventsInput = object({
15510
16107
  text: string(),
@@ -15515,6 +16112,20 @@ var SearchObjectEventsInput = object({
15515
16112
  limit: number().default(50),
15516
16113
  minScore: number().min(0).max(1).default(.2)
15517
16114
  });
16115
+ var TrackCascadeCountsSchema = object({
16116
+ /** Persisted track roots deleted (authoritative). */
16117
+ tracks: number().int(),
16118
+ /** Object events removed with their tracks (best-effort; see note above). */
16119
+ events: number().int(),
16120
+ /** Track/face/plate-owned media removed (best-effort). Never identity media. */
16121
+ media: number().int(),
16122
+ /** Unassigned (non-enrolled) face reads removed (best-effort). */
16123
+ faces: number().int(),
16124
+ /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
16125
+ plates: number().int(),
16126
+ /** Per-track CLIP search vectors removed (best-effort). */
16127
+ embeddings: number().int()
16128
+ });
15518
16129
  var pipelineAnalyticsCapability = {
15519
16130
  name: "pipeline-analytics",
15520
16131
  scope: "device",
@@ -15568,12 +16179,14 @@ var pipelineAnalyticsCapability = {
15568
16179
  audio: number().int()
15569
16180
  })).readonly()),
15570
16181
  /**
15571
- * Delete all events (motion + object + audio) for the given device
15572
- * that are older than `cutoffMs` (exclusive), and delete their
15573
- * thumbnails in lockstep. Returns per-kind deleted counts.
15574
- *
15575
- * Called by Phase B3 recorder orchestration to keep event history
15576
- * aligned with available footage.
16182
+ * @deprecated Prefer `pruneTracksBefore` the track is the ROOT of the
16183
+ * analytics model and retention must cascade from it (design §5.1). This
16184
+ * event-only prune leaves orphaned tracks/faces/plates/embeddings behind.
16185
+ * Retained as a compat shim for the Phase-B3 recorder orchestration caller,
16186
+ * which prunes events to keep history aligned with available footage and
16187
+ * reads the per-kind counts. Delete all events (motion + object + audio)
16188
+ * for the given device older than `cutoffMs` (exclusive) + their thumbnails
16189
+ * in lockstep; returns per-kind deleted counts.
15577
16190
  */
15578
16191
  pruneEventsBefore: method(object({
15579
16192
  deviceId: number(),
@@ -15586,6 +16199,55 @@ var pipelineAnalyticsCapability = {
15586
16199
  kind: "mutation",
15587
16200
  auth: "admin"
15588
16201
  }),
16202
+ /**
16203
+ * Track-centric retention entry point (design §5.1). Selects every
16204
+ * persisted track for the device whose `lastSeen < cutoffMs` (paged) and
16205
+ * runs the extensible whole-track deletion cascade (design §3): object
16206
+ * events + their media, track/face/plate-owned media, unassigned face
16207
+ * reads, per-track CLIP embeddings, then the track root LAST. ENROLLED
16208
+ * (assigned) faces/plates and `ownerKind:'identity'` media are exempt —
16209
+ * the durable matching gallery always persists. Fires the per-track
16210
+ * live-state cleanup so a pruned track can't linger in dispatch/overlay
16211
+ * state. Returns per-family deleted counts (`tracks` authoritative).
16212
+ *
16213
+ * Replaces `pruneEventsBefore` as the correct time-based retention prune.
16214
+ */
16215
+ pruneTracksBefore: method(object({
16216
+ deviceId: number(),
16217
+ cutoffMs: number()
16218
+ }), TrackCascadeCountsSchema, {
16219
+ kind: "mutation",
16220
+ auth: "admin"
16221
+ }),
16222
+ /**
16223
+ * Operator "clean slate" for a device (design §5.3): prune EVERY track for
16224
+ * the device via the same cascade as `pruneTracksBefore` with `cutoffMs =
16225
+ * now`. One call per device — no client-side track enumeration. Enrolled
16226
+ * gallery + identity media are exempt (design §4). Returns per-family
16227
+ * deleted counts.
16228
+ */
16229
+ wipeAllAnalytics: method(object({ deviceId: number() }), TrackCascadeCountsSchema, {
16230
+ kind: "mutation",
16231
+ auth: "admin"
16232
+ }),
16233
+ /**
16234
+ * Delete whole tracks (object events) by id for the given device,
16235
+ * cascading their media in lockstep. Returns the number of tracks
16236
+ * actually deleted plus the ids that could not be removed.
16237
+ *
16238
+ * Operator-driven from the DI Events page (batch delete). Routes through
16239
+ * the same widened track-deletion cascade (design §5.2).
16240
+ */
16241
+ deleteTracks: method(object({
16242
+ deviceId: number(),
16243
+ trackIds: array(string()).min(1)
16244
+ }), object({
16245
+ deleted: number().int(),
16246
+ failed: array(string()).readonly()
16247
+ }), {
16248
+ kind: "mutation",
16249
+ auth: "admin"
16250
+ }),
15589
16251
  getEventMedia: method(object({
15590
16252
  eventId: string(),
15591
16253
  kind: MediaFileKindEnum.optional()
@@ -15603,17 +16265,19 @@ var pipelineAnalyticsCapability = {
15603
16265
  },
15604
16266
  events: {
15605
16267
  /**
15606
- * Enriched frame emitted after refinement. Carries lightweight
15607
- * tracked-detection metadata (track id, class, zones, state) so
15608
- * downstream consumers (stream overlays, notifications) can
15609
- * annotate without querying full Track state.
16268
+ * Enriched frame emitted after refinement the live-overlay source of
16269
+ * truth (two-plane re-injection). Carries the frame's detections in the
16270
+ * `ObjectDetection` wire shape: first-level roots (with track info +
16271
+ * enrichment labels) plus synthesized `kind:'detail'` face/plate entries
16272
+ * re-projected from per-track detail state, so stream overlays render
16273
+ * boxes + recognized names without querying full Track state.
15610
16274
  */
15611
16275
  onFrameTracked: { data: object({
15612
16276
  deviceId: number(),
15613
16277
  timestamp: number(),
15614
16278
  frameWidth: number(),
15615
16279
  frameHeight: number(),
15616
- detections: array(TrackedDetectionSchema).readonly()
16280
+ detections: array(OverlayDetectionSchema).readonly()
15617
16281
  }) },
15618
16282
  /** Track entered active state (first-seen). */
15619
16283
  onTrackStarted: { data: object({
@@ -18426,8 +19090,26 @@ DeviceType.Camera, method(object({
18426
19090
  deviceId: number(),
18427
19091
  status: OsdStatusSchema
18428
19092
  });
18429
- var PlateInfoSchema = object({
18430
- plateId: string(),
19093
+ var VehicleSchema = object({
19094
+ id: string(),
19095
+ name: string(),
19096
+ sampleCount: number().int().nonnegative(),
19097
+ coverMediaKey: string().optional(),
19098
+ /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
19099
+ coverBase64: string().optional()
19100
+ });
19101
+ var VehicleSampleInfoSchema = object({
19102
+ id: string(),
19103
+ /** The plate text this sample enrolled (self-labeling — no embedding). */
19104
+ text: string(),
19105
+ /** OCR confidence of the enrolled read (0..1). */
19106
+ score: number(),
19107
+ addedAt: number().int(),
19108
+ deviceId: number().int().optional(),
19109
+ base64: string().optional()
19110
+ });
19111
+ var PlateInfoSchema = object({
19112
+ plateId: string(),
18431
19113
  deviceId: number().int(),
18432
19114
  trackId: string(),
18433
19115
  timestamp: number().int(),
@@ -18437,6 +19119,16 @@ var PlateInfoSchema = object({
18437
19119
  score: number(),
18438
19120
  /** True when the text was manually corrected (exempt from retention). */
18439
19121
  corrected: boolean(),
19122
+ /** Recognized vehicle id when a matcher lookup named this read (SQL NULL → absent). */
19123
+ recognizedVehicleId: string().optional(),
19124
+ /** Resolved vehicle name for `recognizedVehicleId` (UI convenience). */
19125
+ vehicleName: string().optional(),
19126
+ /** True once the read was assigned to a vehicle (enrolled as a sample). */
19127
+ assigned: boolean(),
19128
+ /** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
19129
+ plateBbox: BoundingBoxSchema.optional(),
19130
+ /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
19131
+ keyFrameMediaKey: string().optional(),
18440
19132
  base64: string().optional()
18441
19133
  });
18442
19134
  var MediaFileLiteSchema = object({
@@ -18498,6 +19190,58 @@ var plateGalleryCapability = {
18498
19190
  deletePlate: method(object({ plateId: string() }), _void(), {
18499
19191
  kind: "mutation",
18500
19192
  auth: "admin"
19193
+ }),
19194
+ listVehicles: method(_void(), array(VehicleSchema).readonly()),
19195
+ createVehicle: method(object({ name: string().min(1) }), VehicleSchema, {
19196
+ kind: "mutation",
19197
+ auth: "admin"
19198
+ }),
19199
+ renameVehicle: method(object({
19200
+ id: string(),
19201
+ name: string().min(1)
19202
+ }), _void(), {
19203
+ kind: "mutation",
19204
+ auth: "admin"
19205
+ }),
19206
+ deleteVehicle: method(object({ id: string() }), _void(), {
19207
+ kind: "mutation",
19208
+ auth: "admin"
19209
+ }),
19210
+ listVehicleSamples: method(object({ vehicleId: string() }), array(VehicleSampleInfoSchema).readonly()),
19211
+ removeVehicleSample: method(object({
19212
+ vehicleId: string(),
19213
+ sampleId: string()
19214
+ }), _void(), {
19215
+ kind: "mutation",
19216
+ auth: "admin"
19217
+ }),
19218
+ assignPlate: method(object({
19219
+ plateId: string(),
19220
+ vehicleId: string()
19221
+ }), _void(), {
19222
+ kind: "mutation",
19223
+ auth: "admin"
19224
+ }),
19225
+ unassignPlate: method(object({ plateId: string() }), _void(), {
19226
+ kind: "mutation",
19227
+ auth: "admin"
19228
+ }),
19229
+ assignPlates: method(object({
19230
+ plateIds: array(string()).min(1),
19231
+ vehicleId: string()
19232
+ }), object({
19233
+ assigned: number().int(),
19234
+ failed: array(string()).readonly()
19235
+ }), {
19236
+ kind: "mutation",
19237
+ auth: "admin"
19238
+ }),
19239
+ unassignPlates: method(object({ plateIds: array(string()).min(1) }), object({
19240
+ unassigned: number().int(),
19241
+ failed: array(string()).readonly()
19242
+ }), {
19243
+ kind: "mutation",
19244
+ auth: "admin"
18501
19245
  })
18502
19246
  }
18503
19247
  };
@@ -18578,6 +19322,10 @@ var GpuInfoSchema = object({
18578
19322
  memoryMB: number().optional()
18579
19323
  });
18580
19324
  var NpuInfoSchema = object({ type: _enum(["apple-ane", "intel-npu"]) });
19325
+ var CoralInfoSchema = object({
19326
+ type: literal("coral-edgetpu"),
19327
+ bus: string().optional()
19328
+ });
18581
19329
  var HardwareInfoSchema = object({
18582
19330
  platform: HardwarePlatformSchema,
18583
19331
  arch: HardwareArchSchema,
@@ -18586,7 +19334,8 @@ var HardwareInfoSchema = object({
18586
19334
  totalRAM_MB: number(),
18587
19335
  availableRAM_MB: number(),
18588
19336
  gpu: GpuInfoSchema.nullable(),
18589
- npu: NpuInfoSchema.nullable()
19337
+ npu: NpuInfoSchema.nullable(),
19338
+ coral: CoralInfoSchema.nullable().optional()
18590
19339
  });
18591
19340
  var PlatformScoreSchema = object({
18592
19341
  runtime: _enum(["node", "python"]),
@@ -21045,6 +21794,168 @@ Object.freeze({
21045
21794
  addonId: null,
21046
21795
  access: "create"
21047
21796
  },
21797
+ "llm.deleteModel": {
21798
+ capName: "llm",
21799
+ capScope: "system",
21800
+ addonId: null,
21801
+ access: "delete"
21802
+ },
21803
+ "llm.deleteProfile": {
21804
+ capName: "llm",
21805
+ capScope: "system",
21806
+ addonId: null,
21807
+ access: "delete"
21808
+ },
21809
+ "llm.generate": {
21810
+ capName: "llm",
21811
+ capScope: "system",
21812
+ addonId: null,
21813
+ access: "create"
21814
+ },
21815
+ "llm.generateVision": {
21816
+ capName: "llm",
21817
+ capScope: "system",
21818
+ addonId: null,
21819
+ access: "create"
21820
+ },
21821
+ "llm.getDefaults": {
21822
+ capName: "llm",
21823
+ capScope: "system",
21824
+ addonId: null,
21825
+ access: "view"
21826
+ },
21827
+ "llm.getRuntimeStatus": {
21828
+ capName: "llm",
21829
+ capScope: "system",
21830
+ addonId: null,
21831
+ access: "view"
21832
+ },
21833
+ "llm.getUsage": {
21834
+ capName: "llm",
21835
+ capScope: "system",
21836
+ addonId: null,
21837
+ access: "view"
21838
+ },
21839
+ "llm.installModel": {
21840
+ capName: "llm",
21841
+ capScope: "system",
21842
+ addonId: null,
21843
+ access: "create"
21844
+ },
21845
+ "llm.listModelCatalog": {
21846
+ capName: "llm",
21847
+ capScope: "system",
21848
+ addonId: null,
21849
+ access: "view"
21850
+ },
21851
+ "llm.listModels": {
21852
+ capName: "llm",
21853
+ capScope: "system",
21854
+ addonId: null,
21855
+ access: "view"
21856
+ },
21857
+ "llm.listNodeModels": {
21858
+ capName: "llm",
21859
+ capScope: "system",
21860
+ addonId: null,
21861
+ access: "view"
21862
+ },
21863
+ "llm.listProfileKinds": {
21864
+ capName: "llm",
21865
+ capScope: "system",
21866
+ addonId: null,
21867
+ access: "view"
21868
+ },
21869
+ "llm.listProfiles": {
21870
+ capName: "llm",
21871
+ capScope: "system",
21872
+ addonId: null,
21873
+ access: "view"
21874
+ },
21875
+ "llm.listRuntimeNodes": {
21876
+ capName: "llm",
21877
+ capScope: "system",
21878
+ addonId: null,
21879
+ access: "view"
21880
+ },
21881
+ "llm.setDefault": {
21882
+ capName: "llm",
21883
+ capScope: "system",
21884
+ addonId: null,
21885
+ access: "create"
21886
+ },
21887
+ "llm.startRuntime": {
21888
+ capName: "llm",
21889
+ capScope: "system",
21890
+ addonId: null,
21891
+ access: "create"
21892
+ },
21893
+ "llm.stopRuntime": {
21894
+ capName: "llm",
21895
+ capScope: "system",
21896
+ addonId: null,
21897
+ access: "create"
21898
+ },
21899
+ "llm.testProfile": {
21900
+ capName: "llm",
21901
+ capScope: "system",
21902
+ addonId: null,
21903
+ access: "create"
21904
+ },
21905
+ "llm.upsertProfile": {
21906
+ capName: "llm",
21907
+ capScope: "system",
21908
+ addonId: null,
21909
+ access: "create"
21910
+ },
21911
+ "llmRuntime.complete": {
21912
+ capName: "llm-runtime",
21913
+ capScope: "system",
21914
+ addonId: null,
21915
+ access: "create"
21916
+ },
21917
+ "llmRuntime.deleteModel": {
21918
+ capName: "llm-runtime",
21919
+ capScope: "system",
21920
+ addonId: null,
21921
+ access: "delete"
21922
+ },
21923
+ "llmRuntime.ensureStarted": {
21924
+ capName: "llm-runtime",
21925
+ capScope: "system",
21926
+ addonId: null,
21927
+ access: "create"
21928
+ },
21929
+ "llmRuntime.getDiskUsage": {
21930
+ capName: "llm-runtime",
21931
+ capScope: "system",
21932
+ addonId: null,
21933
+ access: "view"
21934
+ },
21935
+ "llmRuntime.installModel": {
21936
+ capName: "llm-runtime",
21937
+ capScope: "system",
21938
+ addonId: null,
21939
+ access: "create"
21940
+ },
21941
+ "llmRuntime.listLocalModels": {
21942
+ capName: "llm-runtime",
21943
+ capScope: "system",
21944
+ addonId: null,
21945
+ access: "view"
21946
+ },
21947
+ "llmRuntime.status": {
21948
+ capName: "llm-runtime",
21949
+ capScope: "system",
21950
+ addonId: null,
21951
+ access: "view"
21952
+ },
21953
+ "llmRuntime.stop": {
21954
+ capName: "llm-runtime",
21955
+ capScope: "system",
21956
+ addonId: null,
21957
+ access: "create"
21958
+ },
21048
21959
  "localNetwork.getAllowedAddresses": {
21049
21960
  capName: "local-network",
21050
21961
  capScope: "system",
@@ -21675,6 +22586,12 @@ Object.freeze({
21675
22586
  addonId: null,
21676
22587
  access: "delete"
21677
22588
  },
22589
+ "pipelineAnalytics.deleteTracks": {
22590
+ capName: "pipeline-analytics",
22591
+ capScope: "device",
22592
+ addonId: null,
22593
+ access: "delete"
22594
+ },
21678
22595
  "pipelineAnalytics.getActiveTracks": {
21679
22596
  capName: "pipeline-analytics",
21680
22597
  capScope: "device",
@@ -21741,12 +22658,24 @@ Object.freeze({
21741
22658
  addonId: null,
21742
22659
  access: "create"
21743
22660
  },
22661
+ "pipelineAnalytics.pruneTracksBefore": {
22662
+ capName: "pipeline-analytics",
22663
+ capScope: "device",
22664
+ addonId: null,
22665
+ access: "create"
22666
+ },
21744
22667
  "pipelineAnalytics.searchObjectEvents": {
21745
22668
  capName: "pipeline-analytics",
21746
22669
  capScope: "device",
21747
22670
  addonId: null,
21748
22671
  access: "view"
21749
22672
  },
22673
+ "pipelineAnalytics.wipeAllAnalytics": {
22674
+ capName: "pipeline-analytics",
22675
+ capScope: "device",
22676
+ addonId: null,
22677
+ access: "delete"
22678
+ },
21750
22679
  "pipelineExecutor.cacheFrameInPool": {
21751
22680
  capName: "pipeline-executor",
21752
22681
  capScope: "system",
@@ -22251,18 +23180,42 @@ Object.freeze({
22251
23180
  addonId: null,
22252
23181
  access: "create"
22253
23182
  },
23183
+ "plateGallery.assignPlate": {
23184
+ capName: "plate-gallery",
23185
+ capScope: "system",
23186
+ addonId: null,
23187
+ access: "create"
23188
+ },
23189
+ "plateGallery.assignPlates": {
23190
+ capName: "plate-gallery",
23191
+ capScope: "system",
23192
+ addonId: null,
23193
+ access: "create"
23194
+ },
22254
23195
  "plateGallery.correctPlateText": {
22255
23196
  capName: "plate-gallery",
22256
23197
  capScope: "system",
22257
23198
  addonId: null,
22258
23199
  access: "create"
22259
23200
  },
23201
+ "plateGallery.createVehicle": {
23202
+ capName: "plate-gallery",
23203
+ capScope: "system",
23204
+ addonId: null,
23205
+ access: "create"
23206
+ },
22260
23207
  "plateGallery.deletePlate": {
22261
23208
  capName: "plate-gallery",
22262
23209
  capScope: "system",
22263
23210
  addonId: null,
22264
23211
  access: "delete"
22265
23212
  },
23213
+ "plateGallery.deleteVehicle": {
23214
+ capName: "plate-gallery",
23215
+ capScope: "system",
23216
+ addonId: null,
23217
+ access: "delete"
23218
+ },
22266
23219
  "plateGallery.getPlateByTrack": {
22267
23220
  capName: "plate-gallery",
22268
23221
  capScope: "system",
@@ -22281,6 +23234,30 @@ Object.freeze({
22281
23234
  addonId: null,
22282
23235
  access: "view"
22283
23236
  },
23237
+ "plateGallery.listVehicles": {
23238
+ capName: "plate-gallery",
23239
+ capScope: "system",
23240
+ addonId: null,
23241
+ access: "view"
23242
+ },
23243
+ "plateGallery.listVehicleSamples": {
23244
+ capName: "plate-gallery",
23245
+ capScope: "system",
23246
+ addonId: null,
23247
+ access: "view"
23248
+ },
23249
+ "plateGallery.removeVehicleSample": {
23250
+ capName: "plate-gallery",
23251
+ capScope: "system",
23252
+ addonId: null,
23253
+ access: "delete"
23254
+ },
23255
+ "plateGallery.renameVehicle": {
23256
+ capName: "plate-gallery",
23257
+ capScope: "system",
23258
+ addonId: null,
23259
+ access: "create"
23260
+ },
22284
23261
  "plateGallery.searchPlates": {
22285
23262
  capName: "plate-gallery",
22286
23263
  capScope: "system",
@@ -22293,6 +23270,18 @@ Object.freeze({
22293
23270
  addonId: null,
22294
23271
  access: "view"
22295
23272
  },
23273
+ "plateGallery.unassignPlate": {
23274
+ capName: "plate-gallery",
23275
+ capScope: "system",
23276
+ addonId: null,
23277
+ access: "create"
23278
+ },
23279
+ "plateGallery.unassignPlates": {
23280
+ capName: "plate-gallery",
23281
+ capScope: "system",
23282
+ addonId: null,
23283
+ access: "create"
23284
+ },
22296
23285
  "platformProbe.getCapabilities": {
22297
23286
  capName: "platform-probe",
22298
23287
  capScope: "system",
@@ -22485,6 +23474,48 @@ Object.freeze({
22485
23474
  addonId: null,
22486
23475
  access: "create"
22487
23476
  },
23477
+ "sceneMonitor.captureReference": {
23478
+ capName: "scene-monitor",
23479
+ capScope: "device",
23480
+ addonId: null,
23481
+ access: "create"
23482
+ },
23483
+ "sceneMonitor.createScene": {
23484
+ capName: "scene-monitor",
23485
+ capScope: "device",
23486
+ addonId: null,
23487
+ access: "create"
23488
+ },
23489
+ "sceneMonitor.deleteReference": {
23490
+ capName: "scene-monitor",
23491
+ capScope: "device",
23492
+ addonId: null,
23493
+ access: "delete"
23494
+ },
23495
+ "sceneMonitor.deleteScene": {
23496
+ capName: "scene-monitor",
23497
+ capScope: "device",
23498
+ addonId: null,
23499
+ access: "delete"
23500
+ },
23501
+ "sceneMonitor.listScenes": {
23502
+ capName: "scene-monitor",
23503
+ capScope: "device",
23504
+ addonId: null,
23505
+ access: "view"
23506
+ },
23507
+ "sceneMonitor.recheckNow": {
23508
+ capName: "scene-monitor",
23509
+ capScope: "device",
23510
+ addonId: null,
23511
+ access: "create"
23512
+ },
23513
+ "sceneMonitor.updateScene": {
23514
+ capName: "scene-monitor",
23515
+ capScope: "device",
23516
+ addonId: null,
23517
+ access: "create"
23518
+ },
22488
23519
  "scriptRunner.run": {
22489
23520
  capName: "script-runner",
22490
23521
  capScope: "device",
@@ -23569,6 +24600,7 @@ Object.freeze({
23569
24600
  Object.freeze({
23570
24601
  "broker": "broker",
23571
24602
  "device-export": "device-export",
24603
+ "llm": "ai",
23572
24604
  "mesh-network": "mesh",
23573
24605
  "mqtt-broker": "broker",
23574
24606
  "network-access": "ingress",
@@ -23631,30 +24663,12 @@ Object.defineProperty(exports, "__toESM", {
23631
24663
  return __toESM;
23632
24664
  }
23633
24665
  });
23634
- Object.defineProperty(exports, "_enum", {
23635
- enumerable: true,
23636
- get: function() {
23637
- return _enum;
23638
- }
23639
- });
23640
24666
  Object.defineProperty(exports, "addonWidgetsSourceCapability", {
23641
24667
  enumerable: true,
23642
24668
  get: function() {
23643
24669
  return addonWidgetsSourceCapability;
23644
24670
  }
23645
24671
  });
23646
- Object.defineProperty(exports, "array", {
23647
- enumerable: true,
23648
- get: function() {
23649
- return array;
23650
- }
23651
- });
23652
- Object.defineProperty(exports, "asJsonObject", {
23653
- enumerable: true,
23654
- get: function() {
23655
- return asJsonObject;
23656
- }
23657
- });
23658
24672
  Object.defineProperty(exports, "audioMetricsCapability", {
23659
24673
  enumerable: true,
23660
24674
  get: function() {
@@ -23745,12 +24759,6 @@ Object.defineProperty(exports, "string", {
23745
24759
  return string;
23746
24760
  }
23747
24761
  });
23748
- Object.defineProperty(exports, "tuple", {
23749
- enumerable: true,
23750
- get: function() {
23751
- return tuple;
23752
- }
23753
- });
23754
24762
  Object.defineProperty(exports, "videoclipsCapability", {
23755
24763
  enumerable: true,
23756
24764
  get: function() {