@camstack/addon-post-analysis 1.2.78 → 1.2.79

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.
@@ -12759,6 +12759,18 @@ var LlmGenerateBaseInputSchema = object({
12759
12759
  * Resource ceiling = llama-server flags + idleStopMinutes ONLY (no RSS
12760
12760
  * watchdog — operator decision #3).
12761
12761
  */
12762
+ /**
12763
+ * A companion artifact that MUST land beside the main GGUF: the `mmproj`
12764
+ * projector of a vision model, or shards 2..N of a split GGUF. Carried on the
12765
+ * REF rather than looked up at install time, so what the operator approved in
12766
+ * the preview is exactly what the node downloads.
12767
+ */
12768
+ var ManagedModelExtraFileSchema = object({
12769
+ url: string(),
12770
+ filename: string(),
12771
+ sizeBytes: number(),
12772
+ sha256: string().optional()
12773
+ });
12762
12774
  var ManagedModelRefSchema = discriminatedUnion("kind", [
12763
12775
  object({
12764
12776
  kind: literal("catalog"),
@@ -12767,7 +12779,11 @@ var ManagedModelRefSchema = discriminatedUnion("kind", [
12767
12779
  object({
12768
12780
  kind: literal("url"),
12769
12781
  url: string(),
12770
- sha256: string().optional()
12782
+ sha256: string().optional(),
12783
+ /** Picker/status label; the file basename when absent. */
12784
+ label: string().optional(),
12785
+ sizeBytes: number().optional(),
12786
+ extraFiles: array(ManagedModelExtraFileSchema).optional()
12771
12787
  }),
12772
12788
  object({
12773
12789
  kind: literal("path"),
@@ -12828,11 +12844,39 @@ var ManagedRuntimeConfigSchema = object({
12828
12844
  "q4_1",
12829
12845
  "q4_0"
12830
12846
  ]).optional(),
12847
+ /**
12848
+ * Escape hatch for llama-server flags this schema does NOT model — `--jinja`
12849
+ * (which most vision chat templates need and some language-only models
12850
+ * dislike), `--cont-batching`, `--rope-scaling`, …
12851
+ *
12852
+ * It is NOT a second place to set the flags above. A token that collides
12853
+ * with a typed field is REJECTED at start, naming the field that owns it
12854
+ * (`assertNoOwnedFlags`), because two knobs writing the same argv is exactly
12855
+ * the "two switches that disagree" failure this repo has already shipped
12856
+ * twice (D62).
12857
+ */
12858
+ extraArgs: array(string()).default([]),
12831
12859
  /** Else lazy: first generate boots it. */
12832
12860
  autoStart: boolean().default(false),
12833
12861
  /** 0 = never; frees RAM after quiet periods. */
12834
12862
  idleStopMinutes: number().int().default(30)
12835
12863
  });
12864
+ /**
12865
+ * Where a multi-GB install currently is. A single 0..1 fraction cannot answer
12866
+ * "is it stuck?" for an install that is three files (shards + mmproj) followed
12867
+ * by a sha256 pass over 22 GB — during which the fraction sat at 1.0 and the
12868
+ * node looked hung. Phase + file + bytes is the smallest shape that does.
12869
+ */
12870
+ var LlmDownloadProgressSchema = object({
12871
+ phase: _enum(["downloading", "verifying"]),
12872
+ /** The artifact currently moving, e.g. `mmproj-F16.gguf`. */
12873
+ file: string(),
12874
+ fileIndex: number().int(),
12875
+ fileCount: number().int(),
12876
+ /** Across the WHOLE install, not the current file. */
12877
+ downloadedBytes: number(),
12878
+ totalBytes: number().optional()
12879
+ });
12836
12880
  var LlmRuntimeStatusSchema = object({
12837
12881
  /** Status is ALWAYS node-qualified. */
12838
12882
  nodeId: string(),
@@ -12849,6 +12893,8 @@ var LlmRuntimeStatusSchema = object({
12849
12893
  modelPath: string().optional(),
12850
12894
  modelId: string().optional(),
12851
12895
  downloadProgress: number().min(0).max(1).optional(),
12896
+ /** Detail behind `downloadProgress`; present for the same lifetime. */
12897
+ download: LlmDownloadProgressSchema.optional(),
12852
12898
  lastError: string().optional(),
12853
12899
  crashesInWindow: number(),
12854
12900
  /** Child RSS (sampled best-effort). */
@@ -12859,7 +12905,14 @@ var LlmNodeModelSchema = object({
12859
12905
  file: string(),
12860
12906
  sizeBytes: number(),
12861
12907
  catalogId: string().optional(),
12862
- installedAt: number().optional()
12908
+ installedAt: number().optional(),
12909
+ /**
12910
+ * Absolute path on the node. Present so a file that is on disk but matches
12911
+ * no catalog entry — a custom Hugging Face install, or a GGUF the operator
12912
+ * copied in by hand — is still SELECTABLE, as a `{kind:'path'}` ref. Without
12913
+ * it the picker could list such a file and do nothing with it.
12914
+ */
12915
+ path: string().optional()
12863
12916
  });
12864
12917
  var LlmRuntimeDiskUsageSchema = object({
12865
12918
  nodeId: string(),
@@ -13005,6 +13058,36 @@ var ManagedModelCatalogEntrySchema = object({
13005
13058
  /** Vision models: companion projector file. */
13006
13059
  mmprojUrl: string().optional()
13007
13060
  });
13061
+ /**
13062
+ * The outcome of turning one operator-typed Hugging Face reference into a
13063
+ * download plan. A RESULT, never a throw: "this repo has 24 quantizations and
13064
+ * I will not pick for you" is a normal answer the UI has to render, not an
13065
+ * exception.
13066
+ *
13067
+ * `candidates` is the whole reason the refusal is usable — every string in it
13068
+ * is a tag that resolves when pasted back as `<org>/<repo>:<TAG>`.
13069
+ */
13070
+ var HfModelResolutionSchema = discriminatedUnion("ok", [object({
13071
+ ok: literal(true),
13072
+ /** Ready to hand to `installModel` unchanged. */
13073
+ model: ManagedModelRefSchema,
13074
+ label: string(),
13075
+ repo: string(),
13076
+ quantization: string(),
13077
+ purpose: _enum(["text", "vision"]),
13078
+ totalBytes: number(),
13079
+ /** mmproj + shards, for the preview: an operator approving 23 GB should
13080
+ * see that 0.9 GB of it is a projector they did not name. */
13081
+ extraFilenames: array(string())
13082
+ }), object({
13083
+ ok: literal(false),
13084
+ code: string(),
13085
+ message: string(),
13086
+ candidates: array(string()).optional(),
13087
+ /** Set when the refusal was only the ceiling: re-calling with
13088
+ * `maxBytes: requiredBytes` is the operator's explicit override. */
13089
+ requiredBytes: number().optional()
13090
+ })]);
13008
13091
  var LlmRuntimeNodeSchema = object({
13009
13092
  nodeId: string(),
13010
13093
  reachable: boolean(),
@@ -13041,6 +13124,15 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }
13041
13124
  consumer: string().optional(),
13042
13125
  profileId: string().optional()
13043
13126
  }), array(LlmUsageRollupSchema)), method(object({}), array(ManagedModelCatalogEntrySchema)), method(object({}), array(LlmRuntimeNodeSchema)), method(object({ nodeId: string() }), array(LlmNodeModelSchema)), method(object({
13127
+ /** `https://huggingface.co/<org>/<repo>/resolve/main/<f>.gguf`,
13128
+ * `<org>/<repo>/<f>.gguf`, `<org>/<repo>` or `<org>/<repo>:<QUANT>`. */
13129
+ ref: string(),
13130
+ /** Explicit ceiling override, in bytes. Absent = the built-in ceiling. */
13131
+ maxBytes: number().positive().optional()
13132
+ }), HfModelResolutionSchema, {
13133
+ kind: "mutation",
13134
+ auth: "admin"
13135
+ }), method(object({
13044
13136
  nodeId: string(),
13045
13137
  model: ManagedModelRefSchema
13046
13138
  }), _void(), {
@@ -19242,6 +19334,17 @@ var maxSessionHoldMsField = {
19242
19334
  default: 12e4,
19243
19335
  step: 5e3
19244
19336
  };
19337
+ /**
19338
+ * Quiet period that closes an `audioMode: 'on-motion'` audio window. Floor of
19339
+ * 5s so a rearm can never degenerate into per-event stream churn; default 90s
19340
+ * comfortably outlives the gap between two PIR wakes on a battery camera.
19341
+ */
19342
+ var audioMotionWindowMsField = {
19343
+ min: 5e3,
19344
+ max: 6e5,
19345
+ default: 9e4,
19346
+ step: 5e3
19347
+ };
19245
19348
  var motionFpsField = {
19246
19349
  min: 1,
19247
19350
  max: 30,
@@ -19418,6 +19521,27 @@ var RunnerCameraConfigSchema = object({
19418
19521
  * resolved `CameraDetectionConfig`.
19419
19522
  */
19420
19523
  maxSessionHoldMs: number().min(maxSessionHoldMsField.min).max(maxSessionHoldMsField.max).optional(),
19524
+ /**
19525
+ * Orchestrator-side quiet period (ms) that closes an `audioMode:
19526
+ * 'on-motion'` audio window, measured from the LAST motion event.
19527
+ *
19528
+ * This exists because the falling edge cannot be relied on. Camera-native
19529
+ * providers emit motion as a RISING EDGE ONLY (Reolink's Baichuan push and
19530
+ * its email-push SMTP path both emit `detected: true` and never the
19531
+ * counterpart); only the frame-diff analyzer emits falls. So on an
19532
+ * onboard-only camera a window that closed only on `detected: false` never
19533
+ * closed at all, and `on-motion` silently behaved as `always-on` — on a
19534
+ * battery camera, the one failure mode the mode exists to prevent.
19535
+ *
19536
+ * Every motion event rearms this timer WITHOUT restarting the stream, so a
19537
+ * burst of re-fires costs nothing. A falling edge, when one does arrive,
19538
+ * still closes earlier via `motionCooldownMs` — whichever comes first wins.
19539
+ *
19540
+ * Not consumed by the runner: carried here so it shares the per-camera
19541
+ * device-settings surface with `motionCooldownMs`, exactly like
19542
+ * `maxSessionHoldMs`.
19543
+ */
19544
+ audioMotionWindowMs: number().min(audioMotionWindowMsField.min).max(audioMotionWindowMsField.max).optional(),
19421
19545
  motionFps: number().min(motionFpsField.min).max(motionFpsField.max).default(motionFpsField.default),
19422
19546
  detectionFps: number().min(detectionFpsField.min).max(detectionFpsField.max).default(detectionFpsField.default),
19423
19547
  motionStreamId: string(),
@@ -19513,7 +19637,7 @@ var RunnerCameraConfigSchema = object({
19513
19637
  */
19514
19638
  inferenceDevices: array(RunnerInferenceDeviceSchema).readonly().optional()
19515
19639
  });
19516
- motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
19640
+ motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
19517
19641
  /**
19518
19642
  * Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
19519
19643
  * load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
@@ -22227,6 +22351,25 @@ var BatteryStatusSchema = object({
22227
22351
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
22228
22352
  lastUpdated: number(),
22229
22353
  /**
22354
+ * Ms epoch of the last time the device PROVED it was reachable — a
22355
+ * completed firmware round-trip, an observed wake, or an inbound push
22356
+ * (firmware event, email). `0`/absent = never since this slice was born.
22357
+ *
22358
+ * This is the ONLY input that separates "asleep" from "gone", and it is
22359
+ * fed exclusively by PASSIVE signals: nothing may write it by reaching
22360
+ * for the radio, because a poll that confirms reachability is the same
22361
+ * poll that drains the battery. See {@link deriveBatteryPresence} — the
22362
+ * single derivation every consumer must use; no surface computes its own.
22363
+ *
22364
+ * It is deliberately NOT a clock in the
22365
+ * `scripts/check-runtime-state-durability.ts` sense: it is the
22366
+ * observation itself, and it is the only thing a 30-hour silence is
22367
+ * visible in. Writers quantise it (see `CONTACT_WRITE_QUANTUM_MS` in the
22368
+ * Reolink provider) so a value that means "recently" cannot cost a
22369
+ * SQLite commit per round-trip.
22370
+ */
22371
+ lastContactAt: number().optional(),
22372
+ /**
22230
22373
  * True when the source is a BINARY low-battery indicator (HA
22231
22374
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
22232
22375
  * charge level — `percentage` is then a coarse stand-in (100 = normal,
@@ -28254,7 +28397,70 @@ var CamStreamDescriptorSchema = object({
28254
28397
  /** Transport-specific opaque metadata (e.g. rfc4571 SDP). */
28255
28398
  metadata: record(string(), unknown()).optional()
28256
28399
  });
28257
- DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), array(CamStreamDescriptorSchema).readonly());
28400
+ /**
28401
+ * `stream-catalog` — device-scoped, provider-implemented. The pull counterpart
28402
+ * of the removed `publishCameraStream` push: a camera provider returns the full
28403
+ * set of stream descriptors it can offer for the device, synchronously, so the
28404
+ * broker can reconcile its registry against the authoritative provider state.
28405
+ */
28406
+ /**
28407
+ * The catalog as a DURABLE fact rather than a live answer.
28408
+ *
28409
+ * A battery camera's descriptors are profile-stable — they change when the
28410
+ * operator rewrites an encoder profile, not minute to minute — but building
28411
+ * them costs a Baichuan login, which on a sleeping Argus IS a wake. So the
28412
+ * provider is allowed to build them exactly once per profile and must serve
28413
+ * every later pull from a cache.
28414
+ *
28415
+ * Holding that cache only in RAM is what turned a restart into an outage. The
28416
+ * runner comes back with the camera asleep, `buildStreamCatalogUncached`
28417
+ * correctly refuses to wake it, the pull answers `[]`, the broker has no
28418
+ * cam-stream entry to build a broker from, and `webrtcSession.handleOffer`
28419
+ * fails with a flat "No broker for stream" — for as long as the camera sleeps,
28420
+ * which on a battery cam is most of the day. The camera was fine. The stream
28421
+ * was unreachable because the process had forgotten what the camera offers.
28422
+ *
28423
+ * Declaring it here puts it in `device-runtime-state`, the kernel's canonical
28424
+ * declared collection, with the same `restored` durability `battery` uses for
28425
+ * the same reason: the last known value is the only value there is while the
28426
+ * device is asleep. The broker's brokers are therefore always DEFINABLE — it
28427
+ * is the DIAL that wakes a camera, never the catalog (D173).
28428
+ */
28429
+ var StreamCatalogStateSchema = object({
28430
+ /** The descriptors as last built from a real camera response. Never a guess:
28431
+ * a failed or refused build writes NOTHING, so a restored catalog is always
28432
+ * one the camera itself once produced. */
28433
+ descriptors: array(CamStreamDescriptorSchema),
28434
+ /** Ms epoch of the build that produced {@link descriptors}. Lets the wake
28435
+ * path decide whether the camera's own awake window is worth spending on a
28436
+ * re-read. */
28437
+ lastFetchedAt: number()
28438
+ });
28439
+ var streamCatalogCapability = {
28440
+ name: "stream-catalog",
28441
+ scope: "device",
28442
+ deviceNative: true,
28443
+ mode: "singleton",
28444
+ deviceTypes: [DeviceType.Camera],
28445
+ methods: { getCatalog: method(object({ deviceId: number().int().nonnegative() }), array(CamStreamDescriptorSchema).readonly()) },
28446
+ runtimeState: StreamCatalogStateSchema,
28447
+ /**
28448
+ * Runtime-state durability: **restored** — see the schema doc. A cold
28449
+ * catalog on a sleeping battery camera is not a slow first frame, it is a
28450
+ * camera that cannot be watched at all until it happens to wake.
28451
+ *
28452
+ * Churn is nil by construction: the slice is written only by a SUCCESSFUL
28453
+ * build, and a build only runs when there is no cached copy (or the copy is
28454
+ * a day old and the camera is awake anyway).
28455
+ *
28456
+ * See `RuntimeStateDurability`. Enforced by
28457
+ * `scripts/check-runtime-state-durability.ts`.
28458
+ */
28459
+ durability: "restored",
28460
+ /** Clock field: written, but excluded from the compare that decides whether
28461
+ * persisting is worth a SQLite commit — the descriptors are the value. */
28462
+ volatileStateFields: ["lastFetchedAt"]
28463
+ };
28258
28464
  /** One of the camera's stream profiles. */
28259
28465
  var StreamProfileSchema = _enum([
28260
28466
  "main",
@@ -29958,6 +30164,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
29958
30164
  sceneMonitor: sceneMonitorCapability,
29959
30165
  scriptRunner: scriptRunnerCapability,
29960
30166
  smoke: smokeCapability,
30167
+ streamCatalog: streamCatalogCapability,
29961
30168
  streamParams: streamParamsCapability,
29962
30169
  switch: switchCapability,
29963
30170
  tamper: tamperCapability,
@@ -32844,6 +33051,12 @@ Object.freeze({
32844
33051
  addonId: null,
32845
33052
  access: "view"
32846
33053
  },
33054
+ "llm.resolveModelRef": {
33055
+ capName: "llm",
33056
+ capScope: "system",
33057
+ addonId: null,
33058
+ access: "create"
33059
+ },
32847
33060
  "llm.setDefault": {
32848
33061
  capName: "llm",
32849
33062
  capScope: "system",
@@ -12728,6 +12728,18 @@ var LlmGenerateBaseInputSchema = object({
12728
12728
  * Resource ceiling = llama-server flags + idleStopMinutes ONLY (no RSS
12729
12729
  * watchdog — operator decision #3).
12730
12730
  */
12731
+ /**
12732
+ * A companion artifact that MUST land beside the main GGUF: the `mmproj`
12733
+ * projector of a vision model, or shards 2..N of a split GGUF. Carried on the
12734
+ * REF rather than looked up at install time, so what the operator approved in
12735
+ * the preview is exactly what the node downloads.
12736
+ */
12737
+ var ManagedModelExtraFileSchema = object({
12738
+ url: string(),
12739
+ filename: string(),
12740
+ sizeBytes: number(),
12741
+ sha256: string().optional()
12742
+ });
12731
12743
  var ManagedModelRefSchema = discriminatedUnion("kind", [
12732
12744
  object({
12733
12745
  kind: literal("catalog"),
@@ -12736,7 +12748,11 @@ var ManagedModelRefSchema = discriminatedUnion("kind", [
12736
12748
  object({
12737
12749
  kind: literal("url"),
12738
12750
  url: string(),
12739
- sha256: string().optional()
12751
+ sha256: string().optional(),
12752
+ /** Picker/status label; the file basename when absent. */
12753
+ label: string().optional(),
12754
+ sizeBytes: number().optional(),
12755
+ extraFiles: array(ManagedModelExtraFileSchema).optional()
12740
12756
  }),
12741
12757
  object({
12742
12758
  kind: literal("path"),
@@ -12797,11 +12813,39 @@ var ManagedRuntimeConfigSchema = object({
12797
12813
  "q4_1",
12798
12814
  "q4_0"
12799
12815
  ]).optional(),
12816
+ /**
12817
+ * Escape hatch for llama-server flags this schema does NOT model — `--jinja`
12818
+ * (which most vision chat templates need and some language-only models
12819
+ * dislike), `--cont-batching`, `--rope-scaling`, …
12820
+ *
12821
+ * It is NOT a second place to set the flags above. A token that collides
12822
+ * with a typed field is REJECTED at start, naming the field that owns it
12823
+ * (`assertNoOwnedFlags`), because two knobs writing the same argv is exactly
12824
+ * the "two switches that disagree" failure this repo has already shipped
12825
+ * twice (D62).
12826
+ */
12827
+ extraArgs: array(string()).default([]),
12800
12828
  /** Else lazy: first generate boots it. */
12801
12829
  autoStart: boolean().default(false),
12802
12830
  /** 0 = never; frees RAM after quiet periods. */
12803
12831
  idleStopMinutes: number().int().default(30)
12804
12832
  });
12833
+ /**
12834
+ * Where a multi-GB install currently is. A single 0..1 fraction cannot answer
12835
+ * "is it stuck?" for an install that is three files (shards + mmproj) followed
12836
+ * by a sha256 pass over 22 GB — during which the fraction sat at 1.0 and the
12837
+ * node looked hung. Phase + file + bytes is the smallest shape that does.
12838
+ */
12839
+ var LlmDownloadProgressSchema = object({
12840
+ phase: _enum(["downloading", "verifying"]),
12841
+ /** The artifact currently moving, e.g. `mmproj-F16.gguf`. */
12842
+ file: string(),
12843
+ fileIndex: number().int(),
12844
+ fileCount: number().int(),
12845
+ /** Across the WHOLE install, not the current file. */
12846
+ downloadedBytes: number(),
12847
+ totalBytes: number().optional()
12848
+ });
12805
12849
  var LlmRuntimeStatusSchema = object({
12806
12850
  /** Status is ALWAYS node-qualified. */
12807
12851
  nodeId: string(),
@@ -12818,6 +12862,8 @@ var LlmRuntimeStatusSchema = object({
12818
12862
  modelPath: string().optional(),
12819
12863
  modelId: string().optional(),
12820
12864
  downloadProgress: number().min(0).max(1).optional(),
12865
+ /** Detail behind `downloadProgress`; present for the same lifetime. */
12866
+ download: LlmDownloadProgressSchema.optional(),
12821
12867
  lastError: string().optional(),
12822
12868
  crashesInWindow: number(),
12823
12869
  /** Child RSS (sampled best-effort). */
@@ -12828,7 +12874,14 @@ var LlmNodeModelSchema = object({
12828
12874
  file: string(),
12829
12875
  sizeBytes: number(),
12830
12876
  catalogId: string().optional(),
12831
- installedAt: number().optional()
12877
+ installedAt: number().optional(),
12878
+ /**
12879
+ * Absolute path on the node. Present so a file that is on disk but matches
12880
+ * no catalog entry — a custom Hugging Face install, or a GGUF the operator
12881
+ * copied in by hand — is still SELECTABLE, as a `{kind:'path'}` ref. Without
12882
+ * it the picker could list such a file and do nothing with it.
12883
+ */
12884
+ path: string().optional()
12832
12885
  });
12833
12886
  var LlmRuntimeDiskUsageSchema = object({
12834
12887
  nodeId: string(),
@@ -12974,6 +13027,36 @@ var ManagedModelCatalogEntrySchema = object({
12974
13027
  /** Vision models: companion projector file. */
12975
13028
  mmprojUrl: string().optional()
12976
13029
  });
13030
+ /**
13031
+ * The outcome of turning one operator-typed Hugging Face reference into a
13032
+ * download plan. A RESULT, never a throw: "this repo has 24 quantizations and
13033
+ * I will not pick for you" is a normal answer the UI has to render, not an
13034
+ * exception.
13035
+ *
13036
+ * `candidates` is the whole reason the refusal is usable — every string in it
13037
+ * is a tag that resolves when pasted back as `<org>/<repo>:<TAG>`.
13038
+ */
13039
+ var HfModelResolutionSchema = discriminatedUnion("ok", [object({
13040
+ ok: literal(true),
13041
+ /** Ready to hand to `installModel` unchanged. */
13042
+ model: ManagedModelRefSchema,
13043
+ label: string(),
13044
+ repo: string(),
13045
+ quantization: string(),
13046
+ purpose: _enum(["text", "vision"]),
13047
+ totalBytes: number(),
13048
+ /** mmproj + shards, for the preview: an operator approving 23 GB should
13049
+ * see that 0.9 GB of it is a projector they did not name. */
13050
+ extraFilenames: array(string())
13051
+ }), object({
13052
+ ok: literal(false),
13053
+ code: string(),
13054
+ message: string(),
13055
+ candidates: array(string()).optional(),
13056
+ /** Set when the refusal was only the ceiling: re-calling with
13057
+ * `maxBytes: requiredBytes` is the operator's explicit override. */
13058
+ requiredBytes: number().optional()
13059
+ })]);
12977
13060
  var LlmRuntimeNodeSchema = object({
12978
13061
  nodeId: string(),
12979
13062
  reachable: boolean(),
@@ -13010,6 +13093,15 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }
13010
13093
  consumer: string().optional(),
13011
13094
  profileId: string().optional()
13012
13095
  }), array(LlmUsageRollupSchema)), method(object({}), array(ManagedModelCatalogEntrySchema)), method(object({}), array(LlmRuntimeNodeSchema)), method(object({ nodeId: string() }), array(LlmNodeModelSchema)), method(object({
13096
+ /** `https://huggingface.co/<org>/<repo>/resolve/main/<f>.gguf`,
13097
+ * `<org>/<repo>/<f>.gguf`, `<org>/<repo>` or `<org>/<repo>:<QUANT>`. */
13098
+ ref: string(),
13099
+ /** Explicit ceiling override, in bytes. Absent = the built-in ceiling. */
13100
+ maxBytes: number().positive().optional()
13101
+ }), HfModelResolutionSchema, {
13102
+ kind: "mutation",
13103
+ auth: "admin"
13104
+ }), method(object({
13013
13105
  nodeId: string(),
13014
13106
  model: ManagedModelRefSchema
13015
13107
  }), _void(), {
@@ -19211,6 +19303,17 @@ var maxSessionHoldMsField = {
19211
19303
  default: 12e4,
19212
19304
  step: 5e3
19213
19305
  };
19306
+ /**
19307
+ * Quiet period that closes an `audioMode: 'on-motion'` audio window. Floor of
19308
+ * 5s so a rearm can never degenerate into per-event stream churn; default 90s
19309
+ * comfortably outlives the gap between two PIR wakes on a battery camera.
19310
+ */
19311
+ var audioMotionWindowMsField = {
19312
+ min: 5e3,
19313
+ max: 6e5,
19314
+ default: 9e4,
19315
+ step: 5e3
19316
+ };
19214
19317
  var motionFpsField = {
19215
19318
  min: 1,
19216
19319
  max: 30,
@@ -19387,6 +19490,27 @@ var RunnerCameraConfigSchema = object({
19387
19490
  * resolved `CameraDetectionConfig`.
19388
19491
  */
19389
19492
  maxSessionHoldMs: number().min(maxSessionHoldMsField.min).max(maxSessionHoldMsField.max).optional(),
19493
+ /**
19494
+ * Orchestrator-side quiet period (ms) that closes an `audioMode:
19495
+ * 'on-motion'` audio window, measured from the LAST motion event.
19496
+ *
19497
+ * This exists because the falling edge cannot be relied on. Camera-native
19498
+ * providers emit motion as a RISING EDGE ONLY (Reolink's Baichuan push and
19499
+ * its email-push SMTP path both emit `detected: true` and never the
19500
+ * counterpart); only the frame-diff analyzer emits falls. So on an
19501
+ * onboard-only camera a window that closed only on `detected: false` never
19502
+ * closed at all, and `on-motion` silently behaved as `always-on` — on a
19503
+ * battery camera, the one failure mode the mode exists to prevent.
19504
+ *
19505
+ * Every motion event rearms this timer WITHOUT restarting the stream, so a
19506
+ * burst of re-fires costs nothing. A falling edge, when one does arrive,
19507
+ * still closes earlier via `motionCooldownMs` — whichever comes first wins.
19508
+ *
19509
+ * Not consumed by the runner: carried here so it shares the per-camera
19510
+ * device-settings surface with `motionCooldownMs`, exactly like
19511
+ * `maxSessionHoldMs`.
19512
+ */
19513
+ audioMotionWindowMs: number().min(audioMotionWindowMsField.min).max(audioMotionWindowMsField.max).optional(),
19390
19514
  motionFps: number().min(motionFpsField.min).max(motionFpsField.max).default(motionFpsField.default),
19391
19515
  detectionFps: number().min(detectionFpsField.min).max(detectionFpsField.max).default(detectionFpsField.default),
19392
19516
  motionStreamId: string(),
@@ -19482,7 +19606,7 @@ var RunnerCameraConfigSchema = object({
19482
19606
  */
19483
19607
  inferenceDevices: array(RunnerInferenceDeviceSchema).readonly().optional()
19484
19608
  });
19485
- motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
19609
+ motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
19486
19610
  /**
19487
19611
  * Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
19488
19612
  * load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
@@ -22196,6 +22320,25 @@ var BatteryStatusSchema = object({
22196
22320
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
22197
22321
  lastUpdated: number(),
22198
22322
  /**
22323
+ * Ms epoch of the last time the device PROVED it was reachable — a
22324
+ * completed firmware round-trip, an observed wake, or an inbound push
22325
+ * (firmware event, email). `0`/absent = never since this slice was born.
22326
+ *
22327
+ * This is the ONLY input that separates "asleep" from "gone", and it is
22328
+ * fed exclusively by PASSIVE signals: nothing may write it by reaching
22329
+ * for the radio, because a poll that confirms reachability is the same
22330
+ * poll that drains the battery. See {@link deriveBatteryPresence} — the
22331
+ * single derivation every consumer must use; no surface computes its own.
22332
+ *
22333
+ * It is deliberately NOT a clock in the
22334
+ * `scripts/check-runtime-state-durability.ts` sense: it is the
22335
+ * observation itself, and it is the only thing a 30-hour silence is
22336
+ * visible in. Writers quantise it (see `CONTACT_WRITE_QUANTUM_MS` in the
22337
+ * Reolink provider) so a value that means "recently" cannot cost a
22338
+ * SQLite commit per round-trip.
22339
+ */
22340
+ lastContactAt: number().optional(),
22341
+ /**
22199
22342
  * True when the source is a BINARY low-battery indicator (HA
22200
22343
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
22201
22344
  * charge level — `percentage` is then a coarse stand-in (100 = normal,
@@ -28223,7 +28366,70 @@ var CamStreamDescriptorSchema = object({
28223
28366
  /** Transport-specific opaque metadata (e.g. rfc4571 SDP). */
28224
28367
  metadata: record(string(), unknown()).optional()
28225
28368
  });
28226
- DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), array(CamStreamDescriptorSchema).readonly());
28369
+ /**
28370
+ * `stream-catalog` — device-scoped, provider-implemented. The pull counterpart
28371
+ * of the removed `publishCameraStream` push: a camera provider returns the full
28372
+ * set of stream descriptors it can offer for the device, synchronously, so the
28373
+ * broker can reconcile its registry against the authoritative provider state.
28374
+ */
28375
+ /**
28376
+ * The catalog as a DURABLE fact rather than a live answer.
28377
+ *
28378
+ * A battery camera's descriptors are profile-stable — they change when the
28379
+ * operator rewrites an encoder profile, not minute to minute — but building
28380
+ * them costs a Baichuan login, which on a sleeping Argus IS a wake. So the
28381
+ * provider is allowed to build them exactly once per profile and must serve
28382
+ * every later pull from a cache.
28383
+ *
28384
+ * Holding that cache only in RAM is what turned a restart into an outage. The
28385
+ * runner comes back with the camera asleep, `buildStreamCatalogUncached`
28386
+ * correctly refuses to wake it, the pull answers `[]`, the broker has no
28387
+ * cam-stream entry to build a broker from, and `webrtcSession.handleOffer`
28388
+ * fails with a flat "No broker for stream" — for as long as the camera sleeps,
28389
+ * which on a battery cam is most of the day. The camera was fine. The stream
28390
+ * was unreachable because the process had forgotten what the camera offers.
28391
+ *
28392
+ * Declaring it here puts it in `device-runtime-state`, the kernel's canonical
28393
+ * declared collection, with the same `restored` durability `battery` uses for
28394
+ * the same reason: the last known value is the only value there is while the
28395
+ * device is asleep. The broker's brokers are therefore always DEFINABLE — it
28396
+ * is the DIAL that wakes a camera, never the catalog (D173).
28397
+ */
28398
+ var StreamCatalogStateSchema = object({
28399
+ /** The descriptors as last built from a real camera response. Never a guess:
28400
+ * a failed or refused build writes NOTHING, so a restored catalog is always
28401
+ * one the camera itself once produced. */
28402
+ descriptors: array(CamStreamDescriptorSchema),
28403
+ /** Ms epoch of the build that produced {@link descriptors}. Lets the wake
28404
+ * path decide whether the camera's own awake window is worth spending on a
28405
+ * re-read. */
28406
+ lastFetchedAt: number()
28407
+ });
28408
+ var streamCatalogCapability = {
28409
+ name: "stream-catalog",
28410
+ scope: "device",
28411
+ deviceNative: true,
28412
+ mode: "singleton",
28413
+ deviceTypes: [DeviceType.Camera],
28414
+ methods: { getCatalog: method(object({ deviceId: number().int().nonnegative() }), array(CamStreamDescriptorSchema).readonly()) },
28415
+ runtimeState: StreamCatalogStateSchema,
28416
+ /**
28417
+ * Runtime-state durability: **restored** — see the schema doc. A cold
28418
+ * catalog on a sleeping battery camera is not a slow first frame, it is a
28419
+ * camera that cannot be watched at all until it happens to wake.
28420
+ *
28421
+ * Churn is nil by construction: the slice is written only by a SUCCESSFUL
28422
+ * build, and a build only runs when there is no cached copy (or the copy is
28423
+ * a day old and the camera is awake anyway).
28424
+ *
28425
+ * See `RuntimeStateDurability`. Enforced by
28426
+ * `scripts/check-runtime-state-durability.ts`.
28427
+ */
28428
+ durability: "restored",
28429
+ /** Clock field: written, but excluded from the compare that decides whether
28430
+ * persisting is worth a SQLite commit — the descriptors are the value. */
28431
+ volatileStateFields: ["lastFetchedAt"]
28432
+ };
28227
28433
  /** One of the camera's stream profiles. */
28228
28434
  var StreamProfileSchema = _enum([
28229
28435
  "main",
@@ -29927,6 +30133,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
29927
30133
  sceneMonitor: sceneMonitorCapability,
29928
30134
  scriptRunner: scriptRunnerCapability,
29929
30135
  smoke: smokeCapability,
30136
+ streamCatalog: streamCatalogCapability,
29930
30137
  streamParams: streamParamsCapability,
29931
30138
  switch: switchCapability,
29932
30139
  tamper: tamperCapability,
@@ -32813,6 +33020,12 @@ Object.freeze({
32813
33020
  addonId: null,
32814
33021
  access: "view"
32815
33022
  },
33023
+ "llm.resolveModelRef": {
33024
+ capName: "llm",
33025
+ capScope: "system",
33026
+ addonId: null,
33027
+ access: "create"
33028
+ },
32816
33029
  "llm.setDefault": {
32817
33030
  capName: "llm",
32818
33031
  capScope: "system",
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-CFOT1Yoz.js");
5
+ const require_dist = require("../dist-CWoaZE47.js");
6
6
  let node_fs = require("node:fs");
7
7
  let node_fs$1 = require_dist.__toESM(node_fs, 1);
8
8
  node_fs = require_dist.__toESM(node_fs);
@@ -1,4 +1,4 @@
1
- import { $ as hfModelUrl, X as embeddingEncoderCapability, mt as BaseAddon } from "../dist-CA2KdMY9.mjs";
1
+ import { $ as hfModelUrl, X as embeddingEncoderCapability, mt as BaseAddon } from "../dist-D6_m_zg1.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import * as fs from "node:fs";
4
4
  import "node:fs";
@@ -1,6 +1,6 @@
1
1
  import { a as e, i as t, n, o as r, r as i, t as a } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.js-C0AuF9av.mjs";
2
2
  import { t as o } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-B3Wx5J80.mjs";
3
- import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-B4LMjxKe.mjs";
3
+ import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BeCNd7Q3.mjs";
4
4
  import { n as m, r as h, t as g } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-Bm-iyjmq.mjs";
5
5
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils.js
6
6
  var _ = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), v = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), y = (e) => {