@camstack/addon-ai 0.2.13 → 0.2.14

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 +353 -114
  2. package/dist/addon.mjs +353 -114
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -43,7 +43,7 @@ let node_fs_promises = require("node:fs/promises");
43
43
  node_fs_promises = __toESM(node_fs_promises);
44
44
  let node_child_process = require("node:child_process");
45
45
  let node_net = require("node:net");
46
- //#region ../types/dist/event-category-Bz24uP1U.mjs
46
+ //#region ../types/dist/event-category-41fKf-q9.mjs
47
47
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
48
48
  EventCategory["SystemBoot"] = "system.boot";
49
49
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -103,6 +103,26 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
103
103
  */
104
104
  EventCategory["AddonRetryScheduled"] = "addon.retry-scheduled";
105
105
  /**
106
+ * A liveness invariant of this node is false — it has no devices, every
107
+ * camera is offline, or a camera that was recording has stopped producing
108
+ * segments. Emitted by the `liveness-monitor` builtin, once per fault (the
109
+ * `findingId` is stable across ticks), only after its boot grace period.
110
+ * AlertCenter raises a persistent operator-visible alert.
111
+ *
112
+ * It exists because on 2026-08-03 the hub ran four hours with zero devices
113
+ * and zero recordings while every surface stayed quiet.
114
+ *
115
+ * Payload: `{ findingId, severity, title, message, deviceId? }`.
116
+ */
117
+ EventCategory["SystemLivenessFailed"] = "system.liveness-failed";
118
+ /**
119
+ * A previously reported liveness fault is true again. AlertCenter dismisses
120
+ * the matching `SystemLivenessFailed` alert.
121
+ *
122
+ * Payload: `{ findingId }`.
123
+ */
124
+ EventCategory["SystemLivenessRecovered"] = "system.liveness-recovered";
125
+ /**
106
126
  * Monitor is attempting to reload a failed addon NOW. UI uses this
107
127
  * to show a spinner during the retry attempt. Same transient nature
108
128
  * as AddonRetryScheduled.
@@ -7383,14 +7403,7 @@ var RecordingConfigSchema = object({
7383
7403
  * windows only — existing sheets are immutable, and each window's index
7384
7404
  * carries its own tile dims so mixed-preset history renders correctly.
7385
7405
  */
7386
- scrubThumbnails: ScrubThumbnailPresetSchema.optional(),
7387
- /**
7388
- * OPT-IN thumbnail-strip generation for this camera: every keyframe of the
7389
- * low recording saved as a JPEG (the fast-drag scrub depth), a derived
7390
- * cache that eviction reclaims with the footage. Absent/false = no strips
7391
- * are written and scrub reads exact keyframes at every velocity.
7392
- */
7393
- stripsEnabled: boolean().optional()
7406
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7394
7407
  }).strict();
7395
7408
  /**
7396
7409
  * Ops-log — the durable, append-only operations audit shared by the
@@ -7452,7 +7465,7 @@ var OpsLogQueryInputSchema = object({
7452
7465
  /**
7453
7466
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
7454
7467
  *
7455
- * One shape shared by the recorder's `relocateFootage` (segments + strips) and
7468
+ * One shape shared by the recorder's `relocateFootage` (segments) and
7456
7469
  * pipeline-analytics' `relocateMedia` (event media blobs) so the admin Data
7457
7470
  * page renders both movers with one component. Jobs are in-RAM (a restart
7458
7471
  * forgets them — re-running is safe by construction: copy-if-absent, delete
@@ -7474,7 +7487,7 @@ var RelocateJobSchema = object({
7474
7487
  toLocationId: string(),
7475
7488
  /** Scoped device, or null = every device. */
7476
7489
  deviceId: number().nullable(),
7477
- /** What the job moves (owner-addon specific: segments/strips or media). */
7490
+ /** What the job moves (owner-addon specific: segments or media). */
7478
7491
  entities: array(string()),
7479
7492
  filesMoved: number().int(),
7480
7493
  bytesMoved: number().int(),
@@ -7488,7 +7501,7 @@ var RelocateFootageInputSchema = object({
7488
7501
  deviceId: number().optional(),
7489
7502
  fromLocationId: string(),
7490
7503
  toLocationId: string(),
7491
- entities: array(_enum(["segments", "strips"])).optional(),
7504
+ entities: array(_enum(["segments"])).optional(),
7492
7505
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
7493
7506
  * never allowed to starve live writers. */
7494
7507
  throttleMbps: number().min(1).max(1e3).optional()
@@ -15139,6 +15152,210 @@ method(object({ codec: string() }), boolean()), method(_void(), object({
15139
15152
  kind: "mutation",
15140
15153
  auth: "admin"
15141
15154
  });
15155
+ /**
15156
+ * Query filter for settings-store collections.
15157
+ */
15158
+ var QueryFilterSchema = object({
15159
+ where: record(string(), unknown()).optional(),
15160
+ whereIn: record(string(), array(unknown())).optional(),
15161
+ whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
15162
+ orderBy: object({
15163
+ field: string(),
15164
+ direction: _enum(["asc", "desc"])
15165
+ }).optional(),
15166
+ limit: number().optional(),
15167
+ offset: number().optional()
15168
+ });
15169
+ /**
15170
+ * The predicate half of a filter, for BULK MUTATIONS.
15171
+ *
15172
+ * Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
15173
+ * meaning for a statement that rewrites a set, and accepting them would invite
15174
+ * a caller to believe `limit` bounds the damage. Every field is optional here
15175
+ * only so the shape stays composable — the implementation REJECTS a filter
15176
+ * that compiles to no predicate, because that is the whole collection.
15177
+ */
15178
+ var MutationFilterSchema = object({
15179
+ where: record(string(), unknown()).optional(),
15180
+ whereIn: record(string(), array(unknown())).optional(),
15181
+ whereBetween: record(string(), tuple([unknown(), unknown()])).optional()
15182
+ });
15183
+ /** A single stored record: `{ id, data }`. */
15184
+ var SettingsRecordSchema = object({
15185
+ id: string(),
15186
+ data: record(string(), unknown())
15187
+ });
15188
+ /**
15189
+ * Column declaration for a structured (SQL-backed) collection.
15190
+ *
15191
+ * Logical types — the backend translates each to the matching SQLite
15192
+ * storage class and handles per-type marshaling:
15193
+ * - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
15194
+ * - `JSON` — TEXT under the hood; serialised on write, parsed on read
15195
+ * - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
15196
+ */
15197
+ var CollectionColumnSchema = object({
15198
+ name: string(),
15199
+ type: _enum([
15200
+ "TEXT",
15201
+ "INTEGER",
15202
+ "REAL",
15203
+ "JSON",
15204
+ "BOOLEAN"
15205
+ ]),
15206
+ primaryKey: boolean().optional(),
15207
+ notNull: boolean().optional(),
15208
+ unique: boolean().optional(),
15209
+ /**
15210
+ * Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
15211
+ * columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
15212
+ * collection surface simply cannot express their existing tables — which is
15213
+ * why they were still on the uncapped `table*` API.
15214
+ */
15215
+ defaultValue: union([
15216
+ string(),
15217
+ number(),
15218
+ boolean()
15219
+ ]).optional()
15220
+ });
15221
+ var CollectionIndexSchema = object({
15222
+ name: string(),
15223
+ columns: array(string()).readonly(),
15224
+ unique: boolean().optional()
15225
+ });
15226
+ method(object({
15227
+ namespace: string().optional(),
15228
+ collection: string(),
15229
+ key: string()
15230
+ }), unknown()), method(object({
15231
+ namespace: string().optional(),
15232
+ collection: string(),
15233
+ key: string(),
15234
+ value: unknown()
15235
+ }), _void(), { kind: "mutation" }), method(object({
15236
+ namespace: string().optional(),
15237
+ collection: string(),
15238
+ filter: QueryFilterSchema.optional()
15239
+ }), array(SettingsRecordSchema).readonly()), method(object({
15240
+ namespace: string().optional(),
15241
+ collection: string(),
15242
+ record: SettingsRecordSchema
15243
+ }), _void(), { kind: "mutation" }), method(object({
15244
+ namespace: string().optional(),
15245
+ collection: string(),
15246
+ id: string(),
15247
+ data: record(string(), unknown())
15248
+ }), _void(), { kind: "mutation" }), method(object({
15249
+ namespace: string().optional(),
15250
+ collection: string(),
15251
+ key: string()
15252
+ }), _void(), { kind: "mutation" }), method(object({
15253
+ namespace: string().optional(),
15254
+ collection: string(),
15255
+ filter: MutationFilterSchema
15256
+ }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
15257
+ namespace: string().optional(),
15258
+ collection: string(),
15259
+ filter: MutationFilterSchema,
15260
+ data: record(string(), unknown())
15261
+ }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
15262
+ namespace: string().optional(),
15263
+ collection: string(),
15264
+ filter: QueryFilterSchema.optional()
15265
+ }), number()), method(object({
15266
+ namespace: string().optional(),
15267
+ collection: string(),
15268
+ field: string(),
15269
+ bucketSize: number().int().positive(),
15270
+ origin: number().int(),
15271
+ filter: QueryFilterSchema.optional()
15272
+ }), array(object({
15273
+ bucket: number().int(),
15274
+ count: number().int()
15275
+ })).readonly()), method(object({
15276
+ namespace: string().optional(),
15277
+ collection: string()
15278
+ }), boolean()), method(object({
15279
+ namespace: string().optional(),
15280
+ collection: string(),
15281
+ columns: array(CollectionColumnSchema).readonly(),
15282
+ indexes: array(CollectionIndexSchema).readonly().optional()
15283
+ }), _void(), { kind: "mutation" });
15284
+ /**
15285
+ * What one engine says about itself. The orchestrator uses `kind` to pick
15286
+ * a registrant for a collection; `engineId` is what a log line names when
15287
+ * a call is routed or refused.
15288
+ */
15289
+ var EngineInfoSchema = object({
15290
+ engineId: string(),
15291
+ /**
15292
+ * `relational` — rows, columns, indexes, the surface `settings-store`
15293
+ * has always described. `vector` — an embedding store answering
15294
+ * similarity queries. A registrant declares exactly one; an engine that
15295
+ * does both registers twice, because "both" would make the routing
15296
+ * decision ambiguous at exactly the point it must not be.
15297
+ */
15298
+ kind: _enum(["relational", "vector"]),
15299
+ displayName: string()
15300
+ });
15301
+ method(_void(), EngineInfoSchema), method(object({
15302
+ namespace: string().optional(),
15303
+ collection: string(),
15304
+ key: string()
15305
+ }), unknown()), method(object({
15306
+ namespace: string().optional(),
15307
+ collection: string(),
15308
+ key: string(),
15309
+ value: unknown()
15310
+ }), _void(), { kind: "mutation" }), method(object({
15311
+ namespace: string().optional(),
15312
+ collection: string(),
15313
+ filter: QueryFilterSchema.optional()
15314
+ }), array(SettingsRecordSchema).readonly()), method(object({
15315
+ namespace: string().optional(),
15316
+ collection: string(),
15317
+ record: SettingsRecordSchema
15318
+ }), _void(), { kind: "mutation" }), method(object({
15319
+ namespace: string().optional(),
15320
+ collection: string(),
15321
+ id: string(),
15322
+ data: record(string(), unknown())
15323
+ }), _void(), { kind: "mutation" }), method(object({
15324
+ namespace: string().optional(),
15325
+ collection: string(),
15326
+ key: string()
15327
+ }), _void(), { kind: "mutation" }), method(object({
15328
+ namespace: string().optional(),
15329
+ collection: string(),
15330
+ filter: MutationFilterSchema
15331
+ }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
15332
+ namespace: string().optional(),
15333
+ collection: string(),
15334
+ filter: MutationFilterSchema,
15335
+ data: record(string(), unknown())
15336
+ }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
15337
+ namespace: string().optional(),
15338
+ collection: string(),
15339
+ filter: QueryFilterSchema.optional()
15340
+ }), number()), method(object({
15341
+ namespace: string().optional(),
15342
+ collection: string(),
15343
+ field: string(),
15344
+ bucketSize: number().int().positive(),
15345
+ origin: number().int(),
15346
+ filter: QueryFilterSchema.optional()
15347
+ }), array(object({
15348
+ bucket: number().int(),
15349
+ count: number().int()
15350
+ })).readonly()), method(object({
15351
+ namespace: string().optional(),
15352
+ collection: string()
15353
+ }), boolean()), method(object({
15354
+ namespace: string().optional(),
15355
+ collection: string(),
15356
+ columns: array(CollectionColumnSchema).readonly(),
15357
+ indexes: array(CollectionIndexSchema).readonly().optional()
15358
+ }), _void(), { kind: "mutation" });
15142
15359
  DeviceType.Camera;
15143
15360
  /**
15144
15361
  * `device-adoption` — generic discovery + adoption surface,
@@ -18416,6 +18633,28 @@ var ServerUpdateStateSchema = _enum([
18416
18633
  "pending-restart",
18417
18634
  "awaiting-confirmation"
18418
18635
  ]);
18636
+ var ImageContractSchema = object({
18637
+ state: _enum([
18638
+ "in-sync",
18639
+ "behind-patch",
18640
+ "behind-series",
18641
+ "ahead",
18642
+ "unknown"
18643
+ ]),
18644
+ /** The baked seed closure version — the image/app-bundle fingerprint. */
18645
+ seedVersion: string().nullable(),
18646
+ /** Best-known version the deployment contract delivers today. */
18647
+ contractVersion: string().nullable(),
18648
+ /**
18649
+ * Where `contractVersion` came from: a real registry check (`registry`), or
18650
+ * the node's own running version (`running` — a node can never run code
18651
+ * newer than the newest release, so `seed < running` proves image staleness
18652
+ * even before any registry check has run).
18653
+ */
18654
+ contractSource: _enum(["registry", "running"]).nullable(),
18655
+ /** One operator-grade sentence: this node runs image X; the contract says Y. */
18656
+ message: string()
18657
+ });
18419
18658
  var ServerRollbackInfoSchema = object({
18420
18659
  /** The version that failed (or was manually rolled back). */
18421
18660
  fromVersion: string(),
@@ -18452,7 +18691,12 @@ var ServerPackageStatusSchema = object({
18452
18691
  * versions are being IGNORED. Surfaced as a warning in the UI.
18453
18692
  */
18454
18693
  stateFileCorrupt: boolean(),
18455
- lastCheckedAtMs: number().nullable()
18694
+ lastCheckedAtMs: number().nullable(),
18695
+ /**
18696
+ * Seed-vs-contract verdict (see {@link ImageContractSchema}). Optional for
18697
+ * version skew: an older provider's payload simply omits it.
18698
+ */
18699
+ imageContract: ImageContractSchema.optional()
18456
18700
  });
18457
18701
  var ServerUpdateCheckResultSchema = object({
18458
18702
  packageName: string(),
@@ -18487,101 +18731,6 @@ version: string().optional() }), ServerUpdateActionResultSchema, {
18487
18731
  auth: "admin"
18488
18732
  });
18489
18733
  /**
18490
- * Query filter for settings-store collections.
18491
- */
18492
- var QueryFilterSchema = object({
18493
- where: record(string(), unknown()).optional(),
18494
- whereIn: record(string(), array(unknown())).optional(),
18495
- whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
18496
- orderBy: object({
18497
- field: string(),
18498
- direction: _enum(["asc", "desc"])
18499
- }).optional(),
18500
- limit: number().optional(),
18501
- offset: number().optional()
18502
- });
18503
- /** A single stored record: `{ id, data }`. */
18504
- var SettingsRecordSchema = object({
18505
- id: string(),
18506
- data: record(string(), unknown())
18507
- });
18508
- /**
18509
- * Column declaration for a structured (SQL-backed) collection.
18510
- *
18511
- * Logical types — the backend translates each to the matching SQLite
18512
- * storage class and handles per-type marshaling:
18513
- * - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
18514
- * - `JSON` — TEXT under the hood; serialised on write, parsed on read
18515
- * - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
18516
- */
18517
- var CollectionColumnSchema = object({
18518
- name: string(),
18519
- type: _enum([
18520
- "TEXT",
18521
- "INTEGER",
18522
- "REAL",
18523
- "JSON",
18524
- "BOOLEAN"
18525
- ]),
18526
- primaryKey: boolean().optional(),
18527
- notNull: boolean().optional(),
18528
- unique: boolean().optional()
18529
- });
18530
- var CollectionIndexSchema = object({
18531
- name: string(),
18532
- columns: array(string()).readonly(),
18533
- unique: boolean().optional()
18534
- });
18535
- method(object({
18536
- namespace: string().optional(),
18537
- collection: string(),
18538
- key: string()
18539
- }), unknown()), method(object({
18540
- namespace: string().optional(),
18541
- collection: string(),
18542
- key: string(),
18543
- value: unknown()
18544
- }), _void(), { kind: "mutation" }), method(object({
18545
- namespace: string().optional(),
18546
- collection: string(),
18547
- filter: QueryFilterSchema.optional()
18548
- }), array(SettingsRecordSchema).readonly()), method(object({
18549
- namespace: string().optional(),
18550
- collection: string(),
18551
- record: SettingsRecordSchema
18552
- }), _void(), { kind: "mutation" }), method(object({
18553
- namespace: string().optional(),
18554
- collection: string(),
18555
- id: string(),
18556
- data: record(string(), unknown())
18557
- }), _void(), { kind: "mutation" }), method(object({
18558
- namespace: string().optional(),
18559
- collection: string(),
18560
- key: string()
18561
- }), _void(), { kind: "mutation" }), method(object({
18562
- namespace: string().optional(),
18563
- collection: string(),
18564
- filter: QueryFilterSchema.optional()
18565
- }), number()), method(object({
18566
- namespace: string().optional(),
18567
- collection: string(),
18568
- field: string(),
18569
- bucketSize: number().int().positive(),
18570
- origin: number().int(),
18571
- filter: QueryFilterSchema.optional()
18572
- }), array(object({
18573
- bucket: number().int(),
18574
- count: number().int()
18575
- })).readonly()), method(object({
18576
- namespace: string().optional(),
18577
- collection: string()
18578
- }), boolean()), method(object({
18579
- namespace: string().optional(),
18580
- collection: string(),
18581
- columns: array(CollectionColumnSchema).readonly(),
18582
- indexes: array(CollectionIndexSchema).readonly().optional()
18583
- }), _void(), { kind: "mutation" });
18584
- /**
18585
18734
  * `smtp-provider` — pluggable email delivery surface.
18586
18735
  *
18587
18736
  * Collection cap: a deployment may install multiple SMTP relays (e.g.
@@ -22480,6 +22629,84 @@ Object.freeze({
22480
22629
  addonId: null,
22481
22630
  access: "view"
22482
22631
  },
22632
+ "dataStoreProvider.count": {
22633
+ capName: "data-store-provider",
22634
+ capScope: "system",
22635
+ addonId: null,
22636
+ access: "view"
22637
+ },
22638
+ "dataStoreProvider.declareCollection": {
22639
+ capName: "data-store-provider",
22640
+ capScope: "system",
22641
+ addonId: null,
22642
+ access: "create"
22643
+ },
22644
+ "dataStoreProvider.delete": {
22645
+ capName: "data-store-provider",
22646
+ capScope: "system",
22647
+ addonId: null,
22648
+ access: "delete"
22649
+ },
22650
+ "dataStoreProvider.deleteWhere": {
22651
+ capName: "data-store-provider",
22652
+ capScope: "system",
22653
+ addonId: null,
22654
+ access: "delete"
22655
+ },
22656
+ "dataStoreProvider.get": {
22657
+ capName: "data-store-provider",
22658
+ capScope: "system",
22659
+ addonId: null,
22660
+ access: "view"
22661
+ },
22662
+ "dataStoreProvider.getEngineInfo": {
22663
+ capName: "data-store-provider",
22664
+ capScope: "system",
22665
+ addonId: null,
22666
+ access: "view"
22667
+ },
22668
+ "dataStoreProvider.histogram": {
22669
+ capName: "data-store-provider",
22670
+ capScope: "system",
22671
+ addonId: null,
22672
+ access: "view"
22673
+ },
22674
+ "dataStoreProvider.insert": {
22675
+ capName: "data-store-provider",
22676
+ capScope: "system",
22677
+ addonId: null,
22678
+ access: "create"
22679
+ },
22680
+ "dataStoreProvider.isEmpty": {
22681
+ capName: "data-store-provider",
22682
+ capScope: "system",
22683
+ addonId: null,
22684
+ access: "view"
22685
+ },
22686
+ "dataStoreProvider.query": {
22687
+ capName: "data-store-provider",
22688
+ capScope: "system",
22689
+ addonId: null,
22690
+ access: "view"
22691
+ },
22692
+ "dataStoreProvider.set": {
22693
+ capName: "data-store-provider",
22694
+ capScope: "system",
22695
+ addonId: null,
22696
+ access: "create"
22697
+ },
22698
+ "dataStoreProvider.update": {
22699
+ capName: "data-store-provider",
22700
+ capScope: "system",
22701
+ addonId: null,
22702
+ access: "create"
22703
+ },
22704
+ "dataStoreProvider.updateWhere": {
22705
+ capName: "data-store-provider",
22706
+ capScope: "system",
22707
+ addonId: null,
22708
+ access: "create"
22709
+ },
22483
22710
  "dayNight.getOptions": {
22484
22711
  capName: "day-night",
22485
22712
  capScope: "device",
@@ -25558,6 +25785,12 @@ Object.freeze({
25558
25785
  addonId: null,
25559
25786
  access: "delete"
25560
25787
  },
25788
+ "settingsStore.deleteWhere": {
25789
+ capName: "settings-store",
25790
+ capScope: "system",
25791
+ addonId: null,
25792
+ access: "delete"
25793
+ },
25561
25794
  "settingsStore.get": {
25562
25795
  capName: "settings-store",
25563
25796
  capScope: "system",
@@ -25600,6 +25833,12 @@ Object.freeze({
25600
25833
  addonId: null,
25601
25834
  access: "create"
25602
25835
  },
25836
+ "settingsStore.updateWhere": {
25837
+ capName: "settings-store",
25838
+ capScope: "system",
25839
+ addonId: null,
25840
+ access: "create"
25841
+ },
25603
25842
  "smtpProvider.getStatus": {
25604
25843
  capName: "smtp-provider",
25605
25844
  capScope: "system",
@@ -27190,7 +27429,7 @@ var openAiAdapter = {
27190
27429
  * Per-consumer / per-purpose default profile rows (spec §3). Row id is the
27191
27430
  * stable selector key so `set` upserts and `set(selector, null)` deletes.
27192
27431
  */
27193
- var DEFAULTS_COLLECTION = "llm-defaults";
27432
+ var DEFAULTS_COLLECTION = "ai:llm-defaults";
27194
27433
  /** KV JSON-blob shape — a single `data` column routes through the settings
27195
27434
  * backend's canonical key/value path (id TEXT PK, data TEXT). */
27196
27435
  var KV_BLOB_COLUMNS$1 = [{
@@ -27230,7 +27469,7 @@ var DefaultsStore = class {
27230
27469
  selector,
27231
27470
  profileId
27232
27471
  };
27233
- if ((await this.store.query("llm-defaults")).some((r) => r.id === id)) await this.store.update(DEFAULTS_COLLECTION, id, data);
27472
+ if ((await this.store.query("ai:llm-defaults")).some((r) => r.id === id)) await this.store.update(DEFAULTS_COLLECTION, id, data);
27234
27473
  else await this.store.insert(DEFAULTS_COLLECTION, {
27235
27474
  id,
27236
27475
  data
@@ -27245,8 +27484,8 @@ var DefaultsStore = class {
27245
27484
  * Rows are RAW (apiKey present) — redaction is the provider's job (secrets.ts).
27246
27485
  * Invalid rows are dropped on read (`LlmProfileSchema.safeParse`).
27247
27486
  */
27248
- var PROFILES_COLLECTION = "llm-profiles";
27249
- var META_COLLECTION = "llm-meta";
27487
+ var PROFILES_COLLECTION = "ai:llm-profiles";
27488
+ var META_COLLECTION = "ai:llm-meta";
27250
27489
  var SEED_PROFILE_ID = "seed-ollama-lan";
27251
27490
  var SEED_MARKER_ID = "seededDefaults";
27252
27491
  /** KV JSON-blob shape — a single `data` column routes the row through the
@@ -27295,7 +27534,7 @@ var ProfileStore = class {
27295
27534
  }
27296
27535
  async upsert(profile) {
27297
27536
  const data = profileToData(profile);
27298
- if ((await this.store.query("llm-profiles")).some((r) => r.id === profile.id)) await this.store.update(PROFILES_COLLECTION, profile.id, data);
27537
+ if ((await this.store.query("ai:llm-profiles")).some((r) => r.id === profile.id)) await this.store.update(PROFILES_COLLECTION, profile.id, data);
27299
27538
  else await this.store.insert(PROFILES_COLLECTION, {
27300
27539
  id: profile.id,
27301
27540
  data
@@ -27307,7 +27546,7 @@ var ProfileStore = class {
27307
27546
  /** Idempotent template seed (spec §2): one DISABLED LAN-Ollama example,
27308
27547
  * guarded by a marker so a deleted seed never re-appears. */
27309
27548
  async ensureSeeded() {
27310
- if ((await this.store.query("llm-meta")).some((r) => r.id === SEED_MARKER_ID)) return;
27549
+ if ((await this.store.query("ai:llm-meta")).some((r) => r.id === SEED_MARKER_ID)) return;
27311
27550
  await this.upsert({
27312
27551
  id: SEED_PROFILE_ID,
27313
27552
  name: "LAN Ollama (example)",
package/dist/addon.mjs CHANGED
@@ -5,7 +5,7 @@ import { createReadStream } from "node:fs";
5
5
  import * as fsp from "node:fs/promises";
6
6
  import { spawn } from "node:child_process";
7
7
  import { createServer } from "node:net";
8
- //#region ../types/dist/event-category-Bz24uP1U.mjs
8
+ //#region ../types/dist/event-category-41fKf-q9.mjs
9
9
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
10
10
  EventCategory["SystemBoot"] = "system.boot";
11
11
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -65,6 +65,26 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
65
65
  */
66
66
  EventCategory["AddonRetryScheduled"] = "addon.retry-scheduled";
67
67
  /**
68
+ * A liveness invariant of this node is false — it has no devices, every
69
+ * camera is offline, or a camera that was recording has stopped producing
70
+ * segments. Emitted by the `liveness-monitor` builtin, once per fault (the
71
+ * `findingId` is stable across ticks), only after its boot grace period.
72
+ * AlertCenter raises a persistent operator-visible alert.
73
+ *
74
+ * It exists because on 2026-08-03 the hub ran four hours with zero devices
75
+ * and zero recordings while every surface stayed quiet.
76
+ *
77
+ * Payload: `{ findingId, severity, title, message, deviceId? }`.
78
+ */
79
+ EventCategory["SystemLivenessFailed"] = "system.liveness-failed";
80
+ /**
81
+ * A previously reported liveness fault is true again. AlertCenter dismisses
82
+ * the matching `SystemLivenessFailed` alert.
83
+ *
84
+ * Payload: `{ findingId }`.
85
+ */
86
+ EventCategory["SystemLivenessRecovered"] = "system.liveness-recovered";
87
+ /**
68
88
  * Monitor is attempting to reload a failed addon NOW. UI uses this
69
89
  * to show a spinner during the retry attempt. Same transient nature
70
90
  * as AddonRetryScheduled.
@@ -7345,14 +7365,7 @@ var RecordingConfigSchema = object({
7345
7365
  * windows only — existing sheets are immutable, and each window's index
7346
7366
  * carries its own tile dims so mixed-preset history renders correctly.
7347
7367
  */
7348
- scrubThumbnails: ScrubThumbnailPresetSchema.optional(),
7349
- /**
7350
- * OPT-IN thumbnail-strip generation for this camera: every keyframe of the
7351
- * low recording saved as a JPEG (the fast-drag scrub depth), a derived
7352
- * cache that eviction reclaims with the footage. Absent/false = no strips
7353
- * are written and scrub reads exact keyframes at every velocity.
7354
- */
7355
- stripsEnabled: boolean().optional()
7368
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7356
7369
  }).strict();
7357
7370
  /**
7358
7371
  * Ops-log — the durable, append-only operations audit shared by the
@@ -7414,7 +7427,7 @@ var OpsLogQueryInputSchema = object({
7414
7427
  /**
7415
7428
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
7416
7429
  *
7417
- * One shape shared by the recorder's `relocateFootage` (segments + strips) and
7430
+ * One shape shared by the recorder's `relocateFootage` (segments) and
7418
7431
  * pipeline-analytics' `relocateMedia` (event media blobs) so the admin Data
7419
7432
  * page renders both movers with one component. Jobs are in-RAM (a restart
7420
7433
  * forgets them — re-running is safe by construction: copy-if-absent, delete
@@ -7436,7 +7449,7 @@ var RelocateJobSchema = object({
7436
7449
  toLocationId: string(),
7437
7450
  /** Scoped device, or null = every device. */
7438
7451
  deviceId: number().nullable(),
7439
- /** What the job moves (owner-addon specific: segments/strips or media). */
7452
+ /** What the job moves (owner-addon specific: segments or media). */
7440
7453
  entities: array(string()),
7441
7454
  filesMoved: number().int(),
7442
7455
  bytesMoved: number().int(),
@@ -7450,7 +7463,7 @@ var RelocateFootageInputSchema = object({
7450
7463
  deviceId: number().optional(),
7451
7464
  fromLocationId: string(),
7452
7465
  toLocationId: string(),
7453
- entities: array(_enum(["segments", "strips"])).optional(),
7466
+ entities: array(_enum(["segments"])).optional(),
7454
7467
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
7455
7468
  * never allowed to starve live writers. */
7456
7469
  throttleMbps: number().min(1).max(1e3).optional()
@@ -15101,6 +15114,210 @@ method(object({ codec: string() }), boolean()), method(_void(), object({
15101
15114
  kind: "mutation",
15102
15115
  auth: "admin"
15103
15116
  });
15117
+ /**
15118
+ * Query filter for settings-store collections.
15119
+ */
15120
+ var QueryFilterSchema = object({
15121
+ where: record(string(), unknown()).optional(),
15122
+ whereIn: record(string(), array(unknown())).optional(),
15123
+ whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
15124
+ orderBy: object({
15125
+ field: string(),
15126
+ direction: _enum(["asc", "desc"])
15127
+ }).optional(),
15128
+ limit: number().optional(),
15129
+ offset: number().optional()
15130
+ });
15131
+ /**
15132
+ * The predicate half of a filter, for BULK MUTATIONS.
15133
+ *
15134
+ * Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
15135
+ * meaning for a statement that rewrites a set, and accepting them would invite
15136
+ * a caller to believe `limit` bounds the damage. Every field is optional here
15137
+ * only so the shape stays composable — the implementation REJECTS a filter
15138
+ * that compiles to no predicate, because that is the whole collection.
15139
+ */
15140
+ var MutationFilterSchema = object({
15141
+ where: record(string(), unknown()).optional(),
15142
+ whereIn: record(string(), array(unknown())).optional(),
15143
+ whereBetween: record(string(), tuple([unknown(), unknown()])).optional()
15144
+ });
15145
+ /** A single stored record: `{ id, data }`. */
15146
+ var SettingsRecordSchema = object({
15147
+ id: string(),
15148
+ data: record(string(), unknown())
15149
+ });
15150
+ /**
15151
+ * Column declaration for a structured (SQL-backed) collection.
15152
+ *
15153
+ * Logical types — the backend translates each to the matching SQLite
15154
+ * storage class and handles per-type marshaling:
15155
+ * - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
15156
+ * - `JSON` — TEXT under the hood; serialised on write, parsed on read
15157
+ * - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
15158
+ */
15159
+ var CollectionColumnSchema = object({
15160
+ name: string(),
15161
+ type: _enum([
15162
+ "TEXT",
15163
+ "INTEGER",
15164
+ "REAL",
15165
+ "JSON",
15166
+ "BOOLEAN"
15167
+ ]),
15168
+ primaryKey: boolean().optional(),
15169
+ notNull: boolean().optional(),
15170
+ unique: boolean().optional(),
15171
+ /**
15172
+ * Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
15173
+ * columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
15174
+ * collection surface simply cannot express their existing tables — which is
15175
+ * why they were still on the uncapped `table*` API.
15176
+ */
15177
+ defaultValue: union([
15178
+ string(),
15179
+ number(),
15180
+ boolean()
15181
+ ]).optional()
15182
+ });
15183
+ var CollectionIndexSchema = object({
15184
+ name: string(),
15185
+ columns: array(string()).readonly(),
15186
+ unique: boolean().optional()
15187
+ });
15188
+ method(object({
15189
+ namespace: string().optional(),
15190
+ collection: string(),
15191
+ key: string()
15192
+ }), unknown()), method(object({
15193
+ namespace: string().optional(),
15194
+ collection: string(),
15195
+ key: string(),
15196
+ value: unknown()
15197
+ }), _void(), { kind: "mutation" }), method(object({
15198
+ namespace: string().optional(),
15199
+ collection: string(),
15200
+ filter: QueryFilterSchema.optional()
15201
+ }), array(SettingsRecordSchema).readonly()), method(object({
15202
+ namespace: string().optional(),
15203
+ collection: string(),
15204
+ record: SettingsRecordSchema
15205
+ }), _void(), { kind: "mutation" }), method(object({
15206
+ namespace: string().optional(),
15207
+ collection: string(),
15208
+ id: string(),
15209
+ data: record(string(), unknown())
15210
+ }), _void(), { kind: "mutation" }), method(object({
15211
+ namespace: string().optional(),
15212
+ collection: string(),
15213
+ key: string()
15214
+ }), _void(), { kind: "mutation" }), method(object({
15215
+ namespace: string().optional(),
15216
+ collection: string(),
15217
+ filter: MutationFilterSchema
15218
+ }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
15219
+ namespace: string().optional(),
15220
+ collection: string(),
15221
+ filter: MutationFilterSchema,
15222
+ data: record(string(), unknown())
15223
+ }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
15224
+ namespace: string().optional(),
15225
+ collection: string(),
15226
+ filter: QueryFilterSchema.optional()
15227
+ }), number()), method(object({
15228
+ namespace: string().optional(),
15229
+ collection: string(),
15230
+ field: string(),
15231
+ bucketSize: number().int().positive(),
15232
+ origin: number().int(),
15233
+ filter: QueryFilterSchema.optional()
15234
+ }), array(object({
15235
+ bucket: number().int(),
15236
+ count: number().int()
15237
+ })).readonly()), method(object({
15238
+ namespace: string().optional(),
15239
+ collection: string()
15240
+ }), boolean()), method(object({
15241
+ namespace: string().optional(),
15242
+ collection: string(),
15243
+ columns: array(CollectionColumnSchema).readonly(),
15244
+ indexes: array(CollectionIndexSchema).readonly().optional()
15245
+ }), _void(), { kind: "mutation" });
15246
+ /**
15247
+ * What one engine says about itself. The orchestrator uses `kind` to pick
15248
+ * a registrant for a collection; `engineId` is what a log line names when
15249
+ * a call is routed or refused.
15250
+ */
15251
+ var EngineInfoSchema = object({
15252
+ engineId: string(),
15253
+ /**
15254
+ * `relational` — rows, columns, indexes, the surface `settings-store`
15255
+ * has always described. `vector` — an embedding store answering
15256
+ * similarity queries. A registrant declares exactly one; an engine that
15257
+ * does both registers twice, because "both" would make the routing
15258
+ * decision ambiguous at exactly the point it must not be.
15259
+ */
15260
+ kind: _enum(["relational", "vector"]),
15261
+ displayName: string()
15262
+ });
15263
+ method(_void(), EngineInfoSchema), method(object({
15264
+ namespace: string().optional(),
15265
+ collection: string(),
15266
+ key: string()
15267
+ }), unknown()), method(object({
15268
+ namespace: string().optional(),
15269
+ collection: string(),
15270
+ key: string(),
15271
+ value: unknown()
15272
+ }), _void(), { kind: "mutation" }), method(object({
15273
+ namespace: string().optional(),
15274
+ collection: string(),
15275
+ filter: QueryFilterSchema.optional()
15276
+ }), array(SettingsRecordSchema).readonly()), method(object({
15277
+ namespace: string().optional(),
15278
+ collection: string(),
15279
+ record: SettingsRecordSchema
15280
+ }), _void(), { kind: "mutation" }), method(object({
15281
+ namespace: string().optional(),
15282
+ collection: string(),
15283
+ id: string(),
15284
+ data: record(string(), unknown())
15285
+ }), _void(), { kind: "mutation" }), method(object({
15286
+ namespace: string().optional(),
15287
+ collection: string(),
15288
+ key: string()
15289
+ }), _void(), { kind: "mutation" }), method(object({
15290
+ namespace: string().optional(),
15291
+ collection: string(),
15292
+ filter: MutationFilterSchema
15293
+ }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
15294
+ namespace: string().optional(),
15295
+ collection: string(),
15296
+ filter: MutationFilterSchema,
15297
+ data: record(string(), unknown())
15298
+ }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
15299
+ namespace: string().optional(),
15300
+ collection: string(),
15301
+ filter: QueryFilterSchema.optional()
15302
+ }), number()), method(object({
15303
+ namespace: string().optional(),
15304
+ collection: string(),
15305
+ field: string(),
15306
+ bucketSize: number().int().positive(),
15307
+ origin: number().int(),
15308
+ filter: QueryFilterSchema.optional()
15309
+ }), array(object({
15310
+ bucket: number().int(),
15311
+ count: number().int()
15312
+ })).readonly()), method(object({
15313
+ namespace: string().optional(),
15314
+ collection: string()
15315
+ }), boolean()), method(object({
15316
+ namespace: string().optional(),
15317
+ collection: string(),
15318
+ columns: array(CollectionColumnSchema).readonly(),
15319
+ indexes: array(CollectionIndexSchema).readonly().optional()
15320
+ }), _void(), { kind: "mutation" });
15104
15321
  DeviceType.Camera;
15105
15322
  /**
15106
15323
  * `device-adoption` — generic discovery + adoption surface,
@@ -18378,6 +18595,28 @@ var ServerUpdateStateSchema = _enum([
18378
18595
  "pending-restart",
18379
18596
  "awaiting-confirmation"
18380
18597
  ]);
18598
+ var ImageContractSchema = object({
18599
+ state: _enum([
18600
+ "in-sync",
18601
+ "behind-patch",
18602
+ "behind-series",
18603
+ "ahead",
18604
+ "unknown"
18605
+ ]),
18606
+ /** The baked seed closure version — the image/app-bundle fingerprint. */
18607
+ seedVersion: string().nullable(),
18608
+ /** Best-known version the deployment contract delivers today. */
18609
+ contractVersion: string().nullable(),
18610
+ /**
18611
+ * Where `contractVersion` came from: a real registry check (`registry`), or
18612
+ * the node's own running version (`running` — a node can never run code
18613
+ * newer than the newest release, so `seed < running` proves image staleness
18614
+ * even before any registry check has run).
18615
+ */
18616
+ contractSource: _enum(["registry", "running"]).nullable(),
18617
+ /** One operator-grade sentence: this node runs image X; the contract says Y. */
18618
+ message: string()
18619
+ });
18381
18620
  var ServerRollbackInfoSchema = object({
18382
18621
  /** The version that failed (or was manually rolled back). */
18383
18622
  fromVersion: string(),
@@ -18414,7 +18653,12 @@ var ServerPackageStatusSchema = object({
18414
18653
  * versions are being IGNORED. Surfaced as a warning in the UI.
18415
18654
  */
18416
18655
  stateFileCorrupt: boolean(),
18417
- lastCheckedAtMs: number().nullable()
18656
+ lastCheckedAtMs: number().nullable(),
18657
+ /**
18658
+ * Seed-vs-contract verdict (see {@link ImageContractSchema}). Optional for
18659
+ * version skew: an older provider's payload simply omits it.
18660
+ */
18661
+ imageContract: ImageContractSchema.optional()
18418
18662
  });
18419
18663
  var ServerUpdateCheckResultSchema = object({
18420
18664
  packageName: string(),
@@ -18449,101 +18693,6 @@ version: string().optional() }), ServerUpdateActionResultSchema, {
18449
18693
  auth: "admin"
18450
18694
  });
18451
18695
  /**
18452
- * Query filter for settings-store collections.
18453
- */
18454
- var QueryFilterSchema = object({
18455
- where: record(string(), unknown()).optional(),
18456
- whereIn: record(string(), array(unknown())).optional(),
18457
- whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
18458
- orderBy: object({
18459
- field: string(),
18460
- direction: _enum(["asc", "desc"])
18461
- }).optional(),
18462
- limit: number().optional(),
18463
- offset: number().optional()
18464
- });
18465
- /** A single stored record: `{ id, data }`. */
18466
- var SettingsRecordSchema = object({
18467
- id: string(),
18468
- data: record(string(), unknown())
18469
- });
18470
- /**
18471
- * Column declaration for a structured (SQL-backed) collection.
18472
- *
18473
- * Logical types — the backend translates each to the matching SQLite
18474
- * storage class and handles per-type marshaling:
18475
- * - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
18476
- * - `JSON` — TEXT under the hood; serialised on write, parsed on read
18477
- * - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
18478
- */
18479
- var CollectionColumnSchema = object({
18480
- name: string(),
18481
- type: _enum([
18482
- "TEXT",
18483
- "INTEGER",
18484
- "REAL",
18485
- "JSON",
18486
- "BOOLEAN"
18487
- ]),
18488
- primaryKey: boolean().optional(),
18489
- notNull: boolean().optional(),
18490
- unique: boolean().optional()
18491
- });
18492
- var CollectionIndexSchema = object({
18493
- name: string(),
18494
- columns: array(string()).readonly(),
18495
- unique: boolean().optional()
18496
- });
18497
- method(object({
18498
- namespace: string().optional(),
18499
- collection: string(),
18500
- key: string()
18501
- }), unknown()), method(object({
18502
- namespace: string().optional(),
18503
- collection: string(),
18504
- key: string(),
18505
- value: unknown()
18506
- }), _void(), { kind: "mutation" }), method(object({
18507
- namespace: string().optional(),
18508
- collection: string(),
18509
- filter: QueryFilterSchema.optional()
18510
- }), array(SettingsRecordSchema).readonly()), method(object({
18511
- namespace: string().optional(),
18512
- collection: string(),
18513
- record: SettingsRecordSchema
18514
- }), _void(), { kind: "mutation" }), method(object({
18515
- namespace: string().optional(),
18516
- collection: string(),
18517
- id: string(),
18518
- data: record(string(), unknown())
18519
- }), _void(), { kind: "mutation" }), method(object({
18520
- namespace: string().optional(),
18521
- collection: string(),
18522
- key: string()
18523
- }), _void(), { kind: "mutation" }), method(object({
18524
- namespace: string().optional(),
18525
- collection: string(),
18526
- filter: QueryFilterSchema.optional()
18527
- }), number()), method(object({
18528
- namespace: string().optional(),
18529
- collection: string(),
18530
- field: string(),
18531
- bucketSize: number().int().positive(),
18532
- origin: number().int(),
18533
- filter: QueryFilterSchema.optional()
18534
- }), array(object({
18535
- bucket: number().int(),
18536
- count: number().int()
18537
- })).readonly()), method(object({
18538
- namespace: string().optional(),
18539
- collection: string()
18540
- }), boolean()), method(object({
18541
- namespace: string().optional(),
18542
- collection: string(),
18543
- columns: array(CollectionColumnSchema).readonly(),
18544
- indexes: array(CollectionIndexSchema).readonly().optional()
18545
- }), _void(), { kind: "mutation" });
18546
- /**
18547
18696
  * `smtp-provider` — pluggable email delivery surface.
18548
18697
  *
18549
18698
  * Collection cap: a deployment may install multiple SMTP relays (e.g.
@@ -22442,6 +22591,84 @@ Object.freeze({
22442
22591
  addonId: null,
22443
22592
  access: "view"
22444
22593
  },
22594
+ "dataStoreProvider.count": {
22595
+ capName: "data-store-provider",
22596
+ capScope: "system",
22597
+ addonId: null,
22598
+ access: "view"
22599
+ },
22600
+ "dataStoreProvider.declareCollection": {
22601
+ capName: "data-store-provider",
22602
+ capScope: "system",
22603
+ addonId: null,
22604
+ access: "create"
22605
+ },
22606
+ "dataStoreProvider.delete": {
22607
+ capName: "data-store-provider",
22608
+ capScope: "system",
22609
+ addonId: null,
22610
+ access: "delete"
22611
+ },
22612
+ "dataStoreProvider.deleteWhere": {
22613
+ capName: "data-store-provider",
22614
+ capScope: "system",
22615
+ addonId: null,
22616
+ access: "delete"
22617
+ },
22618
+ "dataStoreProvider.get": {
22619
+ capName: "data-store-provider",
22620
+ capScope: "system",
22621
+ addonId: null,
22622
+ access: "view"
22623
+ },
22624
+ "dataStoreProvider.getEngineInfo": {
22625
+ capName: "data-store-provider",
22626
+ capScope: "system",
22627
+ addonId: null,
22628
+ access: "view"
22629
+ },
22630
+ "dataStoreProvider.histogram": {
22631
+ capName: "data-store-provider",
22632
+ capScope: "system",
22633
+ addonId: null,
22634
+ access: "view"
22635
+ },
22636
+ "dataStoreProvider.insert": {
22637
+ capName: "data-store-provider",
22638
+ capScope: "system",
22639
+ addonId: null,
22640
+ access: "create"
22641
+ },
22642
+ "dataStoreProvider.isEmpty": {
22643
+ capName: "data-store-provider",
22644
+ capScope: "system",
22645
+ addonId: null,
22646
+ access: "view"
22647
+ },
22648
+ "dataStoreProvider.query": {
22649
+ capName: "data-store-provider",
22650
+ capScope: "system",
22651
+ addonId: null,
22652
+ access: "view"
22653
+ },
22654
+ "dataStoreProvider.set": {
22655
+ capName: "data-store-provider",
22656
+ capScope: "system",
22657
+ addonId: null,
22658
+ access: "create"
22659
+ },
22660
+ "dataStoreProvider.update": {
22661
+ capName: "data-store-provider",
22662
+ capScope: "system",
22663
+ addonId: null,
22664
+ access: "create"
22665
+ },
22666
+ "dataStoreProvider.updateWhere": {
22667
+ capName: "data-store-provider",
22668
+ capScope: "system",
22669
+ addonId: null,
22670
+ access: "create"
22671
+ },
22445
22672
  "dayNight.getOptions": {
22446
22673
  capName: "day-night",
22447
22674
  capScope: "device",
@@ -25520,6 +25747,12 @@ Object.freeze({
25520
25747
  addonId: null,
25521
25748
  access: "delete"
25522
25749
  },
25750
+ "settingsStore.deleteWhere": {
25751
+ capName: "settings-store",
25752
+ capScope: "system",
25753
+ addonId: null,
25754
+ access: "delete"
25755
+ },
25523
25756
  "settingsStore.get": {
25524
25757
  capName: "settings-store",
25525
25758
  capScope: "system",
@@ -25562,6 +25795,12 @@ Object.freeze({
25562
25795
  addonId: null,
25563
25796
  access: "create"
25564
25797
  },
25798
+ "settingsStore.updateWhere": {
25799
+ capName: "settings-store",
25800
+ capScope: "system",
25801
+ addonId: null,
25802
+ access: "create"
25803
+ },
25565
25804
  "smtpProvider.getStatus": {
25566
25805
  capName: "smtp-provider",
25567
25806
  capScope: "system",
@@ -27152,7 +27391,7 @@ var openAiAdapter = {
27152
27391
  * Per-consumer / per-purpose default profile rows (spec §3). Row id is the
27153
27392
  * stable selector key so `set` upserts and `set(selector, null)` deletes.
27154
27393
  */
27155
- var DEFAULTS_COLLECTION = "llm-defaults";
27394
+ var DEFAULTS_COLLECTION = "ai:llm-defaults";
27156
27395
  /** KV JSON-blob shape — a single `data` column routes through the settings
27157
27396
  * backend's canonical key/value path (id TEXT PK, data TEXT). */
27158
27397
  var KV_BLOB_COLUMNS$1 = [{
@@ -27192,7 +27431,7 @@ var DefaultsStore = class {
27192
27431
  selector,
27193
27432
  profileId
27194
27433
  };
27195
- if ((await this.store.query("llm-defaults")).some((r) => r.id === id)) await this.store.update(DEFAULTS_COLLECTION, id, data);
27434
+ if ((await this.store.query("ai:llm-defaults")).some((r) => r.id === id)) await this.store.update(DEFAULTS_COLLECTION, id, data);
27196
27435
  else await this.store.insert(DEFAULTS_COLLECTION, {
27197
27436
  id,
27198
27437
  data
@@ -27207,8 +27446,8 @@ var DefaultsStore = class {
27207
27446
  * Rows are RAW (apiKey present) — redaction is the provider's job (secrets.ts).
27208
27447
  * Invalid rows are dropped on read (`LlmProfileSchema.safeParse`).
27209
27448
  */
27210
- var PROFILES_COLLECTION = "llm-profiles";
27211
- var META_COLLECTION = "llm-meta";
27449
+ var PROFILES_COLLECTION = "ai:llm-profiles";
27450
+ var META_COLLECTION = "ai:llm-meta";
27212
27451
  var SEED_PROFILE_ID = "seed-ollama-lan";
27213
27452
  var SEED_MARKER_ID = "seededDefaults";
27214
27453
  /** KV JSON-blob shape — a single `data` column routes the row through the
@@ -27257,7 +27496,7 @@ var ProfileStore = class {
27257
27496
  }
27258
27497
  async upsert(profile) {
27259
27498
  const data = profileToData(profile);
27260
- if ((await this.store.query("llm-profiles")).some((r) => r.id === profile.id)) await this.store.update(PROFILES_COLLECTION, profile.id, data);
27499
+ if ((await this.store.query("ai:llm-profiles")).some((r) => r.id === profile.id)) await this.store.update(PROFILES_COLLECTION, profile.id, data);
27261
27500
  else await this.store.insert(PROFILES_COLLECTION, {
27262
27501
  id: profile.id,
27263
27502
  data
@@ -27269,7 +27508,7 @@ var ProfileStore = class {
27269
27508
  /** Idempotent template seed (spec §2): one DISABLED LAN-Ollama example,
27270
27509
  * guarded by a marker so a deleted seed never re-appears. */
27271
27510
  async ensureSeeded() {
27272
- if ((await this.store.query("llm-meta")).some((r) => r.id === SEED_MARKER_ID)) return;
27511
+ if ((await this.store.query("ai:llm-meta")).some((r) => r.id === SEED_MARKER_ID)) return;
27273
27512
  await this.upsert({
27274
27513
  id: SEED_PROFILE_ID,
27275
27514
  name: "LAN Ollama (example)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-ai",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
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",