@camstack/addon-ai 0.4.9 → 0.4.11
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.
- package/dist/addon.js +136 -22
- package/dist/addon.mjs +136 -22
- 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-
|
|
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(),
|
|
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). */
|
|
@@ -20124,6 +20167,14 @@ var ClipSchema = object({
|
|
|
20124
20167
|
endMs: number$1()
|
|
20125
20168
|
}),
|
|
20126
20169
|
/**
|
|
20170
|
+
* Distinct object classes attached to this visit (`person`, `car`, …),
|
|
20171
|
+
* dominant first, capped at {@link MAX_CLIP_LABELS}. The ribbon renders these
|
|
20172
|
+
* instead of the bare kind — "Object" tells the operator nothing a colour bar
|
|
20173
|
+
* did not. Absent (never empty) when the visit attached no classified object
|
|
20174
|
+
* event, so a motion/audio-only visit keeps its kind label.
|
|
20175
|
+
*/
|
|
20176
|
+
labels: array(string()).max(3).optional(),
|
|
20177
|
+
/**
|
|
20127
20178
|
* Lazy thumbnail URL, never inlined.
|
|
20128
20179
|
*
|
|
20129
20180
|
* Recording-derived clips (events-mode keep-window, and the prepared
|
|
@@ -20132,12 +20183,41 @@ var ClipSchema = object({
|
|
|
20132
20183
|
* of the event that owns `kind` (object > motion > audio). Do not extract
|
|
20133
20184
|
* a keyframe from the recorded segments. Other providers (onboard, HKSV)
|
|
20134
20185
|
* mint their own stills.
|
|
20186
|
+
*
|
|
20187
|
+
* **VOUCHED, never fabricated.** A provider emits this only for an event it
|
|
20188
|
+
* has CONFIRMED owns at least one media row (its own, or its owning track's).
|
|
20189
|
+
* Absent is meaningful — "this visit has no event still" — never "we did not
|
|
20190
|
+
* look". Stamping it from a URL template made 35% of one camera's clips point
|
|
20191
|
+
* at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
|
|
20192
|
+
* A read that FAILS drops the claim; it never invents it.
|
|
20135
20193
|
*/
|
|
20136
20194
|
thumbnail: string().optional(),
|
|
20137
|
-
/**
|
|
20138
|
-
*
|
|
20139
|
-
*
|
|
20195
|
+
/**
|
|
20196
|
+
* An instant INSIDE this visit's footage, hole-safe, where a recorded still
|
|
20197
|
+
* can be decoded. Present whenever the visit came from recorded availability;
|
|
20198
|
+
* absent on a per-event padded window (there is no footage to promise).
|
|
20199
|
+
*
|
|
20200
|
+
* This is not a thumbnail and not a second byte path: it is the argument to
|
|
20201
|
+
* the recorder's existing still route. The surface — never the provider —
|
|
20202
|
+
* decides whether to use it. It is the midpoint of the visit's LONGEST
|
|
20203
|
+
* contiguous range, not of the visit: a visit spans its holes by
|
|
20204
|
+
* construction, so a naive midpoint lands in dead air.
|
|
20205
|
+
*/
|
|
20206
|
+
stillAtMs: number$1().optional(),
|
|
20207
|
+
/**
|
|
20208
|
+
* Analytics event ids that overlap this visit — a BOUNDED sample, newest
|
|
20209
|
+
* first within kind (object → motion → audio), capped at
|
|
20210
|
+
* {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
|
|
20211
|
+
*
|
|
20212
|
+
* Bounded because it is not a payload the surface pages through: one visit on
|
|
20213
|
+
* device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
|
|
20214
|
+
* camera-day. Read {@link eventCount} for the true total.
|
|
20215
|
+
*/
|
|
20140
20216
|
eventIds: array(string()).optional(),
|
|
20217
|
+
/** How many analytics events actually overlap this visit. Differs from
|
|
20218
|
+
* `eventIds.length` exactly when the sample was capped — so a truncated
|
|
20219
|
+
* list is never mistaken for a quiet visit. */
|
|
20220
|
+
eventCount: number$1().int().nonnegative().optional(),
|
|
20141
20221
|
/** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
|
|
20142
20222
|
* than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
|
|
20143
20223
|
* bar keeps showing them via `recording.getAvailability`. */
|
|
@@ -20608,7 +20688,14 @@ var SearchResultSchema = object({
|
|
|
20608
20688
|
});
|
|
20609
20689
|
var AutoUpdateSettingsSchema = object({
|
|
20610
20690
|
channel: ChannelSchema,
|
|
20611
|
-
intervalSeconds: number$1()
|
|
20691
|
+
intervalSeconds: number$1(),
|
|
20692
|
+
/**
|
|
20693
|
+
* Cadence of the "an update exists" POLLER, in seconds. Independent of
|
|
20694
|
+
* `channel`: the poller runs while auto-apply is `off`, because being told
|
|
20695
|
+
* about a publish and installing it are different decisions. Clamped
|
|
20696
|
+
* server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
|
|
20697
|
+
*/
|
|
20698
|
+
updateCheckIntervalSeconds: number$1()
|
|
20612
20699
|
});
|
|
20613
20700
|
var AddonAutoUpdateSchema = ChannelWithInheritSchema;
|
|
20614
20701
|
var RestartAddonResultSchema = unknown();
|
|
@@ -20749,7 +20836,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
|
|
|
20749
20836
|
auth: "admin"
|
|
20750
20837
|
}), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
|
|
20751
20838
|
channel: ChannelSchema,
|
|
20752
|
-
intervalSeconds: number$1().min(300).max(86400).optional()
|
|
20839
|
+
intervalSeconds: number$1().min(300).max(86400).optional(),
|
|
20840
|
+
/** Availability-poll cadence; see AutoUpdateSettingsSchema. */
|
|
20841
|
+
updateCheckIntervalSeconds: number$1().min(900).max(604800).optional()
|
|
20753
20842
|
}), unknown(), {
|
|
20754
20843
|
kind: "mutation",
|
|
20755
20844
|
auth: "admin"
|
|
@@ -29414,6 +29503,12 @@ Object.freeze({
|
|
|
29414
29503
|
addonId: null,
|
|
29415
29504
|
access: "create"
|
|
29416
29505
|
},
|
|
29506
|
+
"pipelineAnalytics.reconcileFromDisk": {
|
|
29507
|
+
capName: "pipeline-analytics",
|
|
29508
|
+
capScope: "device",
|
|
29509
|
+
addonId: null,
|
|
29510
|
+
access: "create"
|
|
29511
|
+
},
|
|
29417
29512
|
"pipelineAnalytics.refreshStorageLocationsForMigration": {
|
|
29418
29513
|
capName: "pipeline-analytics",
|
|
29419
29514
|
capScope: "device",
|
|
@@ -29816,6 +29911,12 @@ Object.freeze({
|
|
|
29816
29911
|
addonId: null,
|
|
29817
29912
|
access: "view"
|
|
29818
29913
|
},
|
|
29914
|
+
"pipelineOrchestrator.getReconcileFromDiskStatus": {
|
|
29915
|
+
capName: "pipeline-orchestrator",
|
|
29916
|
+
capScope: "system",
|
|
29917
|
+
addonId: null,
|
|
29918
|
+
access: "view"
|
|
29919
|
+
},
|
|
29819
29920
|
"pipelineOrchestrator.listAgentSettings": {
|
|
29820
29921
|
capName: "pipeline-orchestrator",
|
|
29821
29922
|
capScope: "system",
|
|
@@ -29840,6 +29941,12 @@ Object.freeze({
|
|
|
29840
29941
|
addonId: null,
|
|
29841
29942
|
access: "create"
|
|
29842
29943
|
},
|
|
29944
|
+
"pipelineOrchestrator.reconcileFromDisk": {
|
|
29945
|
+
capName: "pipeline-orchestrator",
|
|
29946
|
+
capScope: "system",
|
|
29947
|
+
addonId: null,
|
|
29948
|
+
access: "create"
|
|
29949
|
+
},
|
|
29843
29950
|
"pipelineOrchestrator.removeAgentSettings": {
|
|
29844
29951
|
capName: "pipeline-orchestrator",
|
|
29845
29952
|
capScope: "system",
|
|
@@ -32831,6 +32938,11 @@ Object.freeze({
|
|
|
32831
32938
|
form: "single",
|
|
32832
32939
|
optional: true
|
|
32833
32940
|
}],
|
|
32941
|
+
"pipelineAnalytics.reconcileFromDisk": [{
|
|
32942
|
+
name: "deviceId",
|
|
32943
|
+
form: "single",
|
|
32944
|
+
optional: false
|
|
32945
|
+
}],
|
|
32834
32946
|
"pipelineAnalytics.restageRetrainTrack": [{
|
|
32835
32947
|
name: "deviceId",
|
|
32836
32948
|
form: "single",
|
|
@@ -33896,6 +34008,8 @@ DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
|
|
|
33896
34008
|
DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
|
|
33897
34009
|
DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
33898
34010
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
34011
|
+
var MB = 1024 * 1024;
|
|
34012
|
+
1024 * MB, 3072 * MB;
|
|
33899
34013
|
//#endregion
|
|
33900
34014
|
//#region ../../node_modules/@ai-sdk/provider/dist/index.js
|
|
33901
34015
|
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-
|
|
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(),
|
|
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). */
|
|
@@ -20150,6 +20193,14 @@ var ClipSchema = object({
|
|
|
20150
20193
|
endMs: number$1()
|
|
20151
20194
|
}),
|
|
20152
20195
|
/**
|
|
20196
|
+
* Distinct object classes attached to this visit (`person`, `car`, …),
|
|
20197
|
+
* dominant first, capped at {@link MAX_CLIP_LABELS}. The ribbon renders these
|
|
20198
|
+
* instead of the bare kind — "Object" tells the operator nothing a colour bar
|
|
20199
|
+
* did not. Absent (never empty) when the visit attached no classified object
|
|
20200
|
+
* event, so a motion/audio-only visit keeps its kind label.
|
|
20201
|
+
*/
|
|
20202
|
+
labels: array(string()).max(3).optional(),
|
|
20203
|
+
/**
|
|
20153
20204
|
* Lazy thumbnail URL, never inlined.
|
|
20154
20205
|
*
|
|
20155
20206
|
* Recording-derived clips (events-mode keep-window, and the prepared
|
|
@@ -20158,12 +20209,41 @@ var ClipSchema = object({
|
|
|
20158
20209
|
* of the event that owns `kind` (object > motion > audio). Do not extract
|
|
20159
20210
|
* a keyframe from the recorded segments. Other providers (onboard, HKSV)
|
|
20160
20211
|
* mint their own stills.
|
|
20212
|
+
*
|
|
20213
|
+
* **VOUCHED, never fabricated.** A provider emits this only for an event it
|
|
20214
|
+
* has CONFIRMED owns at least one media row (its own, or its owning track's).
|
|
20215
|
+
* Absent is meaningful — "this visit has no event still" — never "we did not
|
|
20216
|
+
* look". Stamping it from a URL template made 35% of one camera's clips point
|
|
20217
|
+
* at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
|
|
20218
|
+
* A read that FAILS drops the claim; it never invents it.
|
|
20161
20219
|
*/
|
|
20162
20220
|
thumbnail: string().optional(),
|
|
20163
|
-
/**
|
|
20164
|
-
*
|
|
20165
|
-
*
|
|
20221
|
+
/**
|
|
20222
|
+
* An instant INSIDE this visit's footage, hole-safe, where a recorded still
|
|
20223
|
+
* can be decoded. Present whenever the visit came from recorded availability;
|
|
20224
|
+
* absent on a per-event padded window (there is no footage to promise).
|
|
20225
|
+
*
|
|
20226
|
+
* This is not a thumbnail and not a second byte path: it is the argument to
|
|
20227
|
+
* the recorder's existing still route. The surface — never the provider —
|
|
20228
|
+
* decides whether to use it. It is the midpoint of the visit's LONGEST
|
|
20229
|
+
* contiguous range, not of the visit: a visit spans its holes by
|
|
20230
|
+
* construction, so a naive midpoint lands in dead air.
|
|
20231
|
+
*/
|
|
20232
|
+
stillAtMs: number$1().optional(),
|
|
20233
|
+
/**
|
|
20234
|
+
* Analytics event ids that overlap this visit — a BOUNDED sample, newest
|
|
20235
|
+
* first within kind (object → motion → audio), capped at
|
|
20236
|
+
* {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
|
|
20237
|
+
*
|
|
20238
|
+
* Bounded because it is not a payload the surface pages through: one visit on
|
|
20239
|
+
* device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
|
|
20240
|
+
* camera-day. Read {@link eventCount} for the true total.
|
|
20241
|
+
*/
|
|
20166
20242
|
eventIds: array(string()).optional(),
|
|
20243
|
+
/** How many analytics events actually overlap this visit. Differs from
|
|
20244
|
+
* `eventIds.length` exactly when the sample was capped — so a truncated
|
|
20245
|
+
* list is never mistaken for a quiet visit. */
|
|
20246
|
+
eventCount: number$1().int().nonnegative().optional(),
|
|
20167
20247
|
/** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
|
|
20168
20248
|
* than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
|
|
20169
20249
|
* bar keeps showing them via `recording.getAvailability`. */
|
|
@@ -20634,7 +20714,14 @@ var SearchResultSchema = object({
|
|
|
20634
20714
|
});
|
|
20635
20715
|
var AutoUpdateSettingsSchema = object({
|
|
20636
20716
|
channel: ChannelSchema,
|
|
20637
|
-
intervalSeconds: number$1()
|
|
20717
|
+
intervalSeconds: number$1(),
|
|
20718
|
+
/**
|
|
20719
|
+
* Cadence of the "an update exists" POLLER, in seconds. Independent of
|
|
20720
|
+
* `channel`: the poller runs while auto-apply is `off`, because being told
|
|
20721
|
+
* about a publish and installing it are different decisions. Clamped
|
|
20722
|
+
* server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
|
|
20723
|
+
*/
|
|
20724
|
+
updateCheckIntervalSeconds: number$1()
|
|
20638
20725
|
});
|
|
20639
20726
|
var AddonAutoUpdateSchema = ChannelWithInheritSchema;
|
|
20640
20727
|
var RestartAddonResultSchema = unknown();
|
|
@@ -20775,7 +20862,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
|
|
|
20775
20862
|
auth: "admin"
|
|
20776
20863
|
}), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
|
|
20777
20864
|
channel: ChannelSchema,
|
|
20778
|
-
intervalSeconds: number$1().min(300).max(86400).optional()
|
|
20865
|
+
intervalSeconds: number$1().min(300).max(86400).optional(),
|
|
20866
|
+
/** Availability-poll cadence; see AutoUpdateSettingsSchema. */
|
|
20867
|
+
updateCheckIntervalSeconds: number$1().min(900).max(604800).optional()
|
|
20779
20868
|
}), unknown(), {
|
|
20780
20869
|
kind: "mutation",
|
|
20781
20870
|
auth: "admin"
|
|
@@ -29440,6 +29529,12 @@ Object.freeze({
|
|
|
29440
29529
|
addonId: null,
|
|
29441
29530
|
access: "create"
|
|
29442
29531
|
},
|
|
29532
|
+
"pipelineAnalytics.reconcileFromDisk": {
|
|
29533
|
+
capName: "pipeline-analytics",
|
|
29534
|
+
capScope: "device",
|
|
29535
|
+
addonId: null,
|
|
29536
|
+
access: "create"
|
|
29537
|
+
},
|
|
29443
29538
|
"pipelineAnalytics.refreshStorageLocationsForMigration": {
|
|
29444
29539
|
capName: "pipeline-analytics",
|
|
29445
29540
|
capScope: "device",
|
|
@@ -29842,6 +29937,12 @@ Object.freeze({
|
|
|
29842
29937
|
addonId: null,
|
|
29843
29938
|
access: "view"
|
|
29844
29939
|
},
|
|
29940
|
+
"pipelineOrchestrator.getReconcileFromDiskStatus": {
|
|
29941
|
+
capName: "pipeline-orchestrator",
|
|
29942
|
+
capScope: "system",
|
|
29943
|
+
addonId: null,
|
|
29944
|
+
access: "view"
|
|
29945
|
+
},
|
|
29845
29946
|
"pipelineOrchestrator.listAgentSettings": {
|
|
29846
29947
|
capName: "pipeline-orchestrator",
|
|
29847
29948
|
capScope: "system",
|
|
@@ -29866,6 +29967,12 @@ Object.freeze({
|
|
|
29866
29967
|
addonId: null,
|
|
29867
29968
|
access: "create"
|
|
29868
29969
|
},
|
|
29970
|
+
"pipelineOrchestrator.reconcileFromDisk": {
|
|
29971
|
+
capName: "pipeline-orchestrator",
|
|
29972
|
+
capScope: "system",
|
|
29973
|
+
addonId: null,
|
|
29974
|
+
access: "create"
|
|
29975
|
+
},
|
|
29869
29976
|
"pipelineOrchestrator.removeAgentSettings": {
|
|
29870
29977
|
capName: "pipeline-orchestrator",
|
|
29871
29978
|
capScope: "system",
|
|
@@ -32857,6 +32964,11 @@ Object.freeze({
|
|
|
32857
32964
|
form: "single",
|
|
32858
32965
|
optional: true
|
|
32859
32966
|
}],
|
|
32967
|
+
"pipelineAnalytics.reconcileFromDisk": [{
|
|
32968
|
+
name: "deviceId",
|
|
32969
|
+
form: "single",
|
|
32970
|
+
optional: false
|
|
32971
|
+
}],
|
|
32860
32972
|
"pipelineAnalytics.restageRetrainTrack": [{
|
|
32861
32973
|
name: "deviceId",
|
|
32862
32974
|
form: "single",
|
|
@@ -33922,6 +34034,8 @@ DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
|
|
|
33922
34034
|
DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
|
|
33923
34035
|
DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
33924
34036
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
34037
|
+
var MB = 1024 * 1024;
|
|
34038
|
+
1024 * MB, 3072 * MB;
|
|
33925
34039
|
//#endregion
|
|
33926
34040
|
//#region ../../node_modules/@ai-sdk/provider/dist/index.js
|
|
33927
34041
|
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.
|
|
3
|
+
"version": "0.4.11",
|
|
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",
|