@camstack/addon-ai 0.4.9 → 0.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +128 -22
  2. package/dist/addon.mjs +128 -22
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -15,7 +15,7 @@ let node_zlib = require("node:zlib");
15
15
  let node_fs_promises = require("node:fs/promises");
16
16
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
17
17
  let node_child_process = require("node:child_process");
18
- //#region ../types/dist/event-category-C0lyLd5U.mjs
18
+ //#region ../types/dist/event-category-XfKNtfCc.mjs
19
19
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
20
20
  EventCategory["SystemBoot"] = "system.boot";
21
21
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -54,6 +54,22 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
54
54
  EventCategory["AddonInstalled"] = "addon.installed";
55
55
  EventCategory["AddonUninstalled"] = "addon.uninstalled";
56
56
  EventCategory["AddonCrashed"] = "addon.crashed";
57
+ /**
58
+ * A RUNNER the D6 crash circuit-breaker gave up on — terminal.
59
+ *
60
+ * `AddonCrashed` is the routine, self-healing fact ("it crashed; it is being
61
+ * respawned"); this is the one that never resolves itself. Emitted exactly
62
+ * once per trip, by `process-service.ts`, carrying the node, the runner, the
63
+ * addons it hosted and the crash count that tripped the breaker.
64
+ *
65
+ * It exists because a runner marked terminally `failed` used to be SILENT:
66
+ * on 2026-08-18 the `recorder` runner died of three unhandled ffmpeg spawn
67
+ * errors, the breaker stopped respawning it (correctly), `/health` kept
68
+ * returning 200, and fleet-wide recording was gone for 3h15 before the
69
+ * operator's phone told him. The Notification Center's system-event intake
70
+ * consumes this category and maps it to the `addon-crash-loop` kind.
71
+ */
72
+ EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
57
73
  EventCategory["AddonError"] = "addon.error";
58
74
  EventCategory["AddonPageReady"] = "addon.page-ready";
59
75
  EventCategory["AddonWidgetReady"] = "addon.widget-ready";
@@ -7806,6 +7822,12 @@ var RecordingConfigSchema = object({
7806
7822
  /** DERIVED summary of `bands`, stamped by the recorder on every save.
7807
7823
  * Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
7808
7824
  mode: RecordingStorageModeSchema.optional(),
7825
+ /**
7826
+ * Which assigned broker slots to record. Absent / empty = {@link
7827
+ * DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
7828
+ * camera's currently assigned slots — never `mid` unless the operator
7829
+ * picks it, and never a slot the broker has not assigned.
7830
+ */
7809
7831
  profiles: array(CamProfileSchema).optional(),
7810
7832
  segmentSeconds: number$1().int().positive().optional(),
7811
7833
  /**
@@ -7886,7 +7908,11 @@ var RelocateFootageInputSchema = object({
7886
7908
  profiles: array(string()).optional(),
7887
7909
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
7888
7910
  * never allowed to starve live writers. */
7889
- throttleMbps: number$1().min(1).max(1e3).optional()
7911
+ throttleMbps: number$1().min(1).max(1e3).optional(),
7912
+ /** Move only segments whose startMs is >= this. Absent = the whole source
7913
+ * pile. Used when a full drain is too expensive and the operator only
7914
+ * wants the recent window on the new disk. */
7915
+ sinceMs: number$1().int().optional()
7890
7916
  });
7891
7917
  /** Internal, lease-scoped participant operation. It is intentionally separate
7892
7918
  * from persistent recording settings: a migration never changes
@@ -14530,6 +14556,7 @@ var NcSystemEventKindSchema = _enum([
14530
14556
  "node-offline",
14531
14557
  "node-inference-unavailable",
14532
14558
  "detection-blind",
14559
+ "addon-crash-loop",
14533
14560
  "addon-update-available",
14534
14561
  "server-update-available",
14535
14562
  "alarm-triggered",
@@ -17103,6 +17130,12 @@ var TrackCascadeCountsSchema = object({
17103
17130
  /** Per-track CLIP search vectors removed (best-effort). */
17104
17131
  embeddings: number$1().int()
17105
17132
  });
17133
+ /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17134
+ var DiskReconcileCountsSchema = object({
17135
+ mediaDropped: number$1().int(),
17136
+ tracks: number$1().int(),
17137
+ events: number$1().int()
17138
+ });
17106
17139
  /** Event-store footprint for one camera. */
17107
17140
  var EventStoreDeviceFootprintSchema = object({
17108
17141
  deviceId: number$1(),
@@ -17279,6 +17312,9 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
17279
17312
  }), method(object({ deviceId: number$1() }), TrackCascadeCountsSchema, {
17280
17313
  kind: "mutation",
17281
17314
  auth: "admin"
17315
+ }), method(object({ deviceId: number$1() }), DiskReconcileCountsSchema, {
17316
+ kind: "mutation",
17317
+ auth: "admin"
17282
17318
  }), method(object({
17283
17319
  deviceId: number$1(),
17284
17320
  trackIds: array(string()).min(1)
@@ -18789,6 +18825,24 @@ var CameraStatusDegradationSchema = object({
18789
18825
  *
18790
18826
  * See spec: `docs/superpowers/specs/2026-06-24-camera-status-aggregator-cap.md`
18791
18827
  */
18828
+ var DiskReconcileJobSchema = object({
18829
+ state: _enum([
18830
+ "idle",
18831
+ "running",
18832
+ "done",
18833
+ "error"
18834
+ ]),
18835
+ total: number$1().int().nonnegative(),
18836
+ completed: number$1().int().nonnegative(),
18837
+ currentDeviceId: number$1().int().nullable(),
18838
+ failed: array(number$1().int()).readonly(),
18839
+ mediaDropped: number$1().int().nonnegative(),
18840
+ tracks: number$1().int().nonnegative(),
18841
+ events: number$1().int().nonnegative(),
18842
+ startedAtMs: number$1().int().nullable(),
18843
+ finishedAtMs: number$1().int().nullable(),
18844
+ error: string().nullable()
18845
+ });
18792
18846
  var CameraStatusSchema = object({
18793
18847
  deviceId: number$1(),
18794
18848
  assignment: CameraAssignmentStatusSchema,
@@ -19020,7 +19074,10 @@ method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
19020
19074
  }), CameraSwitchGroupSchema, {
19021
19075
  kind: "mutation",
19022
19076
  auth: "admin"
19023
- }), method(object({ deviceId: number$1() }), CameraStatusSchema), method(object({ deviceIds: array(number$1()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
19077
+ }), method(object({ deviceId: number$1() }), CameraStatusSchema), method(object({ deviceIds: array(number$1()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), DiskReconcileJobSchema, {
19078
+ kind: "mutation",
19079
+ auth: "admin"
19080
+ }), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
19024
19081
  name: string(),
19025
19082
  description: string().optional(),
19026
19083
  config: CameraPipelineConfigSchema
@@ -20093,20 +20150,6 @@ var VectorStatsResultSchema = object({
20093
20150
  exact: boolean()
20094
20151
  });
20095
20152
  method(VectorDeclareIndexInputSchema, _void(), { kind: "mutation" }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, { kind: "mutation" }), method(VectorQueryInputSchema, VectorQueryResultSchema), method(VectorGetInputSchema, VectorGetResultSchema), method(VectorDeleteInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorStatsInputSchema, VectorStatsResultSchema);
20096
- /**
20097
- * `videoclips` — the unified, navigable-clip surface for a camera.
20098
- *
20099
- * A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
20100
- * provider per device, substitutable. The DEFAULT provider (registered by
20101
- * `addon-post-analysis`, `defaultActive: true`) composes the analytics event
20102
- * log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
20103
- * is a time-WINDOW over existing footage, never a separate file. A camera that
20104
- * exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
20105
- * wrapper provider for its device and serve its own clip catalog + URLs.
20106
- *
20107
- * A `Clip` is purely time-based (subtree-blind): playback resolves segments by
20108
- * temporal overlap, so the API never decides `continuous` vs `events`.
20109
- */
20110
20153
  var ClipSchema = object({
20111
20154
  /** Opaque, provider-namespaced id. The default provider encodes the time
20112
20155
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -20132,12 +20175,41 @@ var ClipSchema = object({
20132
20175
  * of the event that owns `kind` (object > motion > audio). Do not extract
20133
20176
  * a keyframe from the recorded segments. Other providers (onboard, HKSV)
20134
20177
  * mint their own stills.
20178
+ *
20179
+ * **VOUCHED, never fabricated.** A provider emits this only for an event it
20180
+ * has CONFIRMED owns at least one media row (its own, or its owning track's).
20181
+ * Absent is meaningful — "this visit has no event still" — never "we did not
20182
+ * look". Stamping it from a URL template made 35% of one camera's clips point
20183
+ * at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
20184
+ * A read that FAILS drops the claim; it never invents it.
20135
20185
  */
20136
20186
  thumbnail: string().optional(),
20137
- /** Analytics event ids that overlap this visit. Empty on footage-only clips.
20138
- * The default provider's visit grain puts many motion heartbeats on one clip
20139
- * instead of minting one clip per marker. */
20187
+ /**
20188
+ * An instant INSIDE this visit's footage, hole-safe, where a recorded still
20189
+ * can be decoded. Present whenever the visit came from recorded availability;
20190
+ * absent on a per-event padded window (there is no footage to promise).
20191
+ *
20192
+ * This is not a thumbnail and not a second byte path: it is the argument to
20193
+ * the recorder's existing still route. The surface — never the provider —
20194
+ * decides whether to use it. It is the midpoint of the visit's LONGEST
20195
+ * contiguous range, not of the visit: a visit spans its holes by
20196
+ * construction, so a naive midpoint lands in dead air.
20197
+ */
20198
+ stillAtMs: number$1().optional(),
20199
+ /**
20200
+ * Analytics event ids that overlap this visit — a BOUNDED sample, newest
20201
+ * first within kind (object → motion → audio), capped at
20202
+ * {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
20203
+ *
20204
+ * Bounded because it is not a payload the surface pages through: one visit on
20205
+ * device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
20206
+ * camera-day. Read {@link eventCount} for the true total.
20207
+ */
20140
20208
  eventIds: array(string()).optional(),
20209
+ /** How many analytics events actually overlap this visit. Differs from
20210
+ * `eventIds.length` exactly when the sample was capped — so a truncated
20211
+ * list is never mistaken for a quiet visit. */
20212
+ eventCount: number$1().int().nonnegative().optional(),
20141
20213
  /** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
20142
20214
  * than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
20143
20215
  * bar keeps showing them via `recording.getAvailability`. */
@@ -20608,7 +20680,14 @@ var SearchResultSchema = object({
20608
20680
  });
20609
20681
  var AutoUpdateSettingsSchema = object({
20610
20682
  channel: ChannelSchema,
20611
- intervalSeconds: number$1()
20683
+ intervalSeconds: number$1(),
20684
+ /**
20685
+ * Cadence of the "an update exists" POLLER, in seconds. Independent of
20686
+ * `channel`: the poller runs while auto-apply is `off`, because being told
20687
+ * about a publish and installing it are different decisions. Clamped
20688
+ * server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
20689
+ */
20690
+ updateCheckIntervalSeconds: number$1()
20612
20691
  });
20613
20692
  var AddonAutoUpdateSchema = ChannelWithInheritSchema;
20614
20693
  var RestartAddonResultSchema = unknown();
@@ -20749,7 +20828,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
20749
20828
  auth: "admin"
20750
20829
  }), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
20751
20830
  channel: ChannelSchema,
20752
- intervalSeconds: number$1().min(300).max(86400).optional()
20831
+ intervalSeconds: number$1().min(300).max(86400).optional(),
20832
+ /** Availability-poll cadence; see AutoUpdateSettingsSchema. */
20833
+ updateCheckIntervalSeconds: number$1().min(900).max(604800).optional()
20753
20834
  }), unknown(), {
20754
20835
  kind: "mutation",
20755
20836
  auth: "admin"
@@ -29414,6 +29495,12 @@ Object.freeze({
29414
29495
  addonId: null,
29415
29496
  access: "create"
29416
29497
  },
29498
+ "pipelineAnalytics.reconcileFromDisk": {
29499
+ capName: "pipeline-analytics",
29500
+ capScope: "device",
29501
+ addonId: null,
29502
+ access: "create"
29503
+ },
29417
29504
  "pipelineAnalytics.refreshStorageLocationsForMigration": {
29418
29505
  capName: "pipeline-analytics",
29419
29506
  capScope: "device",
@@ -29816,6 +29903,12 @@ Object.freeze({
29816
29903
  addonId: null,
29817
29904
  access: "view"
29818
29905
  },
29906
+ "pipelineOrchestrator.getReconcileFromDiskStatus": {
29907
+ capName: "pipeline-orchestrator",
29908
+ capScope: "system",
29909
+ addonId: null,
29910
+ access: "view"
29911
+ },
29819
29912
  "pipelineOrchestrator.listAgentSettings": {
29820
29913
  capName: "pipeline-orchestrator",
29821
29914
  capScope: "system",
@@ -29840,6 +29933,12 @@ Object.freeze({
29840
29933
  addonId: null,
29841
29934
  access: "create"
29842
29935
  },
29936
+ "pipelineOrchestrator.reconcileFromDisk": {
29937
+ capName: "pipeline-orchestrator",
29938
+ capScope: "system",
29939
+ addonId: null,
29940
+ access: "create"
29941
+ },
29843
29942
  "pipelineOrchestrator.removeAgentSettings": {
29844
29943
  capName: "pipeline-orchestrator",
29845
29944
  capScope: "system",
@@ -32831,6 +32930,11 @@ Object.freeze({
32831
32930
  form: "single",
32832
32931
  optional: true
32833
32932
  }],
32933
+ "pipelineAnalytics.reconcileFromDisk": [{
32934
+ name: "deviceId",
32935
+ form: "single",
32936
+ optional: false
32937
+ }],
32834
32938
  "pipelineAnalytics.restageRetrainTrack": [{
32835
32939
  name: "deviceId",
32836
32940
  form: "single",
@@ -33896,6 +34000,8 @@ DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
33896
34000
  DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
33897
34001
  DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
33898
34002
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
34003
+ var MB = 1024 * 1024;
34004
+ 1024 * MB, 3072 * MB;
33899
34005
  //#endregion
33900
34006
  //#region ../../node_modules/@ai-sdk/provider/dist/index.js
33901
34007
  var marker$2 = "vercel.ai.error";
package/dist/addon.mjs CHANGED
@@ -41,7 +41,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
41
41
  }) : target, mod));
42
42
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
43
43
  //#endregion
44
- //#region ../types/dist/event-category-C0lyLd5U.mjs
44
+ //#region ../types/dist/event-category-XfKNtfCc.mjs
45
45
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
46
46
  EventCategory["SystemBoot"] = "system.boot";
47
47
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -80,6 +80,22 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
80
80
  EventCategory["AddonInstalled"] = "addon.installed";
81
81
  EventCategory["AddonUninstalled"] = "addon.uninstalled";
82
82
  EventCategory["AddonCrashed"] = "addon.crashed";
83
+ /**
84
+ * A RUNNER the D6 crash circuit-breaker gave up on — terminal.
85
+ *
86
+ * `AddonCrashed` is the routine, self-healing fact ("it crashed; it is being
87
+ * respawned"); this is the one that never resolves itself. Emitted exactly
88
+ * once per trip, by `process-service.ts`, carrying the node, the runner, the
89
+ * addons it hosted and the crash count that tripped the breaker.
90
+ *
91
+ * It exists because a runner marked terminally `failed` used to be SILENT:
92
+ * on 2026-08-18 the `recorder` runner died of three unhandled ffmpeg spawn
93
+ * errors, the breaker stopped respawning it (correctly), `/health` kept
94
+ * returning 200, and fleet-wide recording was gone for 3h15 before the
95
+ * operator's phone told him. The Notification Center's system-event intake
96
+ * consumes this category and maps it to the `addon-crash-loop` kind.
97
+ */
98
+ EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
83
99
  EventCategory["AddonError"] = "addon.error";
84
100
  EventCategory["AddonPageReady"] = "addon.page-ready";
85
101
  EventCategory["AddonWidgetReady"] = "addon.widget-ready";
@@ -7832,6 +7848,12 @@ var RecordingConfigSchema = object({
7832
7848
  /** DERIVED summary of `bands`, stamped by the recorder on every save.
7833
7849
  * Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
7834
7850
  mode: RecordingStorageModeSchema.optional(),
7851
+ /**
7852
+ * Which assigned broker slots to record. Absent / empty = {@link
7853
+ * DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
7854
+ * camera's currently assigned slots — never `mid` unless the operator
7855
+ * picks it, and never a slot the broker has not assigned.
7856
+ */
7835
7857
  profiles: array(CamProfileSchema).optional(),
7836
7858
  segmentSeconds: number$1().int().positive().optional(),
7837
7859
  /**
@@ -7912,7 +7934,11 @@ var RelocateFootageInputSchema = object({
7912
7934
  profiles: array(string()).optional(),
7913
7935
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
7914
7936
  * never allowed to starve live writers. */
7915
- throttleMbps: number$1().min(1).max(1e3).optional()
7937
+ throttleMbps: number$1().min(1).max(1e3).optional(),
7938
+ /** Move only segments whose startMs is >= this. Absent = the whole source
7939
+ * pile. Used when a full drain is too expensive and the operator only
7940
+ * wants the recent window on the new disk. */
7941
+ sinceMs: number$1().int().optional()
7916
7942
  });
7917
7943
  /** Internal, lease-scoped participant operation. It is intentionally separate
7918
7944
  * from persistent recording settings: a migration never changes
@@ -14556,6 +14582,7 @@ var NcSystemEventKindSchema = _enum([
14556
14582
  "node-offline",
14557
14583
  "node-inference-unavailable",
14558
14584
  "detection-blind",
14585
+ "addon-crash-loop",
14559
14586
  "addon-update-available",
14560
14587
  "server-update-available",
14561
14588
  "alarm-triggered",
@@ -17129,6 +17156,12 @@ var TrackCascadeCountsSchema = object({
17129
17156
  /** Per-track CLIP search vectors removed (best-effort). */
17130
17157
  embeddings: number$1().int()
17131
17158
  });
17159
+ /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17160
+ var DiskReconcileCountsSchema = object({
17161
+ mediaDropped: number$1().int(),
17162
+ tracks: number$1().int(),
17163
+ events: number$1().int()
17164
+ });
17132
17165
  /** Event-store footprint for one camera. */
17133
17166
  var EventStoreDeviceFootprintSchema = object({
17134
17167
  deviceId: number$1(),
@@ -17305,6 +17338,9 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
17305
17338
  }), method(object({ deviceId: number$1() }), TrackCascadeCountsSchema, {
17306
17339
  kind: "mutation",
17307
17340
  auth: "admin"
17341
+ }), method(object({ deviceId: number$1() }), DiskReconcileCountsSchema, {
17342
+ kind: "mutation",
17343
+ auth: "admin"
17308
17344
  }), method(object({
17309
17345
  deviceId: number$1(),
17310
17346
  trackIds: array(string()).min(1)
@@ -18815,6 +18851,24 @@ var CameraStatusDegradationSchema = object({
18815
18851
  *
18816
18852
  * See spec: `docs/superpowers/specs/2026-06-24-camera-status-aggregator-cap.md`
18817
18853
  */
18854
+ var DiskReconcileJobSchema = object({
18855
+ state: _enum([
18856
+ "idle",
18857
+ "running",
18858
+ "done",
18859
+ "error"
18860
+ ]),
18861
+ total: number$1().int().nonnegative(),
18862
+ completed: number$1().int().nonnegative(),
18863
+ currentDeviceId: number$1().int().nullable(),
18864
+ failed: array(number$1().int()).readonly(),
18865
+ mediaDropped: number$1().int().nonnegative(),
18866
+ tracks: number$1().int().nonnegative(),
18867
+ events: number$1().int().nonnegative(),
18868
+ startedAtMs: number$1().int().nullable(),
18869
+ finishedAtMs: number$1().int().nullable(),
18870
+ error: string().nullable()
18871
+ });
18818
18872
  var CameraStatusSchema = object({
18819
18873
  deviceId: number$1(),
18820
18874
  assignment: CameraAssignmentStatusSchema,
@@ -19046,7 +19100,10 @@ method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
19046
19100
  }), CameraSwitchGroupSchema, {
19047
19101
  kind: "mutation",
19048
19102
  auth: "admin"
19049
- }), method(object({ deviceId: number$1() }), CameraStatusSchema), method(object({ deviceIds: array(number$1()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
19103
+ }), method(object({ deviceId: number$1() }), CameraStatusSchema), method(object({ deviceIds: array(number$1()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), DiskReconcileJobSchema, {
19104
+ kind: "mutation",
19105
+ auth: "admin"
19106
+ }), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
19050
19107
  name: string(),
19051
19108
  description: string().optional(),
19052
19109
  config: CameraPipelineConfigSchema
@@ -20119,20 +20176,6 @@ var VectorStatsResultSchema = object({
20119
20176
  exact: boolean()
20120
20177
  });
20121
20178
  method(VectorDeclareIndexInputSchema, _void(), { kind: "mutation" }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, { kind: "mutation" }), method(VectorQueryInputSchema, VectorQueryResultSchema), method(VectorGetInputSchema, VectorGetResultSchema), method(VectorDeleteInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorStatsInputSchema, VectorStatsResultSchema);
20122
- /**
20123
- * `videoclips` — the unified, navigable-clip surface for a camera.
20124
- *
20125
- * A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
20126
- * provider per device, substitutable. The DEFAULT provider (registered by
20127
- * `addon-post-analysis`, `defaultActive: true`) composes the analytics event
20128
- * log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
20129
- * is a time-WINDOW over existing footage, never a separate file. A camera that
20130
- * exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
20131
- * wrapper provider for its device and serve its own clip catalog + URLs.
20132
- *
20133
- * A `Clip` is purely time-based (subtree-blind): playback resolves segments by
20134
- * temporal overlap, so the API never decides `continuous` vs `events`.
20135
- */
20136
20179
  var ClipSchema = object({
20137
20180
  /** Opaque, provider-namespaced id. The default provider encodes the time
20138
20181
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -20158,12 +20201,41 @@ var ClipSchema = object({
20158
20201
  * of the event that owns `kind` (object > motion > audio). Do not extract
20159
20202
  * a keyframe from the recorded segments. Other providers (onboard, HKSV)
20160
20203
  * mint their own stills.
20204
+ *
20205
+ * **VOUCHED, never fabricated.** A provider emits this only for an event it
20206
+ * has CONFIRMED owns at least one media row (its own, or its owning track's).
20207
+ * Absent is meaningful — "this visit has no event still" — never "we did not
20208
+ * look". Stamping it from a URL template made 35% of one camera's clips point
20209
+ * at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
20210
+ * A read that FAILS drops the claim; it never invents it.
20161
20211
  */
20162
20212
  thumbnail: string().optional(),
20163
- /** Analytics event ids that overlap this visit. Empty on footage-only clips.
20164
- * The default provider's visit grain puts many motion heartbeats on one clip
20165
- * instead of minting one clip per marker. */
20213
+ /**
20214
+ * An instant INSIDE this visit's footage, hole-safe, where a recorded still
20215
+ * can be decoded. Present whenever the visit came from recorded availability;
20216
+ * absent on a per-event padded window (there is no footage to promise).
20217
+ *
20218
+ * This is not a thumbnail and not a second byte path: it is the argument to
20219
+ * the recorder's existing still route. The surface — never the provider —
20220
+ * decides whether to use it. It is the midpoint of the visit's LONGEST
20221
+ * contiguous range, not of the visit: a visit spans its holes by
20222
+ * construction, so a naive midpoint lands in dead air.
20223
+ */
20224
+ stillAtMs: number$1().optional(),
20225
+ /**
20226
+ * Analytics event ids that overlap this visit — a BOUNDED sample, newest
20227
+ * first within kind (object → motion → audio), capped at
20228
+ * {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
20229
+ *
20230
+ * Bounded because it is not a payload the surface pages through: one visit on
20231
+ * device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
20232
+ * camera-day. Read {@link eventCount} for the true total.
20233
+ */
20166
20234
  eventIds: array(string()).optional(),
20235
+ /** How many analytics events actually overlap this visit. Differs from
20236
+ * `eventIds.length` exactly when the sample was capped — so a truncated
20237
+ * list is never mistaken for a quiet visit. */
20238
+ eventCount: number$1().int().nonnegative().optional(),
20167
20239
  /** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
20168
20240
  * than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
20169
20241
  * bar keeps showing them via `recording.getAvailability`. */
@@ -20634,7 +20706,14 @@ var SearchResultSchema = object({
20634
20706
  });
20635
20707
  var AutoUpdateSettingsSchema = object({
20636
20708
  channel: ChannelSchema,
20637
- intervalSeconds: number$1()
20709
+ intervalSeconds: number$1(),
20710
+ /**
20711
+ * Cadence of the "an update exists" POLLER, in seconds. Independent of
20712
+ * `channel`: the poller runs while auto-apply is `off`, because being told
20713
+ * about a publish and installing it are different decisions. Clamped
20714
+ * server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
20715
+ */
20716
+ updateCheckIntervalSeconds: number$1()
20638
20717
  });
20639
20718
  var AddonAutoUpdateSchema = ChannelWithInheritSchema;
20640
20719
  var RestartAddonResultSchema = unknown();
@@ -20775,7 +20854,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
20775
20854
  auth: "admin"
20776
20855
  }), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
20777
20856
  channel: ChannelSchema,
20778
- intervalSeconds: number$1().min(300).max(86400).optional()
20857
+ intervalSeconds: number$1().min(300).max(86400).optional(),
20858
+ /** Availability-poll cadence; see AutoUpdateSettingsSchema. */
20859
+ updateCheckIntervalSeconds: number$1().min(900).max(604800).optional()
20779
20860
  }), unknown(), {
20780
20861
  kind: "mutation",
20781
20862
  auth: "admin"
@@ -29440,6 +29521,12 @@ Object.freeze({
29440
29521
  addonId: null,
29441
29522
  access: "create"
29442
29523
  },
29524
+ "pipelineAnalytics.reconcileFromDisk": {
29525
+ capName: "pipeline-analytics",
29526
+ capScope: "device",
29527
+ addonId: null,
29528
+ access: "create"
29529
+ },
29443
29530
  "pipelineAnalytics.refreshStorageLocationsForMigration": {
29444
29531
  capName: "pipeline-analytics",
29445
29532
  capScope: "device",
@@ -29842,6 +29929,12 @@ Object.freeze({
29842
29929
  addonId: null,
29843
29930
  access: "view"
29844
29931
  },
29932
+ "pipelineOrchestrator.getReconcileFromDiskStatus": {
29933
+ capName: "pipeline-orchestrator",
29934
+ capScope: "system",
29935
+ addonId: null,
29936
+ access: "view"
29937
+ },
29845
29938
  "pipelineOrchestrator.listAgentSettings": {
29846
29939
  capName: "pipeline-orchestrator",
29847
29940
  capScope: "system",
@@ -29866,6 +29959,12 @@ Object.freeze({
29866
29959
  addonId: null,
29867
29960
  access: "create"
29868
29961
  },
29962
+ "pipelineOrchestrator.reconcileFromDisk": {
29963
+ capName: "pipeline-orchestrator",
29964
+ capScope: "system",
29965
+ addonId: null,
29966
+ access: "create"
29967
+ },
29869
29968
  "pipelineOrchestrator.removeAgentSettings": {
29870
29969
  capName: "pipeline-orchestrator",
29871
29970
  capScope: "system",
@@ -32857,6 +32956,11 @@ Object.freeze({
32857
32956
  form: "single",
32858
32957
  optional: true
32859
32958
  }],
32959
+ "pipelineAnalytics.reconcileFromDisk": [{
32960
+ name: "deviceId",
32961
+ form: "single",
32962
+ optional: false
32963
+ }],
32860
32964
  "pipelineAnalytics.restageRetrainTrack": [{
32861
32965
  name: "deviceId",
32862
32966
  form: "single",
@@ -33922,6 +34026,8 @@ DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
33922
34026
  DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
33923
34027
  DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
33924
34028
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
34029
+ var MB = 1024 * 1024;
34030
+ 1024 * MB, 3072 * MB;
33925
34031
  //#endregion
33926
34032
  //#region ../../node_modules/@ai-sdk/provider/dist/index.js
33927
34033
  var marker$2 = "vercel.ai.error";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-ai",
3
- "version": "0.4.9",
3
+ "version": "0.4.10",
4
4
  "description": "AI addon for CamStack — the `llm` collection provider (cloud, LAN, and camstack-managed local llama.cpp profiles) plus the per-node `llm-runtime` managed executor.",
5
5
  "keywords": [
6
6
  "camstack",