@camstack/addon-tailscale 1.1.28 → 1.2.1

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.
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  enumerable: true
25
25
  }) : target, mod));
26
26
  //#endregion
27
- const require_dist = require("../dist-CPFhFQVO.js");
27
+ const require_dist = require("../dist-DEDkX8co.js");
28
28
  let node_child_process = require("node:child_process");
29
29
  let node_util = require("node:util");
30
30
  let node_fs = require("node:fs");
@@ -1,4 +1,4 @@
1
- import { i as EventCategory, n as networkAccessCapability, r as BaseAddon, t as meshNetworkCapability } from "../dist-C_oio-xb.mjs";
1
+ import { i as EventCategory, n as networkAccessCapability, r as BaseAddon, t as meshNetworkCapability } from "../dist-D1JegZhD.mjs";
2
2
  import { execFile, spawn } from "node:child_process";
3
3
  import { promisify } from "node:util";
4
4
  import * as fs from "node:fs";
@@ -7067,6 +7067,17 @@ var ModelCatalogEntrySchema = object({
7067
7067
  "imagenet",
7068
7068
  "none"
7069
7069
  ]).optional(),
7070
+ /**
7071
+ * The model already applies softmax IN-GRAPH — its raw output is a
7072
+ * probability distribution, not logits. When set, the `softmax`
7073
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7074
+ * probability vector collapses it toward uniform (top-1 score craters far
7075
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7076
+ * the output is raw logits and the postprocessor applies softmax (the normal
7077
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7078
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7079
+ */
7080
+ outputProbabilities: boolean().optional(),
7070
7081
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7071
7082
  /**
7072
7083
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -11080,10 +11091,7 @@ var ConfigUISchemaNullableBridge = custom();
11080
11091
  var InferenceCapabilitiesBridge = custom();
11081
11092
  var ModelAvailabilityListBridge = custom();
11082
11093
  var PipelineRunResultBridge = custom();
11083
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
11084
- kind: "mutation",
11085
- auth: "admin"
11086
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11094
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11087
11095
  modelId: string(),
11088
11096
  settings: record(string(), unknown()).readonly()
11089
11097
  }))), method(object({ steps: record(string(), object({
@@ -11143,13 +11151,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11143
11151
  * (inputClasses ≠ null) are skipped and served per-track via
11144
11152
  * pipelineRunner.runDetailSubtree (two-plane design).
11145
11153
  */
11146
- plane: _enum(["full", "frame"]).optional()
11154
+ plane: _enum(["full", "frame"]).optional(),
11155
+ /**
11156
+ * Inference-device selector (Phase 2 multi-device). Format
11157
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
11158
+ * Omitted ⇒ the runner's default device (current single-engine
11159
+ * behaviour). Selects WHICH device pool of the node runs the call.
11160
+ */
11161
+ deviceKey: string().optional()
11147
11162
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11148
11163
  engine: PipelineEngineChoiceSchema.optional(),
11149
11164
  steps: array(PipelineStepInputSchema).min(1),
11150
11165
  frames: array(FrameInputSchema).min(1).max(255),
11151
11166
  deviceId: number().optional(),
11152
- sessionId: string().optional()
11167
+ sessionId: string().optional(),
11168
+ /**
11169
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
11170
+ * the batch to the Python pool's bench preprocess cache
11171
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
11172
+ * preprocessed ONCE and every later inference is a pure-inference cache
11173
+ * hit — the sustained-throughput run measures inference, not
11174
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
11175
+ * full preprocess every call, correct). Fresh per sustained run;
11176
+ * released via `uncacheFrame`.
11177
+ */
11178
+ frameId: number().int().nonnegative().optional(),
11179
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
11180
+ deviceKey: string().optional()
11153
11181
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
11154
11182
  data: _instanceof(Uint8Array),
11155
11183
  width: number().int().positive(),
@@ -11181,8 +11209,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11181
11209
  * - `runtime` — main camera-serving engine (no idle TTL).
11182
11210
  * - `warm-override` — benchmark/test override held in the warm
11183
11211
  * cache; auto-disposed after the idle TTL.
11212
+ * - `device-pool` — a concurrent per-device pool (Phase 2
11213
+ * multi-device, keyed by `deviceKey`) resolved
11214
+ * via `resolveDeviceFactory`. Runs alongside the
11215
+ * `runtime` engine on a DIFFERENT accelerator
11216
+ * (NPU / iGPU / Coral) — this is how the
11217
+ * Engines tab shows all pools running at once.
11184
11218
  */
11185
- kind: _enum(["runtime", "warm-override"]),
11219
+ kind: _enum([
11220
+ "runtime",
11221
+ "warm-override",
11222
+ "device-pool"
11223
+ ]),
11186
11224
  /** Native pid of the underlying Python pool (null when no pool). */
11187
11225
  poolPid: number().nullable(),
11188
11226
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -11284,7 +11322,21 @@ var NativeCropResultSchema = object({
11284
11322
  /** Packed rgb (24-bit) pixels of the crop. */
11285
11323
  bytes: _instanceof(Uint8Array),
11286
11324
  width: number().int().positive(),
11287
- height: number().int().positive()
11325
+ height: number().int().positive(),
11326
+ /**
11327
+ * Which source served this crop, so a quality-sensitive consumer (the native
11328
+ * `keyFrame`) can reject a degraded fallback:
11329
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
11330
+ * quality path).
11331
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
11332
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
11333
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
11334
+ *
11335
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
11336
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
11337
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
11338
+ */
11339
+ tier: _enum(["native", "ram-fullframe"]).optional()
11288
11340
  });
11289
11341
  /** Parent detection context passed to `runDetailSubtree` — the crop's
11290
11342
  * originating detection, in FRAME-space coordinates. Reuses
@@ -11524,7 +11576,14 @@ var RunnerCameraConfigSchema = object({
11524
11576
  * camera's detect node differs from its source-owner (P2d, gated by the
11525
11577
  * `remoteSourcingNodes` rollout setting).
11526
11578
  */
11527
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11579
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11580
+ /**
11581
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11582
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11583
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11584
+ * this only selects WHICH device pool of that node runs the session.
11585
+ */
11586
+ deviceKey: string().optional()
11528
11587
  });
11529
11588
  motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
11530
11589
  /**
@@ -11545,6 +11604,19 @@ var RunnerLocalLoadSchema = object({
11545
11604
  avgInferenceTimeMs: number(),
11546
11605
  /** Total queue depth across motion + detection queues. */
11547
11606
  queueDepthTotal: number(),
11607
+ /**
11608
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11609
+ * this runner currently has attached cameras on, so the orchestrator's second
11610
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11611
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11612
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11613
+ */
11614
+ devices: array(object({
11615
+ deviceKey: string(),
11616
+ backend: string(),
11617
+ attachedCameras: number(),
11618
+ queueDepthTotal: number()
11619
+ })).default([]),
11548
11620
  /** Hardware capability flags reported by this node. */
11549
11621
  hardware: object({
11550
11622
  hasGpu: boolean(),
@@ -13020,6 +13092,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
13020
13092
  kind: "mutation",
13021
13093
  auth: "admin"
13022
13094
  });
13095
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
13096
+ new Set(Object.values(DeviceType));
13023
13097
  /**
13024
13098
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13025
13099
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -14593,7 +14667,8 @@ var LinkedDeviceSchema = object({
14593
14667
  deviceId: number(),
14594
14668
  name: string(),
14595
14669
  location: string().nullable(),
14596
- features: array(string())
14670
+ features: array(string()),
14671
+ producesTrackedEvents: boolean().optional()
14597
14672
  });
14598
14673
  var SavedDeviceRowSchema = object({
14599
14674
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16240,6 +16315,7 @@ var TrackSchema = object({
16240
16315
  deviceId: number(),
16241
16316
  className: string(),
16242
16317
  label: string().optional(),
16318
+ producingDeviceName: string().optional(),
16243
16319
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16244
16320
  source: TrackSourceSchema.optional(),
16245
16321
  firstSeen: number(),
@@ -16377,7 +16453,8 @@ var MediaFileKindEnum = _enum([
16377
16453
  "fullFrameBoxed",
16378
16454
  "faceCrop",
16379
16455
  "plateCrop",
16380
- "keyFrame"
16456
+ "keyFrame",
16457
+ "keyFrameSmall"
16381
16458
  ]);
16382
16459
  var MediaFileSchema = object({
16383
16460
  key: string(),
@@ -16706,13 +16783,11 @@ var PipelineTemplateSchema = object({
16706
16783
  createdAt: string(),
16707
16784
  updatedAt: string()
16708
16785
  });
16709
- var AgentAddonConfigSchema = object({
16710
- enabled: boolean(),
16786
+ var DeviceStepConfigSchema = object({
16711
16787
  modelId: string().optional(),
16712
- settings: record(string(), unknown()).readonly()
16788
+ settings: record(string(), unknown()).optional()
16713
16789
  });
16714
16790
  var AgentPipelineSettingsSchema = object({
16715
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
16716
16791
  maxCameras: number().int().nonnegative().nullable().default(null),
16717
16792
  /** Per-node detection weight (relative share for the quota balancer). */
16718
16793
  detectWeight: number().positive().optional(),
@@ -16736,7 +16811,22 @@ var AgentPipelineSettingsSchema = object({
16736
16811
  * it already uses to reach the hub). Set this only when the auto-detected
16737
16812
  * address is wrong (multi-homed host, NAT, custom interface).
16738
16813
  */
16739
- reachableHost: string().optional()
16814
+ reachableHost: string().optional(),
16815
+ /**
16816
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
16817
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
16818
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
16819
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
16820
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
16821
+ * the default model/settings for every camera landing on that accelerator;
16822
+ * a stepId absent ⇒ the step uses that device's format default.
16823
+ */
16824
+ inferenceDevices: record(string(), object({
16825
+ enabled: boolean(),
16826
+ weight: number().positive().optional(),
16827
+ maxSessions: number().int().positive().optional(),
16828
+ steps: record(string(), DeviceStepConfigSchema).optional()
16829
+ })).optional()
16740
16830
  });
16741
16831
  var CameraPipelineForAgentSchema = object({
16742
16832
  steps: array(PipelineStepInputSchema).readonly(),
@@ -16746,14 +16836,13 @@ var CameraPipelineForAgentSchema = object({
16746
16836
  }).nullable()
16747
16837
  });
16748
16838
  var CameraStepOverridePatchSchema = object({
16749
- enabled: boolean().optional(),
16750
16839
  modelId: string().optional(),
16751
16840
  settings: record(string(), unknown()).readonly().optional()
16752
16841
  });
16753
16842
  var CameraPipelineSettingsSchema = object({
16754
16843
  pinnedAgentNodeId: string().optional(),
16755
16844
  stepToggles: record(string(), boolean()).optional(),
16756
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
16845
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
16757
16846
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
16758
16847
  });
16759
16848
  /**
@@ -16967,6 +17056,44 @@ var CameraStatusSchema = object({
16967
17056
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
16968
17057
  fetchedAt: number()
16969
17058
  });
17059
+ var NodeInferenceDeviceSchema = object({
17060
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17061
+ key: string(),
17062
+ backend: string(),
17063
+ device: string(),
17064
+ format: _enum(MODEL_FORMATS),
17065
+ /** Whether the node's live probe reports the device as usable right now. */
17066
+ available: boolean(),
17067
+ /**
17068
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17069
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17070
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17071
+ * not a balanced target). An explicit stored value always wins; a stored-only
17072
+ * (unavailable) key keeps its stored value.
17073
+ */
17074
+ enabled: boolean(),
17075
+ /** Relative balancer weight for the enabled device (default 1). */
17076
+ weight: number(),
17077
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17078
+ maxSessions: number().nullable(),
17079
+ /** Object-detection model the executor defaults to for this deviceKey. */
17080
+ defaultModelId: string(),
17081
+ /**
17082
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17083
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17084
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17085
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17086
+ * available per format; this is the stored selection that becomes the
17087
+ * default for EVERY camera landing on this accelerator.
17088
+ */
17089
+ steps: record(string(), DeviceStepConfigSchema).optional()
17090
+ });
17091
+ var NodeInferenceDevicesSchema = object({
17092
+ nodeId: string(),
17093
+ /** False when the node's platform-probe was unreachable (no live device set). */
17094
+ reachable: boolean(),
17095
+ devices: array(NodeInferenceDeviceSchema).readonly()
17096
+ });
16970
17097
  method(object({
16971
17098
  deviceId: number(),
16972
17099
  agentNodeId: string()
@@ -16976,7 +17103,13 @@ method(object({
16976
17103
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
16977
17104
  kind: "mutation",
16978
17105
  auth: "admin"
16979
- }), method(_void(), object({ migrated: number() }), {
17106
+ }), method(object({
17107
+ deviceId: number(),
17108
+ deviceKey: string()
17109
+ }), object({ success: literal(true) }), {
17110
+ kind: "mutation",
17111
+ auth: "admin"
17112
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
16980
17113
  kind: "mutation",
16981
17114
  auth: "admin"
16982
17115
  }), method(_void(), array(PipelineAssignmentSchema).readonly()), method(object({ deviceId: number() }), PipelineAssignmentSchema.nullable()), method(_void(), array(AgentLoadSummarySchema).readonly()), method(_void(), GlobalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(object({ nodeId: string() }), CapabilityBindingsSchema), method(object({
@@ -17010,13 +17143,7 @@ method(object({
17010
17143
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17011
17144
  nodeId: string(),
17012
17145
  settings: AgentPipelineSettingsSchema
17013
- })).readonly()), method(object({
17014
- agentNodeId: string(),
17015
- defaults: record(string(), AgentAddonConfigSchema)
17016
- }), object({ success: literal(true) }), {
17017
- kind: "mutation",
17018
- auth: "admin"
17019
- }), method(object({ agentNodeId: string() }), object({
17146
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17020
17147
  success: boolean(),
17021
17148
  removed: boolean()
17022
17149
  }), {
@@ -17048,7 +17175,18 @@ method(object({
17048
17175
  }), object({ success: literal(true) }), {
17049
17176
  kind: "mutation",
17050
17177
  auth: "admin"
17051
- }), method(object({ agentNodeId: string() }), object({
17178
+ }), method(object({
17179
+ agentNodeId: string(),
17180
+ inferenceDevices: record(string(), object({
17181
+ enabled: boolean(),
17182
+ weight: number().positive().optional(),
17183
+ maxSessions: number().int().positive().optional(),
17184
+ steps: record(string(), DeviceStepConfigSchema).optional()
17185
+ }))
17186
+ }), object({ success: literal(true) }), {
17187
+ kind: "mutation",
17188
+ auth: "admin"
17189
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17052
17190
  success: literal(true),
17053
17191
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17054
17192
  effectiveModelId: string().nullable(),
@@ -17064,9 +17202,10 @@ method(object({
17064
17202
  }), object({ success: literal(true) }), {
17065
17203
  kind: "mutation",
17066
17204
  auth: "admin"
17067
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17205
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17068
17206
  deviceId: number(),
17069
17207
  agentNodeId: string(),
17208
+ deviceKey: string(),
17070
17209
  addonId: string(),
17071
17210
  patch: CameraStepOverridePatchSchema.nullable()
17072
17211
  }), object({ success: literal(true) }), {
@@ -17103,14 +17242,13 @@ method(object({
17103
17242
  });
17104
17243
  /**
17105
17244
  * server-management — per-NODE singleton capability for a node's ROOT
17106
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17107
- * agents).
17245
+ * package lifecycle (runtime-updatable node packages).
17108
17246
  *
17109
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
17110
- * on agents) carries the whole software stack in its npm dep tree, so ONE
17111
- * version describes the node. Updates install into
17112
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
17113
- * starter (probation boot + auto-rollback to N-1).
17247
+ * Every node role runs the SAME root package (`@camstack/server`), which
17248
+ * carries the whole software stack in its npm dep tree, so ONE version
17249
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17250
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17251
+ * no auto-rollback).
17114
17252
  *
17115
17253
  * Providers:
17116
17254
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17218,7 +17356,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17218
17356
  /** Explicit target version; omitted = latest from the registry. */
17219
17357
  version: string().optional() }), ServerUpdateActionResultSchema, {
17220
17358
  kind: "mutation",
17221
- auth: "admin"
17359
+ auth: "admin",
17360
+ timeoutMs: 16 * 6e4
17222
17361
  }), method(_void(), ServerUpdateActionResultSchema, {
17223
17362
  kind: "mutation",
17224
17363
  auth: "admin"
@@ -18262,22 +18401,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18262
18401
  var RestartAddonResultSchema = unknown();
18263
18402
  var InstallPackageResultSchema = unknown();
18264
18403
  var ReloadPackagesResultSchema = unknown();
18265
- /**
18266
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
18267
- * server restarts so the admin UI can react to the `restartingAt`
18268
- * timestamp (shows reconnect overlay). The transition from
18269
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
18270
- * `system.restart-completed` event after the new process boots.
18271
- *
18272
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
18273
- */
18274
- var UpdateFrameworkPackageResultSchema = object({
18275
- packageName: string(),
18276
- fromVersion: string(),
18277
- toVersion: string(),
18278
- /** Ms-epoch the server scheduled its self-restart. */
18279
- restartingAt: number()
18280
- });
18281
18404
  var BulkUpdateItemStatusSchema = _enum([
18282
18405
  "queued",
18283
18406
  "updating",
@@ -18405,13 +18528,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18405
18528
  }), object({ success: literal(true) }), {
18406
18529
  kind: "mutation",
18407
18530
  auth: "admin"
18408
- }), method(object({
18409
- packageName: string().min(1),
18410
- version: string().optional(),
18411
- deferRestart: boolean().optional()
18412
- }), UpdateFrameworkPackageResultSchema, {
18413
- kind: "mutation",
18414
- auth: "admin"
18415
18531
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18416
18532
  kind: "mutation",
18417
18533
  auth: "admin"
@@ -19338,10 +19454,10 @@ var TopologyCategorySchema = object({
19338
19454
  addons: array(TopologyCategoryAddonSchema).readonly()
19339
19455
  });
19340
19456
  /**
19341
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
19342
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
19343
- * version visibility for the Server management surface. Nullable: offline
19344
- * rows and pre-phase-2 nodes report none.
19457
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19458
+ * root package for every node role) as reported by its `registerNode`
19459
+ * manifest — version visibility for the Server management surface. Nullable:
19460
+ * offline rows and nodes that never reported one.
19345
19461
  */
19346
19462
  var TopologyRootPackageSchema = object({
19347
19463
  name: string(),
@@ -19729,17 +19845,28 @@ var PlatformScoreSchema = object({
19729
19845
  format: _enum([
19730
19846
  "onnx",
19731
19847
  "coreml",
19732
- "openvino"
19848
+ "openvino",
19849
+ "tflite"
19733
19850
  ]),
19734
19851
  score: number(),
19735
19852
  reason: string(),
19736
19853
  available: boolean()
19737
19854
  });
19855
+ var InferenceDeviceDescriptorSchema = object({
19856
+ key: string(),
19857
+ backend: string(),
19858
+ device: string(),
19859
+ format: ModelFormatSchema,
19860
+ runtime: literal("python"),
19861
+ score: number(),
19862
+ available: boolean()
19863
+ });
19738
19864
  var PlatformCapabilitiesSchema = object({
19739
19865
  hardware: HardwareInfoSchema,
19740
19866
  scores: array(PlatformScoreSchema).readonly(),
19741
19867
  bestScore: PlatformScoreSchema,
19742
- pythonPath: string().nullable()
19868
+ pythonPath: string().nullable(),
19869
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
19743
19870
  });
19744
19871
  var ModelRequirementSchema = object({
19745
19872
  modelId: string(),
@@ -20618,12 +20745,6 @@ Object.freeze({
20618
20745
  addonId: null,
20619
20746
  access: "delete"
20620
20747
  },
20621
- "addons.updateFrameworkPackage": {
20622
- capName: "addons",
20623
- capScope: "system",
20624
- addonId: null,
20625
- access: "create"
20626
- },
20627
20748
  "addons.updatePackage": {
20628
20749
  capName: "addons",
20629
20750
  capScope: "system",
@@ -23396,12 +23517,6 @@ Object.freeze({
23396
23517
  addonId: null,
23397
23518
  access: "view"
23398
23519
  },
23399
- "pipelineExecutor.reprobeEngine": {
23400
- capName: "pipeline-executor",
23401
- capScope: "system",
23402
- addonId: null,
23403
- access: "create"
23404
- },
23405
23520
  "pipelineExecutor.runAudioTest": {
23406
23521
  capName: "pipeline-executor",
23407
23522
  capScope: "system",
@@ -23552,6 +23667,12 @@ Object.freeze({
23552
23667
  addonId: null,
23553
23668
  access: "view"
23554
23669
  },
23670
+ "pipelineOrchestrator.getNodeInferenceDevices": {
23671
+ capName: "pipeline-orchestrator",
23672
+ capScope: "system",
23673
+ addonId: null,
23674
+ access: "view"
23675
+ },
23555
23676
  "pipelineOrchestrator.getPipelineAssignment": {
23556
23677
  capName: "pipeline-orchestrator",
23557
23678
  capScope: "system",
@@ -23564,6 +23685,12 @@ Object.freeze({
23564
23685
  addonId: null,
23565
23686
  access: "view"
23566
23687
  },
23688
+ "pipelineOrchestrator.getPipelineDevicePin": {
23689
+ capName: "pipeline-orchestrator",
23690
+ capScope: "system",
23691
+ addonId: null,
23692
+ access: "view"
23693
+ },
23567
23694
  "pipelineOrchestrator.listAgentSettings": {
23568
23695
  capName: "pipeline-orchestrator",
23569
23696
  capScope: "system",
@@ -23606,19 +23733,19 @@ Object.freeze({
23606
23733
  addonId: null,
23607
23734
  access: "create"
23608
23735
  },
23609
- "pipelineOrchestrator.setAgentAddonDefaults": {
23736
+ "pipelineOrchestrator.setAgentCapabilities": {
23610
23737
  capName: "pipeline-orchestrator",
23611
23738
  capScope: "system",
23612
23739
  addonId: null,
23613
23740
  access: "create"
23614
23741
  },
23615
- "pipelineOrchestrator.setAgentCapabilities": {
23742
+ "pipelineOrchestrator.setAgentDetectWeight": {
23616
23743
  capName: "pipeline-orchestrator",
23617
23744
  capScope: "system",
23618
23745
  addonId: null,
23619
23746
  access: "create"
23620
23747
  },
23621
- "pipelineOrchestrator.setAgentDetectWeight": {
23748
+ "pipelineOrchestrator.setAgentInferenceDevices": {
23622
23749
  capName: "pipeline-orchestrator",
23623
23750
  capScope: "system",
23624
23751
  addonId: null,
@@ -23660,6 +23787,12 @@ Object.freeze({
23660
23787
  addonId: null,
23661
23788
  access: "create"
23662
23789
  },
23790
+ "pipelineOrchestrator.setPipelineDevicePin": {
23791
+ capName: "pipeline-orchestrator",
23792
+ capScope: "system",
23793
+ addonId: null,
23794
+ access: "create"
23795
+ },
23663
23796
  "pipelineOrchestrator.unassignAudio": {
23664
23797
  capName: "pipeline-orchestrator",
23665
23798
  capScope: "system",
@@ -25212,31 +25345,5 @@ Object.freeze({
25212
25345
  "network-access": "ingress",
25213
25346
  "smtp-provider": "email"
25214
25347
  });
25215
- var frameworkSwapPackageSchema = object({
25216
- name: string(),
25217
- stagedPath: string(),
25218
- backupPath: string(),
25219
- toVersion: string(),
25220
- fromVersion: string().nullable()
25221
- });
25222
- object({
25223
- jobId: string(),
25224
- taskId: string(),
25225
- packages: array(frameworkSwapPackageSchema),
25226
- requestedAtMs: number(),
25227
- schemaVersion: literal(1)
25228
- });
25229
- object({
25230
- jobId: string(),
25231
- taskId: string(),
25232
- backups: array(object({
25233
- name: string(),
25234
- backupPath: string(),
25235
- livePath: string()
25236
- })),
25237
- appliedAtMs: number(),
25238
- bootAttempts: number(),
25239
- schemaVersion: literal(1)
25240
- });
25241
25348
  //#endregion
25242
25349
  export { EventCategory as i, networkAccessCapability as n, BaseAddon as r, meshNetworkCapability as t };
@@ -7067,6 +7067,17 @@ var ModelCatalogEntrySchema = object({
7067
7067
  "imagenet",
7068
7068
  "none"
7069
7069
  ]).optional(),
7070
+ /**
7071
+ * The model already applies softmax IN-GRAPH — its raw output is a
7072
+ * probability distribution, not logits. When set, the `softmax`
7073
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7074
+ * probability vector collapses it toward uniform (top-1 score craters far
7075
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7076
+ * the output is raw logits and the postprocessor applies softmax (the normal
7077
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7078
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7079
+ */
7080
+ outputProbabilities: boolean().optional(),
7070
7081
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7071
7082
  /**
7072
7083
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -11080,10 +11091,7 @@ var ConfigUISchemaNullableBridge = custom();
11080
11091
  var InferenceCapabilitiesBridge = custom();
11081
11092
  var ModelAvailabilityListBridge = custom();
11082
11093
  var PipelineRunResultBridge = custom();
11083
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
11084
- kind: "mutation",
11085
- auth: "admin"
11086
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11094
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11087
11095
  modelId: string(),
11088
11096
  settings: record(string(), unknown()).readonly()
11089
11097
  }))), method(object({ steps: record(string(), object({
@@ -11143,13 +11151,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11143
11151
  * (inputClasses ≠ null) are skipped and served per-track via
11144
11152
  * pipelineRunner.runDetailSubtree (two-plane design).
11145
11153
  */
11146
- plane: _enum(["full", "frame"]).optional()
11154
+ plane: _enum(["full", "frame"]).optional(),
11155
+ /**
11156
+ * Inference-device selector (Phase 2 multi-device). Format
11157
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
11158
+ * Omitted ⇒ the runner's default device (current single-engine
11159
+ * behaviour). Selects WHICH device pool of the node runs the call.
11160
+ */
11161
+ deviceKey: string().optional()
11147
11162
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11148
11163
  engine: PipelineEngineChoiceSchema.optional(),
11149
11164
  steps: array(PipelineStepInputSchema).min(1),
11150
11165
  frames: array(FrameInputSchema).min(1).max(255),
11151
11166
  deviceId: number().optional(),
11152
- sessionId: string().optional()
11167
+ sessionId: string().optional(),
11168
+ /**
11169
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
11170
+ * the batch to the Python pool's bench preprocess cache
11171
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
11172
+ * preprocessed ONCE and every later inference is a pure-inference cache
11173
+ * hit — the sustained-throughput run measures inference, not
11174
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
11175
+ * full preprocess every call, correct). Fresh per sustained run;
11176
+ * released via `uncacheFrame`.
11177
+ */
11178
+ frameId: number().int().nonnegative().optional(),
11179
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
11180
+ deviceKey: string().optional()
11153
11181
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
11154
11182
  data: _instanceof(Uint8Array),
11155
11183
  width: number().int().positive(),
@@ -11181,8 +11209,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11181
11209
  * - `runtime` — main camera-serving engine (no idle TTL).
11182
11210
  * - `warm-override` — benchmark/test override held in the warm
11183
11211
  * cache; auto-disposed after the idle TTL.
11212
+ * - `device-pool` — a concurrent per-device pool (Phase 2
11213
+ * multi-device, keyed by `deviceKey`) resolved
11214
+ * via `resolveDeviceFactory`. Runs alongside the
11215
+ * `runtime` engine on a DIFFERENT accelerator
11216
+ * (NPU / iGPU / Coral) — this is how the
11217
+ * Engines tab shows all pools running at once.
11184
11218
  */
11185
- kind: _enum(["runtime", "warm-override"]),
11219
+ kind: _enum([
11220
+ "runtime",
11221
+ "warm-override",
11222
+ "device-pool"
11223
+ ]),
11186
11224
  /** Native pid of the underlying Python pool (null when no pool). */
11187
11225
  poolPid: number().nullable(),
11188
11226
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -11284,7 +11322,21 @@ var NativeCropResultSchema = object({
11284
11322
  /** Packed rgb (24-bit) pixels of the crop. */
11285
11323
  bytes: _instanceof(Uint8Array),
11286
11324
  width: number().int().positive(),
11287
- height: number().int().positive()
11325
+ height: number().int().positive(),
11326
+ /**
11327
+ * Which source served this crop, so a quality-sensitive consumer (the native
11328
+ * `keyFrame`) can reject a degraded fallback:
11329
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
11330
+ * quality path).
11331
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
11332
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
11333
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
11334
+ *
11335
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
11336
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
11337
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
11338
+ */
11339
+ tier: _enum(["native", "ram-fullframe"]).optional()
11288
11340
  });
11289
11341
  /** Parent detection context passed to `runDetailSubtree` — the crop's
11290
11342
  * originating detection, in FRAME-space coordinates. Reuses
@@ -11524,7 +11576,14 @@ var RunnerCameraConfigSchema = object({
11524
11576
  * camera's detect node differs from its source-owner (P2d, gated by the
11525
11577
  * `remoteSourcingNodes` rollout setting).
11526
11578
  */
11527
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11579
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11580
+ /**
11581
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11582
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11583
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11584
+ * this only selects WHICH device pool of that node runs the session.
11585
+ */
11586
+ deviceKey: string().optional()
11528
11587
  });
11529
11588
  motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
11530
11589
  /**
@@ -11545,6 +11604,19 @@ var RunnerLocalLoadSchema = object({
11545
11604
  avgInferenceTimeMs: number(),
11546
11605
  /** Total queue depth across motion + detection queues. */
11547
11606
  queueDepthTotal: number(),
11607
+ /**
11608
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11609
+ * this runner currently has attached cameras on, so the orchestrator's second
11610
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11611
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11612
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11613
+ */
11614
+ devices: array(object({
11615
+ deviceKey: string(),
11616
+ backend: string(),
11617
+ attachedCameras: number(),
11618
+ queueDepthTotal: number()
11619
+ })).default([]),
11548
11620
  /** Hardware capability flags reported by this node. */
11549
11621
  hardware: object({
11550
11622
  hasGpu: boolean(),
@@ -13020,6 +13092,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
13020
13092
  kind: "mutation",
13021
13093
  auth: "admin"
13022
13094
  });
13095
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
13096
+ new Set(Object.values(DeviceType));
13023
13097
  /**
13024
13098
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13025
13099
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -14593,7 +14667,8 @@ var LinkedDeviceSchema = object({
14593
14667
  deviceId: number(),
14594
14668
  name: string(),
14595
14669
  location: string().nullable(),
14596
- features: array(string())
14670
+ features: array(string()),
14671
+ producesTrackedEvents: boolean().optional()
14597
14672
  });
14598
14673
  var SavedDeviceRowSchema = object({
14599
14674
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16240,6 +16315,7 @@ var TrackSchema = object({
16240
16315
  deviceId: number(),
16241
16316
  className: string(),
16242
16317
  label: string().optional(),
16318
+ producingDeviceName: string().optional(),
16243
16319
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16244
16320
  source: TrackSourceSchema.optional(),
16245
16321
  firstSeen: number(),
@@ -16377,7 +16453,8 @@ var MediaFileKindEnum = _enum([
16377
16453
  "fullFrameBoxed",
16378
16454
  "faceCrop",
16379
16455
  "plateCrop",
16380
- "keyFrame"
16456
+ "keyFrame",
16457
+ "keyFrameSmall"
16381
16458
  ]);
16382
16459
  var MediaFileSchema = object({
16383
16460
  key: string(),
@@ -16706,13 +16783,11 @@ var PipelineTemplateSchema = object({
16706
16783
  createdAt: string(),
16707
16784
  updatedAt: string()
16708
16785
  });
16709
- var AgentAddonConfigSchema = object({
16710
- enabled: boolean(),
16786
+ var DeviceStepConfigSchema = object({
16711
16787
  modelId: string().optional(),
16712
- settings: record(string(), unknown()).readonly()
16788
+ settings: record(string(), unknown()).optional()
16713
16789
  });
16714
16790
  var AgentPipelineSettingsSchema = object({
16715
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
16716
16791
  maxCameras: number().int().nonnegative().nullable().default(null),
16717
16792
  /** Per-node detection weight (relative share for the quota balancer). */
16718
16793
  detectWeight: number().positive().optional(),
@@ -16736,7 +16811,22 @@ var AgentPipelineSettingsSchema = object({
16736
16811
  * it already uses to reach the hub). Set this only when the auto-detected
16737
16812
  * address is wrong (multi-homed host, NAT, custom interface).
16738
16813
  */
16739
- reachableHost: string().optional()
16814
+ reachableHost: string().optional(),
16815
+ /**
16816
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
16817
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
16818
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
16819
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
16820
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
16821
+ * the default model/settings for every camera landing on that accelerator;
16822
+ * a stepId absent ⇒ the step uses that device's format default.
16823
+ */
16824
+ inferenceDevices: record(string(), object({
16825
+ enabled: boolean(),
16826
+ weight: number().positive().optional(),
16827
+ maxSessions: number().int().positive().optional(),
16828
+ steps: record(string(), DeviceStepConfigSchema).optional()
16829
+ })).optional()
16740
16830
  });
16741
16831
  var CameraPipelineForAgentSchema = object({
16742
16832
  steps: array(PipelineStepInputSchema).readonly(),
@@ -16746,14 +16836,13 @@ var CameraPipelineForAgentSchema = object({
16746
16836
  }).nullable()
16747
16837
  });
16748
16838
  var CameraStepOverridePatchSchema = object({
16749
- enabled: boolean().optional(),
16750
16839
  modelId: string().optional(),
16751
16840
  settings: record(string(), unknown()).readonly().optional()
16752
16841
  });
16753
16842
  var CameraPipelineSettingsSchema = object({
16754
16843
  pinnedAgentNodeId: string().optional(),
16755
16844
  stepToggles: record(string(), boolean()).optional(),
16756
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
16845
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
16757
16846
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
16758
16847
  });
16759
16848
  /**
@@ -16967,6 +17056,44 @@ var CameraStatusSchema = object({
16967
17056
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
16968
17057
  fetchedAt: number()
16969
17058
  });
17059
+ var NodeInferenceDeviceSchema = object({
17060
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17061
+ key: string(),
17062
+ backend: string(),
17063
+ device: string(),
17064
+ format: _enum(MODEL_FORMATS),
17065
+ /** Whether the node's live probe reports the device as usable right now. */
17066
+ available: boolean(),
17067
+ /**
17068
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17069
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17070
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17071
+ * not a balanced target). An explicit stored value always wins; a stored-only
17072
+ * (unavailable) key keeps its stored value.
17073
+ */
17074
+ enabled: boolean(),
17075
+ /** Relative balancer weight for the enabled device (default 1). */
17076
+ weight: number(),
17077
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17078
+ maxSessions: number().nullable(),
17079
+ /** Object-detection model the executor defaults to for this deviceKey. */
17080
+ defaultModelId: string(),
17081
+ /**
17082
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17083
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17084
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17085
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17086
+ * available per format; this is the stored selection that becomes the
17087
+ * default for EVERY camera landing on this accelerator.
17088
+ */
17089
+ steps: record(string(), DeviceStepConfigSchema).optional()
17090
+ });
17091
+ var NodeInferenceDevicesSchema = object({
17092
+ nodeId: string(),
17093
+ /** False when the node's platform-probe was unreachable (no live device set). */
17094
+ reachable: boolean(),
17095
+ devices: array(NodeInferenceDeviceSchema).readonly()
17096
+ });
16970
17097
  method(object({
16971
17098
  deviceId: number(),
16972
17099
  agentNodeId: string()
@@ -16976,7 +17103,13 @@ method(object({
16976
17103
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
16977
17104
  kind: "mutation",
16978
17105
  auth: "admin"
16979
- }), method(_void(), object({ migrated: number() }), {
17106
+ }), method(object({
17107
+ deviceId: number(),
17108
+ deviceKey: string()
17109
+ }), object({ success: literal(true) }), {
17110
+ kind: "mutation",
17111
+ auth: "admin"
17112
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
16980
17113
  kind: "mutation",
16981
17114
  auth: "admin"
16982
17115
  }), method(_void(), array(PipelineAssignmentSchema).readonly()), method(object({ deviceId: number() }), PipelineAssignmentSchema.nullable()), method(_void(), array(AgentLoadSummarySchema).readonly()), method(_void(), GlobalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(object({ nodeId: string() }), CapabilityBindingsSchema), method(object({
@@ -17010,13 +17143,7 @@ method(object({
17010
17143
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17011
17144
  nodeId: string(),
17012
17145
  settings: AgentPipelineSettingsSchema
17013
- })).readonly()), method(object({
17014
- agentNodeId: string(),
17015
- defaults: record(string(), AgentAddonConfigSchema)
17016
- }), object({ success: literal(true) }), {
17017
- kind: "mutation",
17018
- auth: "admin"
17019
- }), method(object({ agentNodeId: string() }), object({
17146
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17020
17147
  success: boolean(),
17021
17148
  removed: boolean()
17022
17149
  }), {
@@ -17048,7 +17175,18 @@ method(object({
17048
17175
  }), object({ success: literal(true) }), {
17049
17176
  kind: "mutation",
17050
17177
  auth: "admin"
17051
- }), method(object({ agentNodeId: string() }), object({
17178
+ }), method(object({
17179
+ agentNodeId: string(),
17180
+ inferenceDevices: record(string(), object({
17181
+ enabled: boolean(),
17182
+ weight: number().positive().optional(),
17183
+ maxSessions: number().int().positive().optional(),
17184
+ steps: record(string(), DeviceStepConfigSchema).optional()
17185
+ }))
17186
+ }), object({ success: literal(true) }), {
17187
+ kind: "mutation",
17188
+ auth: "admin"
17189
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17052
17190
  success: literal(true),
17053
17191
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17054
17192
  effectiveModelId: string().nullable(),
@@ -17064,9 +17202,10 @@ method(object({
17064
17202
  }), object({ success: literal(true) }), {
17065
17203
  kind: "mutation",
17066
17204
  auth: "admin"
17067
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17205
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17068
17206
  deviceId: number(),
17069
17207
  agentNodeId: string(),
17208
+ deviceKey: string(),
17070
17209
  addonId: string(),
17071
17210
  patch: CameraStepOverridePatchSchema.nullable()
17072
17211
  }), object({ success: literal(true) }), {
@@ -17103,14 +17242,13 @@ method(object({
17103
17242
  });
17104
17243
  /**
17105
17244
  * server-management — per-NODE singleton capability for a node's ROOT
17106
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17107
- * agents).
17245
+ * package lifecycle (runtime-updatable node packages).
17108
17246
  *
17109
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
17110
- * on agents) carries the whole software stack in its npm dep tree, so ONE
17111
- * version describes the node. Updates install into
17112
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
17113
- * starter (probation boot + auto-rollback to N-1).
17247
+ * Every node role runs the SAME root package (`@camstack/server`), which
17248
+ * carries the whole software stack in its npm dep tree, so ONE version
17249
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17250
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17251
+ * no auto-rollback).
17114
17252
  *
17115
17253
  * Providers:
17116
17254
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17218,7 +17356,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17218
17356
  /** Explicit target version; omitted = latest from the registry. */
17219
17357
  version: string().optional() }), ServerUpdateActionResultSchema, {
17220
17358
  kind: "mutation",
17221
- auth: "admin"
17359
+ auth: "admin",
17360
+ timeoutMs: 16 * 6e4
17222
17361
  }), method(_void(), ServerUpdateActionResultSchema, {
17223
17362
  kind: "mutation",
17224
17363
  auth: "admin"
@@ -18262,22 +18401,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18262
18401
  var RestartAddonResultSchema = unknown();
18263
18402
  var InstallPackageResultSchema = unknown();
18264
18403
  var ReloadPackagesResultSchema = unknown();
18265
- /**
18266
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
18267
- * server restarts so the admin UI can react to the `restartingAt`
18268
- * timestamp (shows reconnect overlay). The transition from
18269
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
18270
- * `system.restart-completed` event after the new process boots.
18271
- *
18272
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
18273
- */
18274
- var UpdateFrameworkPackageResultSchema = object({
18275
- packageName: string(),
18276
- fromVersion: string(),
18277
- toVersion: string(),
18278
- /** Ms-epoch the server scheduled its self-restart. */
18279
- restartingAt: number()
18280
- });
18281
18404
  var BulkUpdateItemStatusSchema = _enum([
18282
18405
  "queued",
18283
18406
  "updating",
@@ -18405,13 +18528,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18405
18528
  }), object({ success: literal(true) }), {
18406
18529
  kind: "mutation",
18407
18530
  auth: "admin"
18408
- }), method(object({
18409
- packageName: string().min(1),
18410
- version: string().optional(),
18411
- deferRestart: boolean().optional()
18412
- }), UpdateFrameworkPackageResultSchema, {
18413
- kind: "mutation",
18414
- auth: "admin"
18415
18531
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18416
18532
  kind: "mutation",
18417
18533
  auth: "admin"
@@ -19338,10 +19454,10 @@ var TopologyCategorySchema = object({
19338
19454
  addons: array(TopologyCategoryAddonSchema).readonly()
19339
19455
  });
19340
19456
  /**
19341
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
19342
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
19343
- * version visibility for the Server management surface. Nullable: offline
19344
- * rows and pre-phase-2 nodes report none.
19457
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19458
+ * root package for every node role) as reported by its `registerNode`
19459
+ * manifest — version visibility for the Server management surface. Nullable:
19460
+ * offline rows and nodes that never reported one.
19345
19461
  */
19346
19462
  var TopologyRootPackageSchema = object({
19347
19463
  name: string(),
@@ -19729,17 +19845,28 @@ var PlatformScoreSchema = object({
19729
19845
  format: _enum([
19730
19846
  "onnx",
19731
19847
  "coreml",
19732
- "openvino"
19848
+ "openvino",
19849
+ "tflite"
19733
19850
  ]),
19734
19851
  score: number(),
19735
19852
  reason: string(),
19736
19853
  available: boolean()
19737
19854
  });
19855
+ var InferenceDeviceDescriptorSchema = object({
19856
+ key: string(),
19857
+ backend: string(),
19858
+ device: string(),
19859
+ format: ModelFormatSchema,
19860
+ runtime: literal("python"),
19861
+ score: number(),
19862
+ available: boolean()
19863
+ });
19738
19864
  var PlatformCapabilitiesSchema = object({
19739
19865
  hardware: HardwareInfoSchema,
19740
19866
  scores: array(PlatformScoreSchema).readonly(),
19741
19867
  bestScore: PlatformScoreSchema,
19742
- pythonPath: string().nullable()
19868
+ pythonPath: string().nullable(),
19869
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
19743
19870
  });
19744
19871
  var ModelRequirementSchema = object({
19745
19872
  modelId: string(),
@@ -20618,12 +20745,6 @@ Object.freeze({
20618
20745
  addonId: null,
20619
20746
  access: "delete"
20620
20747
  },
20621
- "addons.updateFrameworkPackage": {
20622
- capName: "addons",
20623
- capScope: "system",
20624
- addonId: null,
20625
- access: "create"
20626
- },
20627
20748
  "addons.updatePackage": {
20628
20749
  capName: "addons",
20629
20750
  capScope: "system",
@@ -23396,12 +23517,6 @@ Object.freeze({
23396
23517
  addonId: null,
23397
23518
  access: "view"
23398
23519
  },
23399
- "pipelineExecutor.reprobeEngine": {
23400
- capName: "pipeline-executor",
23401
- capScope: "system",
23402
- addonId: null,
23403
- access: "create"
23404
- },
23405
23520
  "pipelineExecutor.runAudioTest": {
23406
23521
  capName: "pipeline-executor",
23407
23522
  capScope: "system",
@@ -23552,6 +23667,12 @@ Object.freeze({
23552
23667
  addonId: null,
23553
23668
  access: "view"
23554
23669
  },
23670
+ "pipelineOrchestrator.getNodeInferenceDevices": {
23671
+ capName: "pipeline-orchestrator",
23672
+ capScope: "system",
23673
+ addonId: null,
23674
+ access: "view"
23675
+ },
23555
23676
  "pipelineOrchestrator.getPipelineAssignment": {
23556
23677
  capName: "pipeline-orchestrator",
23557
23678
  capScope: "system",
@@ -23564,6 +23685,12 @@ Object.freeze({
23564
23685
  addonId: null,
23565
23686
  access: "view"
23566
23687
  },
23688
+ "pipelineOrchestrator.getPipelineDevicePin": {
23689
+ capName: "pipeline-orchestrator",
23690
+ capScope: "system",
23691
+ addonId: null,
23692
+ access: "view"
23693
+ },
23567
23694
  "pipelineOrchestrator.listAgentSettings": {
23568
23695
  capName: "pipeline-orchestrator",
23569
23696
  capScope: "system",
@@ -23606,19 +23733,19 @@ Object.freeze({
23606
23733
  addonId: null,
23607
23734
  access: "create"
23608
23735
  },
23609
- "pipelineOrchestrator.setAgentAddonDefaults": {
23736
+ "pipelineOrchestrator.setAgentCapabilities": {
23610
23737
  capName: "pipeline-orchestrator",
23611
23738
  capScope: "system",
23612
23739
  addonId: null,
23613
23740
  access: "create"
23614
23741
  },
23615
- "pipelineOrchestrator.setAgentCapabilities": {
23742
+ "pipelineOrchestrator.setAgentDetectWeight": {
23616
23743
  capName: "pipeline-orchestrator",
23617
23744
  capScope: "system",
23618
23745
  addonId: null,
23619
23746
  access: "create"
23620
23747
  },
23621
- "pipelineOrchestrator.setAgentDetectWeight": {
23748
+ "pipelineOrchestrator.setAgentInferenceDevices": {
23622
23749
  capName: "pipeline-orchestrator",
23623
23750
  capScope: "system",
23624
23751
  addonId: null,
@@ -23660,6 +23787,12 @@ Object.freeze({
23660
23787
  addonId: null,
23661
23788
  access: "create"
23662
23789
  },
23790
+ "pipelineOrchestrator.setPipelineDevicePin": {
23791
+ capName: "pipeline-orchestrator",
23792
+ capScope: "system",
23793
+ addonId: null,
23794
+ access: "create"
23795
+ },
23663
23796
  "pipelineOrchestrator.unassignAudio": {
23664
23797
  capName: "pipeline-orchestrator",
23665
23798
  capScope: "system",
@@ -25212,32 +25345,6 @@ Object.freeze({
25212
25345
  "network-access": "ingress",
25213
25346
  "smtp-provider": "email"
25214
25347
  });
25215
- var frameworkSwapPackageSchema = object({
25216
- name: string(),
25217
- stagedPath: string(),
25218
- backupPath: string(),
25219
- toVersion: string(),
25220
- fromVersion: string().nullable()
25221
- });
25222
- object({
25223
- jobId: string(),
25224
- taskId: string(),
25225
- packages: array(frameworkSwapPackageSchema),
25226
- requestedAtMs: number(),
25227
- schemaVersion: literal(1)
25228
- });
25229
- object({
25230
- jobId: string(),
25231
- taskId: string(),
25232
- backups: array(object({
25233
- name: string(),
25234
- backupPath: string(),
25235
- livePath: string()
25236
- })),
25237
- appliedAtMs: number(),
25238
- bootAttempts: number(),
25239
- schemaVersion: literal(1)
25240
- });
25241
25348
  //#endregion
25242
25349
  Object.defineProperty(exports, "BaseAddon", {
25243
25350
  enumerable: true,
@@ -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-CPFhFQVO.js");
5
+ const require_dist = require("../dist-DEDkX8co.js");
6
6
  let node_child_process = require("node:child_process");
7
7
  let node_util = require("node:util");
8
8
  let node_crypto = require("node:crypto");
@@ -1,4 +1,4 @@
1
- import { i as EventCategory, n as networkAccessCapability, r as BaseAddon } from "../dist-C_oio-xb.mjs";
1
+ import { i as EventCategory, n as networkAccessCapability, r as BaseAddon } from "../dist-D1JegZhD.mjs";
2
2
  import { execFile } from "node:child_process";
3
3
  import { promisify } from "node:util";
4
4
  import { randomUUID } from "node:crypto";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-tailscale",
3
- "version": "1.1.28",
3
+ "version": "1.2.1",
4
4
  "description": "Tailscale bundle for CamStack — joins the host to a tailnet (client) and exposes the hub via Serve/Funnel (ingress). Multi-entry npm package shipping 2 addons under a single bundle.",
5
5
  "keywords": [
6
6
  "camstack",